Full Code of ClementTsang/bottom for AI

main ca74694ffc7d cached
285 files
1.6 MB
386.2k tokens
1377 symbols
1 requests
Download .txt
Showing preview only (1,714K chars total). Download the full file or copy to clipboard to get everything.
Repository: ClementTsang/bottom
Branch: main
Commit: ca74694ffc7d
Files: 285
Total size: 1.6 MB

Directory structure:
gitextract_vx6kr0uy/

├── .all-contributorsrc
├── .cargo/
│   └── config.toml
├── .cirrus.yml
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   ├── feature_request.yml
│   │   └── packaging.yml
│   ├── actions/
│   │   └── test-bsd-target/
│   │       └── action.yml
│   ├── ci/
│   │   └── rust_version.txt
│   ├── pull_request_template.md
│   └── workflows/
│       ├── bsd_vm_check.yml
│       ├── build_releases.yml
│       ├── ci.yml
│       ├── clear_workflow_cache.yml
│       ├── coverage.yml
│       ├── deployment.yml
│       ├── docs.yml
│       ├── nightly.yml
│       ├── post_release.yml
│       ├── publish_github_pages.yml
│       ├── test_docs.yml
│       └── validate_schema.yml
├── .gitignore
├── .markdownlint.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── Cross.toml
├── LICENSE
├── README.md
├── build.rs
├── clippy.toml
├── codecov.yml
├── desktop/
│   └── bottom.desktop
├── docs/
│   ├── .gitignore
│   ├── README.md
│   ├── content/
│   │   ├── configuration/
│   │   │   ├── command-line-options.md
│   │   │   └── config-file/
│   │   │       ├── cpu.md
│   │   │       ├── disk-table.md
│   │   │       ├── flags.md
│   │   │       ├── index.md
│   │   │       ├── layout.md
│   │   │       ├── network.md
│   │   │       ├── processes.md
│   │   │       ├── styling.md
│   │   │       └── temperature-table.md
│   │   ├── contribution/
│   │   │   ├── development/
│   │   │   │   ├── build_process.md
│   │   │   │   ├── deploy_process.md
│   │   │   │   ├── dev_env.md
│   │   │   │   ├── logging.md
│   │   │   │   └── testing.md
│   │   │   ├── documentation.md
│   │   │   ├── issues-and-pull-requests.md
│   │   │   └── packaging-and-distribution.md
│   │   ├── index.md
│   │   ├── nightly-release.md
│   │   ├── stylesheets/
│   │   │   └── extra.css
│   │   ├── support/
│   │   │   ├── official.md
│   │   │   └── unofficial.md
│   │   ├── troubleshooting.md
│   │   └── usage/
│   │       ├── autocomplete.md
│   │       ├── basic-mode.md
│   │       ├── general-usage.md
│   │       └── widgets/
│   │           ├── battery.md
│   │           ├── cpu.md
│   │           ├── disk.md
│   │           ├── memory.md
│   │           ├── network.md
│   │           ├── process.md
│   │           └── temperature.md
│   ├── hooks/
│   │   ├── nightly_banner.py
│   │   └── nightly_redirect.py
│   ├── mike.sh
│   ├── mkdocs.yml
│   ├── overrides/
│   │   └── main.html
│   ├── requirements.txt
│   └── serve.sh
├── rustfmt.toml
├── sample_configs/
│   ├── default_config.toml
│   └── demo_config.toml
├── schema/
│   ├── README.md
│   ├── nightly/
│   │   └── bottom.json
│   ├── v0.10/
│   │   └── bottom.json
│   ├── v0.11/
│   │   └── bottom.json
│   ├── v0.12.0/
│   │   └── bottom.json
│   └── v0.9/
│       └── bottom.json
├── scripts/
│   ├── ci/
│   │   ├── bsd_tests.sh
│   │   ├── ci_bsd.sh
│   │   ├── cirrus_release.py
│   │   └── configure_git.sh
│   ├── clear_cache.py
│   ├── hooks/
│   │   ├── README.md
│   │   └── pre-push
│   ├── schema/
│   │   ├── bad_file.toml
│   │   ├── generate.sh
│   │   ├── nightly.sh
│   │   ├── requirements.txt
│   │   └── validator.py
│   └── windows/
│       └── choco/
│           ├── bottom.nuspec.template
│           ├── choco_packager.py
│           └── chocolateyinstall.ps1.template
├── src/
│   ├── app/
│   │   ├── data/
│   │   │   ├── mod.rs
│   │   │   ├── process.rs
│   │   │   ├── store.rs
│   │   │   ├── temperature.rs
│   │   │   └── time_series.rs
│   │   ├── filter.rs
│   │   ├── layout_manager.rs
│   │   └── states.rs
│   ├── app.rs
│   ├── bin/
│   │   ├── main.rs
│   │   └── schema.rs
│   ├── canvas/
│   │   ├── components/
│   │   │   ├── data_table/
│   │   │   │   ├── column.rs
│   │   │   │   ├── data_type.rs
│   │   │   │   ├── draw.rs
│   │   │   │   ├── props.rs
│   │   │   │   ├── sortable.rs
│   │   │   │   ├── state.rs
│   │   │   │   └── styling.rs
│   │   │   ├── data_table.rs
│   │   │   ├── mod.rs
│   │   │   ├── pipe_gauge.rs
│   │   │   ├── time_graph/
│   │   │   │   ├── base.rs
│   │   │   │   ├── variants/
│   │   │   │   │   ├── auto_y_axis.rs
│   │   │   │   │   └── percent.rs
│   │   │   │   ├── variants.rs
│   │   │   │   ├── vendored/
│   │   │   │   │   ├── canvas.rs
│   │   │   │   │   ├── grid.rs
│   │   │   │   │   └── points.rs
│   │   │   │   └── vendored.rs
│   │   │   ├── time_graph.rs
│   │   │   └── widget_carousel.rs
│   │   ├── dialogs/
│   │   │   ├── help_dialog.rs
│   │   │   ├── mod.rs
│   │   │   └── process_kill_dialog.rs
│   │   ├── drawing_utils.rs
│   │   └── widgets/
│   │       ├── battery_display.rs
│   │       ├── cpu_basic.rs
│   │       ├── cpu_graph.rs
│   │       ├── disk_table.rs
│   │       ├── mem_basic.rs
│   │       ├── mem_graph.rs
│   │       ├── mod.rs
│   │       ├── network_basic.rs
│   │       ├── network_graph.rs
│   │       ├── process_table.rs
│   │       └── temperature_table.rs
│   ├── canvas.rs
│   ├── collection/
│   │   ├── amd/
│   │   │   └── amd_gpu_marketing.rs
│   │   ├── amd.rs
│   │   ├── batteries.rs
│   │   ├── cpu/
│   │   │   └── sysinfo.rs
│   │   ├── cpu.rs
│   │   ├── disks/
│   │   │   ├── freebsd.rs
│   │   │   ├── io_counters.rs
│   │   │   ├── other.rs
│   │   │   ├── unix/
│   │   │   │   ├── file_systems.rs
│   │   │   │   ├── linux/
│   │   │   │   │   ├── counters.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   └── partition.rs
│   │   │   │   ├── macos/
│   │   │   │   │   ├── counters.rs
│   │   │   │   │   ├── io_kit/
│   │   │   │   │   │   ├── bindings.rs
│   │   │   │   │   │   ├── io_disks.rs
│   │   │   │   │   │   ├── io_iterator.rs
│   │   │   │   │   │   └── io_object.rs
│   │   │   │   │   ├── io_kit.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── other/
│   │   │   │   │   ├── bindings.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   └── partition.rs
│   │   │   │   └── usage.rs
│   │   │   ├── unix.rs
│   │   │   ├── windows/
│   │   │   │   └── bindings.rs
│   │   │   ├── windows.rs
│   │   │   └── zfs_io_counters.rs
│   │   ├── disks.rs
│   │   ├── error.rs
│   │   ├── linux/
│   │   │   └── utils.rs
│   │   ├── memory/
│   │   │   ├── arc.rs
│   │   │   ├── sysinfo.rs
│   │   │   └── windows.rs
│   │   ├── memory.rs
│   │   ├── network/
│   │   │   └── sysinfo.rs
│   │   ├── network.rs
│   │   ├── nvidia.rs
│   │   ├── processes/
│   │   │   ├── freebsd.rs
│   │   │   ├── linux/
│   │   │   │   ├── mod.rs
│   │   │   │   └── process.rs
│   │   │   ├── macos/
│   │   │   │   └── sysctl_bindings.rs
│   │   │   ├── macos.rs
│   │   │   ├── unix/
│   │   │   │   ├── process_ext.rs
│   │   │   │   └── user_table.rs
│   │   │   ├── unix.rs
│   │   │   └── windows.rs
│   │   ├── processes.rs
│   │   ├── temperature/
│   │   │   ├── linux.rs
│   │   │   └── sysinfo.rs
│   │   └── temperature.rs
│   ├── collection.rs
│   ├── constants.rs
│   ├── event.rs
│   ├── lib.rs
│   ├── options/
│   │   ├── args.rs
│   │   ├── config/
│   │   │   ├── cpu.rs
│   │   │   ├── disk.rs
│   │   │   ├── flags.rs
│   │   │   ├── ignore_list.rs
│   │   │   ├── layout.rs
│   │   │   ├── network.rs
│   │   │   ├── process.rs
│   │   │   ├── style/
│   │   │   │   ├── battery.rs
│   │   │   │   ├── borders.rs
│   │   │   │   ├── cpu.rs
│   │   │   │   ├── graphs.rs
│   │   │   │   ├── memory.rs
│   │   │   │   ├── network.rs
│   │   │   │   ├── tables.rs
│   │   │   │   ├── themes/
│   │   │   │   │   ├── default.rs
│   │   │   │   │   ├── gruvbox.rs
│   │   │   │   │   └── nord.rs
│   │   │   │   ├── themes.rs
│   │   │   │   ├── utils.rs
│   │   │   │   └── widgets.rs
│   │   │   ├── style.rs
│   │   │   └── temperature.rs
│   │   ├── config.rs
│   │   └── error.rs
│   ├── options.rs
│   ├── utils/
│   │   ├── cancellation_token.rs
│   │   ├── conversion.rs
│   │   ├── data_units.rs
│   │   ├── general.rs
│   │   ├── logging.rs
│   │   ├── process_killer.rs
│   │   └── strings.rs
│   └── widgets/
│       ├── battery_info.rs
│       ├── cpu_graph.rs
│       ├── disk_table.rs
│       ├── mem_graph.rs
│       ├── mod.rs
│       ├── network_graph.rs
│       ├── process_table/
│       │   ├── process_columns.rs
│       │   ├── process_data.rs
│       │   ├── query/
│       │   │   ├── and.rs
│       │   │   ├── attribute.rs
│       │   │   ├── error.rs
│       │   │   ├── or.rs
│       │   │   └── prefix.rs
│       │   ├── query.rs
│       │   └── sort_table.rs
│       ├── process_table.rs
│       └── temperature_table.rs
├── tests/
│   ├── integration/
│   │   ├── arg_tests.rs
│   │   ├── invalid_config_tests.rs
│   │   ├── layout_movement_tests.rs
│   │   ├── main.rs
│   │   ├── util.rs
│   │   └── valid_config_tests.rs
│   ├── invalid_configs/
│   │   ├── duplicate_temp_type.toml
│   │   ├── empty_layout.toml
│   │   ├── invalid_colour_hex.toml
│   │   ├── invalid_colour_hex_2.toml
│   │   ├── invalid_colour_hex_3.toml
│   │   ├── invalid_colour_name.toml
│   │   ├── invalid_colour_rgb.toml
│   │   ├── invalid_colour_rgb_2.toml
│   │   ├── invalid_colour_string.toml
│   │   ├── invalid_default_widget_count.toml
│   │   ├── invalid_disk_column.toml
│   │   ├── invalid_layout_widget_type.toml
│   │   ├── invalid_process_column.toml
│   │   ├── lone_default_widget_count.toml
│   │   └── toml_mismatch_type.toml
│   └── valid_configs/
│       ├── all_proc.toml
│       ├── cpu_doughnut.toml
│       ├── empty_config.toml
│       ├── filtering.toml
│       ├── many_proc.toml
│       ├── os_specific/
│       │   └── linux.toml
│       ├── proc_columns.toml
│       ├── styling.toml
│       ├── styling_2.toml
│       └── theme.toml
└── wix/
    ├── License.rtf
    └── main.wxs

================================================
FILE CONTENTS
================================================

================================================
FILE: .all-contributorsrc
================================================
{
  "files": [
    "README.md"
  ],
  "imageSize": 100,
  "commit": false,
  "contributors": [
    {
      "login": "shilangyu",
      "name": "Marcin Wojnarowski",
      "avatar_url": "https://avatars3.githubusercontent.com/u/29288116?v=4",
      "profile": "http://shilangyu.github.io",
      "contributions": [
        "code",
        "platform"
      ]
    },
    {
      "login": "mqudsi",
      "name": "Mahmoud Al-Qudsi",
      "avatar_url": "https://avatars3.githubusercontent.com/u/606923?v=4",
      "profile": "http://neosmart.net/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "andys8",
      "name": "Andy",
      "avatar_url": "https://avatars0.githubusercontent.com/u/13085980?v=4",
      "profile": "https://andys8.de",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "HarHarLinks",
      "name": "Kim Brose",
      "avatar_url": "https://avatars0.githubusercontent.com/u/2803622?v=4",
      "profile": "https://github.com/HarHarLinks",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "svenstaro",
      "name": "Sven-Hendrik Haase",
      "avatar_url": "https://avatars0.githubusercontent.com/u/1664?v=4",
      "profile": "https://svenstaro.org",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "tim77",
      "name": "Artem Polishchuk",
      "avatar_url": "https://avatars0.githubusercontent.com/u/5614476?v=4",
      "profile": "https://liberapay.com/Artem4/",
      "contributions": [
        "platform",
        "doc"
      ]
    },
    {
      "login": "runlevel5",
      "name": "Trung Lê",
      "avatar_url": "https://avatars2.githubusercontent.com/u/135605?v=4",
      "profile": "http://ruby-journal.com/",
      "contributions": [
        "platform",
        "infra"
      ]
    },
    {
      "login": "dm9pZCAq",
      "name": "dm9pZCAq",
      "avatar_url": "https://avatars1.githubusercontent.com/u/46228973?v=4",
      "profile": "https://github.com/dm9pZCAq",
      "contributions": [
        "platform",
        "doc"
      ]
    },
    {
      "login": "LlinksRechts",
      "name": "Lukas Rysavy",
      "avatar_url": "https://avatars2.githubusercontent.com/u/10536802?v=4",
      "profile": "https://lukor.org",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "ehamberg",
      "name": "Erlend Hamberg",
      "avatar_url": "https://avatars3.githubusercontent.com/u/16063?v=4",
      "profile": "http://hamberg.no/erlend",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "Frederick888",
      "name": "Frederick Zhang",
      "avatar_url": "https://avatars.githubusercontent.com/u/4507647?v=4",
      "profile": "https://onee3.org",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "pvanheus",
      "name": "pvanheus",
      "avatar_url": "https://avatars.githubusercontent.com/u/4154788?v=4",
      "profile": "https://github.com/pvanheus",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "briandipalma",
      "name": "Brian Di Palma",
      "avatar_url": "https://avatars.githubusercontent.com/u/1597820?v=4",
      "profile": "https://github.com/briandipalma",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "dakyskye",
      "name": "Lasha Kanteladze",
      "avatar_url": "https://avatars.githubusercontent.com/u/32128756?v=4",
      "profile": "https://dakyskye.github.io",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "herbygillot",
      "name": "Herby Gillot",
      "avatar_url": "https://avatars.githubusercontent.com/u/618376?v=4",
      "profile": "https://github.com/herbygillot",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "yellowsquid",
      "name": "Greg Brown",
      "avatar_url": "https://avatars.githubusercontent.com/u/46519298?v=4",
      "profile": "https://github.com/yellowsquid",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "TotalCaesar659",
      "name": "TotalCaesar659",
      "avatar_url": "https://avatars.githubusercontent.com/u/14265316?v=4",
      "profile": "https://github.com/TotalCaesar659",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "grawlinson",
      "name": "George Rawlinson",
      "avatar_url": "https://avatars.githubusercontent.com/u/4408051?v=4",
      "profile": "https://github.com/grawlinson",
      "contributions": [
        "doc",
        "platform"
      ]
    },
    {
      "login": "adiabatic",
      "name": "adiabatic",
      "avatar_url": "https://avatars.githubusercontent.com/u/101246?v=4",
      "profile": "https://www.frogorbits.com/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "bowlofeggs",
      "name": "Randy Barlow",
      "avatar_url": "https://avatars.githubusercontent.com/u/354506?v=4",
      "profile": "https://electronsweatshop.com",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "patricksjackson",
      "name": "Patrick Jackson",
      "avatar_url": "https://avatars.githubusercontent.com/u/160646?v=4",
      "profile": "http://jackson.dev",
      "contributions": [
        "ideas",
        "doc"
      ]
    },
    {
      "login": "mati865",
      "name": "Mateusz Mikuła",
      "avatar_url": "https://avatars.githubusercontent.com/u/1174646?v=4",
      "profile": "https://github.com/mati865",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "GuillaumeGomez",
      "name": "Guillaume Gomez",
      "avatar_url": "https://avatars.githubusercontent.com/u/3050060?v=4",
      "profile": "https://blog.guillaume-gomez.fr",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "shurizzle",
      "name": "shura",
      "avatar_url": "https://avatars.githubusercontent.com/u/203655?v=4",
      "profile": "https://github.com/shurizzle",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "wezm",
      "name": "Wesley Moore",
      "avatar_url": "https://avatars.githubusercontent.com/u/21787?v=4",
      "profile": "https://www.wezm.net/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "xgdgsc",
      "name": "xgdgsc",
      "avatar_url": "https://avatars.githubusercontent.com/u/1189869?v=4",
      "profile": "https://github.com/xgdgsc",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "ViridiCanis",
      "name": "ViridiCanis",
      "avatar_url": "https://avatars.githubusercontent.com/u/49595344?v=4",
      "profile": "https://github.com/ViridiCanis",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "jamartin9",
      "name": "Justin Martin",
      "avatar_url": "https://avatars.githubusercontent.com/u/7027701?v=4",
      "profile": "https://github.com/jamartin9",
      "contributions": [
        "code",
        "doc"
      ]
    },
    {
      "login": "DianaNites",
      "name": "Diana",
      "avatar_url": "https://avatars.githubusercontent.com/u/5275194?v=4",
      "profile": "https://github.com/DianaNites",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "hervyqa",
      "name": "Hervy Qurrotul Ainur Rozi",
      "avatar_url": "https://avatars.githubusercontent.com/u/45872139?v=4",
      "profile": "https://hervyqa.id",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "mrivnak",
      "name": "Mike Rivnak",
      "avatar_url": "https://avatars.githubusercontent.com/u/7389355?v=4",
      "profile": "https://mrivnak.github.io",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "lroobrou",
      "name": "lroobrou",
      "avatar_url": "https://avatars.githubusercontent.com/u/35152113?v=4",
      "profile": "https://github.com/lroobrou",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "database64128",
      "name": "database64128",
      "avatar_url": "https://avatars.githubusercontent.com/u/18757988?v=4",
      "profile": "https://cube64128.xyz/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "sou-chon",
      "name": "Chon Sou",
      "avatar_url": "https://avatars.githubusercontent.com/u/35537528?v=4",
      "profile": "https://github.com/sou-chon",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "Drsheppard01",
      "name": "DrSheppard",
      "avatar_url": "https://avatars.githubusercontent.com/u/60893791?v=4",
      "profile": "https://github.com/Drsheppard01",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "RaresCon",
      "name": "Rareș Constantin",
      "avatar_url": "https://avatars.githubusercontent.com/u/95525840?v=4",
      "profile": "https://github.com/RaresCon",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "felipesuri",
      "name": "felipesuri",
      "avatar_url": "https://avatars.githubusercontent.com/u/50281523?v=4",
      "profile": "http://felipesuri.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "spital",
      "name": "spital",
      "avatar_url": "https://avatars.githubusercontent.com/u/11034264?v=4",
      "profile": "https://github.com/spital",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "mbikovitsky",
      "name": "Michael Bikovitsky",
      "avatar_url": "https://avatars.githubusercontent.com/u/1389811?v=4",
      "profile": "https://bikodbg.com/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "dvalter",
      "name": "Dmitry Valter",
      "avatar_url": "https://avatars.githubusercontent.com/u/38795282?v=4",
      "profile": "https://github.com/dvalter",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "aragonnetje6",
      "name": "Grace Stok",
      "avatar_url": "https://avatars.githubusercontent.com/u/69118097?v=4",
      "profile": "https://github.com/aragonnetje6",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "yshui",
      "name": "Yuxuan Shui",
      "avatar_url": "https://avatars.githubusercontent.com/u/366851?v=4",
      "profile": "https://github.com/yshui",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "WenqingZong",
      "name": "Wenqing Zong",
      "avatar_url": "https://avatars.githubusercontent.com/u/43934749?v=4",
      "profile": "http://zongwenqing.com",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "gabelluardo",
      "name": "Gabriele Belluardo",
      "avatar_url": "https://avatars.githubusercontent.com/u/42920247?v=4",
      "profile": "http://gabelluardo.github.io",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "zebp",
      "name": "Zeb Piasecki",
      "avatar_url": "https://avatars.githubusercontent.com/u/14242997?v=4",
      "profile": "https://zebulon.dev/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "Freed-Wu",
      "name": "wzy",
      "avatar_url": "https://avatars.githubusercontent.com/u/32936898?v=4",
      "profile": "https://freed-wu.github.io/",
      "contributions": [
        "code",
        "doc"
      ]
    },
    {
      "login": "john-s-lin",
      "name": "john-s-lin",
      "avatar_url": "https://avatars.githubusercontent.com/u/66440371?v=4",
      "profile": "https://johnlin.ca/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "lyuha",
      "name": "Lee Wonjoon",
      "avatar_url": "https://avatars.githubusercontent.com/u/4014016?v=4",
      "profile": "https://github.com/lyuha",
      "contributions": [
        "code",
        "doc"
      ]
    },
    {
      "login": "davlgd",
      "name": "David Legrand",
      "avatar_url": "https://avatars.githubusercontent.com/u/1110600?v=4",
      "profile": "https://www.davlgd.fr",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "MichalBryxi",
      "name": "Michal Bryxí",
      "avatar_url": "https://avatars.githubusercontent.com/u/847473?v=4",
      "profile": "https://github.com/MichalBryxi",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "TheSkyentist",
      "name": "Raphael Erik Hviding",
      "avatar_url": "https://avatars.githubusercontent.com/u/17031860?v=4",
      "profile": "http://mpia.de/~hviding/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "CosmicHorrorDev",
      "name": "CosmicHorror",
      "avatar_url": "https://avatars.githubusercontent.com/u/30302768?v=4",
      "profile": "http://cosmichorror.dev",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "woodsb02",
      "name": "Ben Woods",
      "avatar_url": "https://avatars.githubusercontent.com/u/7113557?v=4",
      "profile": "https://www.woods.am/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "stephen-huan",
      "name": "Stephen Huan",
      "avatar_url": "https://avatars.githubusercontent.com/u/20411956?v=4",
      "profile": "http://cgdct.moe",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "jasongwartz",
      "name": "Jason Gwartz",
      "avatar_url": "https://avatars.githubusercontent.com/u/10981911?v=4",
      "profile": "https://github.com/jasongwartz",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "llc0930",
      "name": "llc0930",
      "avatar_url": "https://avatars.githubusercontent.com/u/14966910?v=4",
      "profile": "https://github.com/llc0930",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "yretenai",
      "name": "Ada Ahmed",
      "avatar_url": "https://avatars.githubusercontent.com/u/614231?v=4",
      "profile": "https://chronovore.dev",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "Wateir",
      "name": "Wateir",
      "avatar_url": "https://avatars.githubusercontent.com/u/78731687?v=4",
      "profile": "https://github.com/Wateir",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "al42and",
      "name": "Andrey Alekseenko",
      "avatar_url": "https://avatars.githubusercontent.com/u/933873?v=4",
      "profile": "https://github.com/al42and",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "fgimian",
      "name": "Fotis Gimian",
      "avatar_url": "https://avatars.githubusercontent.com/u/1811813?v=4",
      "profile": "http://fgimian.github.io/",
      "contributions": [
        "code",
        "doc"
      ]
    },
    {
      "login": "SigmaSquadron",
      "name": "Fernando Rodrigues",
      "avatar_url": "https://avatars.githubusercontent.com/u/174749595?v=4",
      "profile": "https://sigmasquadron.net",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "mtoohey31",
      "name": "Matthew Toohey",
      "avatar_url": "https://avatars.githubusercontent.com/u/36740602?v=4",
      "profile": "https://mtoohey.com",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "win8linux",
      "name": "Julius Enriquez",
      "avatar_url": "https://avatars.githubusercontent.com/u/11584387?v=4",
      "profile": "https://meander.site",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "benjamb",
      "name": "Ben Brown",
      "avatar_url": "https://avatars.githubusercontent.com/u/8291297?v=4",
      "profile": "https://github.com/benjamb",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "nyurik",
      "name": "Yuri Astrakhan",
      "avatar_url": "https://avatars.githubusercontent.com/u/1641515?v=4",
      "profile": "https://github.com/nyurik",
      "contributions": [
        "code",
        "doc"
      ]
    },
    {
      "login": "kachick",
      "name": "Kenichi Kamiya",
      "avatar_url": "https://avatars.githubusercontent.com/u/1180335?v=4",
      "profile": "https://kachick.github.io/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "yahlia",
      "name": "yahlia",
      "avatar_url": "https://avatars.githubusercontent.com/u/40295453?v=4",
      "profile": "https://github.com/yahlia",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "Bucket-Bucket-Bucket",
      "name": "Bucket-Bucket-Bucket",
      "avatar_url": "https://avatars.githubusercontent.com/u/107044719?v=4",
      "profile": "https://github.com/Bucket-Bucket-Bucket",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "marverix",
      "name": "Marek Sierociński",
      "avatar_url": "https://avatars.githubusercontent.com/u/2142811?v=4",
      "profile": "http://marek.sierocinscy.pl",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Tommimon",
      "name": "Tommaso Montanari",
      "avatar_url": "https://avatars.githubusercontent.com/u/37435103?v=4",
      "profile": "https://github.com/Tommimon",
      "contributions": [
        "design",
        "ideas"
      ]
    },
    {
      "login": "jylenhof",
      "name": "Jean-Yves LENHOF",
      "avatar_url": "https://avatars.githubusercontent.com/u/36410287?v=4",
      "profile": "http://blog.lenhof.eu.org",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Saphereye",
      "name": "Adarsh Das",
      "avatar_url": "https://avatars.githubusercontent.com/u/59739923?v=4",
      "profile": "http://saphereye.github.io",
      "contributions": [
        "code",
        "doc"
      ]
    },
    {
      "login": "oxyzenQ",
      "name": "rezky_nightky",
      "avatar_url": "https://avatars.githubusercontent.com/u/130107241?v=4",
      "profile": "https://github.com/oxyzenQ",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "gitgoggles",
      "name": "gitgoggles",
      "avatar_url": "https://avatars.githubusercontent.com/u/101480183?v=4",
      "profile": "https://github.com/gitgoggles",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "thunze",
      "name": "Tom",
      "avatar_url": "https://avatars.githubusercontent.com/u/22795263?v=4",
      "profile": "https://github.com/thunze",
      "contributions": [
        "maintenance"
      ]
    },
    {
      "login": "ggaddy",
      "name": "G",
      "avatar_url": "https://avatars.githubusercontent.com/u/13815367?v=4",
      "profile": "https://github.com/ggaddy",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "lpnh",
      "name": "Filipe Paniguel",
      "avatar_url": "https://avatars.githubusercontent.com/u/90577992?v=4",
      "profile": "https://github.com/lpnh",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "WqyJh",
      "name": "Qiying Wang",
      "avatar_url": "https://avatars.githubusercontent.com/u/15232241?v=4",
      "profile": "https://www.jianshu.com/u/f5754cd2e83d",
      "contributions": [
        "code"
      ]
    }
  ],
  "contributorsPerLine": 7,
  "projectName": "bottom",
  "projectOwner": "ClementTsang",
  "repoType": "github",
  "repoHost": "https://github.com",
  "skipCi": false,
  "commitConvention": "angular",
  "commitType": "docs"
}


================================================
FILE: .cargo/config.toml
================================================
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

[target.i686-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]


================================================
FILE: .cirrus.yml
================================================
%YAML 1.1
---
# Configuration for CirrusCI. This is primarily used for testing and building FreeBSD and old versions of Linux,
# since other CI platforms don't support build jobs for these configurations.
#
# Note that we set the YAML directive above to prevent some linting errors around the templates.

setup_template: &SETUP_TEMPLATE
  setup_script:
    - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs --output rustup.sh
    - sh rustup.sh --default-toolchain stable -y

cache_template: &CACHE_TEMPLATE
  registry_cache:
    folder: $HOME/.cargo/registry
    reupload_on_changes: "true"
    fingerprint_script:
      - $HOME/.cargo/bin/rustc --version
      - cat Cargo.lock
      - echo $CIRRUS_OS
      - echo $CIRRUS_TASK_NAME
  target_cache:
    folder: target
    reupload_on_changes: "true"
    fingerprint_script:
      - $HOME/.cargo/bin/rustc --version
      - cat Cargo.lock
      - echo $CIRRUS_OS
      - echo $CIRRUS_TASK_NAME

cleanup_template: &CLEANUP_TEMPLATE
  before_cache_script:
    - rm -rf $HOME/.cargo/registry/index
    - rm -rf $HOME/.cargo/registry/src
    - rm -f ./target/.rustc_info.json

env:
  CARGO_INCREMENTAL: "0"
  CARGO_PROFILE_DEV_DEBUG: "0"
  CARGO_HUSKY_DONT_INSTALL_HOOKS: "true"

release_task:
  auto_cancellation: "false"
  only_if: $CIRRUS_BUILD_SOURCE == "api" && $BTM_BUILD_RELEASE_CALLER == "ci"
  timeout_in: "30m"
  env:
    BTM_GENERATE: "true"
    COMPLETION_DIR: "target/tmp/bottom/completion/"
    MANPAGE_DIR: "target/tmp/bottom/manpage/"
    # -PLACEHOLDER FOR CI-
  matrix:
    - name: "Legacy Linux (2.17)"
      alias: "linux_2_17_build"
      container:
        image: quay.io/pypa/manylinux2014_x86_64
      env:
        TARGET: "x86_64-unknown-linux-gnu"
        NAME: "x86_64-unknown-linux-gnu-2-17"
  <<: *SETUP_TEMPLATE
  <<: *CACHE_TEMPLATE
  build_script:
    - . $HOME/.cargo/env
    - cargo build --release --locked --features deploy
    - mv ./target/release/btm ./
    - ./btm -V
    - mv "$COMPLETION_DIR" completion
    - mv "$MANPAGE_DIR" manpage
    - tar -czvf bottom_$NAME.tar.gz btm completion
  binaries_artifacts:
    path: bottom_$NAME.tar.gz
  <<: *CLEANUP_TEMPLATE


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug report
description: Found something wrong or broken? If it hasn't already been filed/solved, report it!
labels: ["bug"]
body:
  - type: checkboxes
    id: acknowledgements
    attributes:
      label: Checklist
      options:
        - label: >
            I've looked through the [troubleshooting docs](https://bottom.pages.dev/nightly/troubleshooting),
            [the known problems list](https://bottom.pages.dev/nightly/support/official/#known-problems), and 
            [existing open issues](https://github.com/ClementTsang/bottom/issues?q=is%3Aopen+is%3Aissue) for similar
            issues.
          required: true

  - type: input
    id: operating_system
    attributes:
      label: What operating system and version are you using?
      description: >
        Please provide the operating system(s) and version(s) that are experiencing the problem.
        Note that issues on operating systems that [are not officially supported](https://github.com/ClementTsang/bottom#support)
        may not be prioritized/resolved.
      placeholder: Arch Linux 6.6.2

  - type: dropdown
    id: architecture
    attributes:
      label: What architecture are you using?
      description: >
        Please select the architecture(s) that are experiencing the problem.
        Note that systems that [are not officially supported](https://github.com/ClementTsang/bottom#support)
        may not be prioritized/resolved.
      multiple: true
      options:
        - x86_64/AMD64
        - arm64
        - x86
        - arm32
        - Other (please specify in the Additional Information area at the end)

  - type: textarea
    id: terminal
    attributes:
      label: What terminal(s) are you running bottom on that are experiencing the problem?
      description: >
        Please provide what terminal(s) you are running `bottom` on (e.g. Konsole, kitty, urxvt)
        that are experiencing the issue, as well as their version and any relevant settings (e.g. terminal theme).
      placeholder: kitty 0.25.2

  - type: dropdown
    id: filesystem
    validations:
      required: false
    attributes:
      label: (Optional) What filesystem(s) are you using?
      description: >
        If you know, please select what filesystem(s) you are using on the system that is experiencing the problem. This
        can be especially helpful if the issue is related to either the disk or memory widgets.
      multiple: true
      options:
        - ext4
        - NTFS
        - exFAT
        - FAT
        - ZFS
        - Btrfs
        - APFS
        - Other (please specify in the Additional Information area at the end)"

  - type: input
    id: version
    validations:
      required: true
    attributes:
      label: What version of bottom are you running?
      description: >
        Please specify which version of `bottom` you're running that is causing problems. You can find this with
        `btm -V`. If you are using a nightly/non-release version, please also specify that.

        It would also be helpful if you are not running [the latest version](https://github.com/ClementTsang/bottom/releases/latest)
        to try that as well to see if the issue has already been resolved.
      placeholder: 0.12.3

  - type: textarea
    id: install
    validations:
      required: true
    attributes:
      label: How did you install bottom?
      description: >
        Please describe how you installed `bottom`. If you manually compiled it, please also mention your _Rust version_.

        **Note: if you installed `bottom` from cargo, please ensure that you installed the right crate (https://crates.io/crates/bottom).**
      placeholder: Installed bottom through the Arch official repos.

  # TODO: After some point also add in a `btm check` invocation

  - type: textarea
    id: description
    validations:
      required: true
    attributes:
      label: Describe the issue
      description: >
        Give a description of the issue. If possible, provide screenshots/videos.
      placeholder: |
        Example:
        bottom is failing to output information for a mounted encrypted partition on basic mode. It should be able to report this information, but I'm not seeing the entry at all.

  - type: textarea
    id: expected
    validations:
      required: true
    attributes:
      label: What is the expected behaviour?
      description: >
        Describe the behaviour you expected.
      placeholder: |
        Example:
        I expect to be able to see information about the encrypted partition on basic mode.

  - type: textarea
    id: actual
    validations:
      required: true
    attributes:
      label: What is the actual behaviour?
      description: >
        Describe the behaviour you actually see. If possible, provide screenshots/videos.
      placeholder: |
        Example:
        I am unable to see information about my encrypted partition.

  - type: textarea
    id: reproduce
    validations:
      required: true
    attributes:
      label: How can we reproduce this?
      description: >
        Provide detailed steps on _how_ to reproduce your problem, to the best of your ability. Be as detailed as
        possible. Include any config files or flags used. If possible, provide screenshots/videos of the issue.

        Remember - if maintainers cannot reproduce the issue, it will be very hard to fix!
      placeholder: |
        Example:
          1. Mount a LUKS encrypted partition.
          2. Run `btm --basic`
          3. Observe there is no partition shown.

  - type: textarea
    id: additional
    attributes:
      label: Additional information
      description: Provide any additional information you think may be relevant or helpful.
      placeholder: It works fine if I just run it normally without the `--basic` flag.


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
  - name: Open a discussion
    about: |
      Got a question about using bottom? Need help troubleshooting something? Or maybe just want to talk about something related to bottom? Feel free to open a discussion!
    url: https://github.com/ClementTsang/bottom/discussions/new


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Feature request
description: Got a good idea that hasn't already been suggested?  Mention it here!
labels: ["feature"]
body:
  - type: checkboxes
    id: acknowledgements
    attributes:
      label: Checklist
      options:
        - label: >
            I've looked through [the documentation](https://bottom.pages.dev/nightly/) and 
            [existing open issues](https://github.com/ClementTsang/bottom/issues?q=is%3Aopen+is%3Aissue+label%3Afeature)
            for similar feature requests.
          required: true

  - type: textarea
    id: description
    validations:
      required: true
    attributes:
      label: Describe the feature request
      description: >
        Please describe what behaviour you are looking for, the motivation for it, and use cases where this feature
        would be helpful to both you and others. Try to be clear and concise.

        If you have any ideas to implement this feature as well, feel free to write them down here too.
      placeholder: |
        Example:
        It would be nice to support FreeBSD, as I and others often use similar tools on my FreeBSD-based system.
        I also noticed that sysinfo has FreeBSD support as a data source.


================================================
FILE: .github/ISSUE_TEMPLATE/packaging.yml
================================================
name: Packaging
description: For issues, questions, or requests regarding packaging or distribution.
labels: ["packaging"]
body:
  - type: markdown
    attributes:
      value: >
        If this is an issue about supporting a new package/installation method for a platform you use, please
        consider maintaining it yourself/with others and submitting a PR or issue with a link to it - they'll be
        very much appreciated and likely added to the README quickly. [The documentation on packaging/distribution](https://bottom.pages.dev/nightly/contribution/packaging-and-distribution/)
        may be helpful in setting things up. If there are some issues with bottom itself causing problems with
        packaging, feel free to open an appropriate issue.


        If this is an issue regarding a specific existing distribution channel, feel free to report issues here if they
        are related to the following sources:

          * [crates.io](https://crates.io/crates/bottom)
          * [Binary releases/packages released on GitHub](https://github.com/ClementTsang/bottom/releases)


        For any other distribution channel, please first try to contact the package maintainers where appropriate
        to get help regarding distribution-specific issues (e.g. the package has issues installing, the package
        is outdated, etc.) before reaching out here. While I am happy to help where possible, I do not
        personally use many of the various ways people distribute bottom. As such, I might lack the
        platform-specific context, knowledge, or tools to be able to help you at all regarding the
        distribution method, and the best I can do is just point you to the package maintainer.

  - type: checkboxes
    id: acknowledgements
    attributes:
      label: Checklist
      options:
        - label: >
            I have read and understood the above text.
          required: true

  - type: textarea
    id: description
    validations:
      required: true
    attributes:
      label: Describe the issue
      description: >
        What is the packaging-related issue? Please be clear and concise.
      placeholder: |
        Example: Would it be possible to add shell completion generation as a separate build artifact?


================================================
FILE: .github/actions/test-bsd-target/action.yml
================================================
name: Test BSD Target
description: Run tests for a BSD target using VMs, with retries on failure. Needed as cross doesn't support them (https://github.com/cross-rs/cross/wiki/FAQ#running-bsd-tests).

inputs:
  target:
    description: "Rust target triple (e.g., x86_64-unknown-freebsd)"
    required: true
  os-version:
    description: "OS release version (e.g., 13.2 for FreeBSD)"
    required: false

runs:
  using: composite
  steps:
    - name: FreeBSD Test (Attempt 1)
      uses: vmactions/freebsd-vm@c9f815bc7aa0d34c9fdd0619b034a32d6ca7b57e # v1.4.2
      if: ${{ inputs.target == 'x86_64-unknown-freebsd' }}
      with:
        release: "${{ inputs.os-version }}"
        envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
        usesh: true
        run: sh ./scripts/ci/bsd_tests.sh ${{ inputs.target }}
      id: freebsd_attempt_1
      continue-on-error: true

    - name: FreeBSD Test (Attempt 2)
      uses: vmactions/freebsd-vm@c9f815bc7aa0d34c9fdd0619b034a32d6ca7b57e # v1.4.2
      if: ${{ inputs.target == 'x86_64-unknown-freebsd' && steps.freebsd_attempt_1.outcome == 'failure' }}
      with:
        release: "${{ inputs.os-version }}"
        envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
        usesh: true
        run: sh ./scripts/ci/bsd_tests.sh ${{ inputs.target }}
      id: freebsd_attempt_2
      continue-on-error: true

    - name: FreeBSD Test (Attempt 3)
      uses: vmactions/freebsd-vm@c9f815bc7aa0d34c9fdd0619b034a32d6ca7b57e # v1.4.2
      if: ${{ inputs.target == 'x86_64-unknown-freebsd' && steps.freebsd_attempt_2.outcome == 'failure' }}
      with:
        release: "${{ inputs.os-version }}"
        envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
        usesh: true
        run: sh ./scripts/ci/bsd_tests.sh ${{ inputs.target }}
      id: freebsd_attempt_3

    - name: NetBSD Test (Attempt 1)
      uses: vmactions/netbsd-vm@e04aec09540429f9cebb0e7941f7cd0c0fc3b44f # v1.3.6
      if: ${{ inputs.target == 'x86_64-unknown-netbsd' }}
      with:
        release: "${{ inputs.os-version }}"
        envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
        usesh: true
        run: sh ./scripts/ci/bsd_tests.sh ${{ inputs.target }}
      id: netbsd_attempt_1
      continue-on-error: true

    - name: NetBSD Test (Attempt 2)
      uses: vmactions/netbsd-vm@e04aec09540429f9cebb0e7941f7cd0c0fc3b44f # v1.3.6
      if: ${{ inputs.target == 'x86_64-unknown-netbsd' && steps.netbsd_attempt_1.outcome == 'failure' }}
      with:
        release: "${{ inputs.os-version }}"
        envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
        usesh: true
        run: sh ./scripts/ci/bsd_tests.sh ${{ inputs.target }}
      id: netbsd_attempt_2
      continue-on-error: true

    - name: NetBSD Test (Attempt 3)
      uses: vmactions/netbsd-vm@e04aec09540429f9cebb0e7941f7cd0c0fc3b44f # v1.3.6
      if: ${{ inputs.target == 'x86_64-unknown-netbsd' && steps.netbsd_attempt_2.outcome == 'failure' }}
      with:
        release: "${{ inputs.os-version }}"
        envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
        usesh: true
        run: sh ./scripts/ci/bsd_tests.sh ${{ inputs.target }}
      id: netbsd_attempt_3


================================================
FILE: .github/ci/rust_version.txt
================================================
1.94.0


================================================
FILE: .github/pull_request_template.md
================================================
<!-- Please use this template (unless you have a very good reason not to). PRs that do not use the template may be closed. -->

## Description

_A description of the change, what it does, and why it was made. If relevant (e.g. UI changes), **please also provide screenshots/recordings**:_

## Issue

_If applicable, what issue does this address?_

Closes: #<issue-number>

## Testing

_If relevant, please state how this was tested (including steps):_

_If this change affects the program, please also indicate which platforms were tested:_

- [ ] _Windows_
- [ ] _macOS (specify version below)_
- [ ] _Linux (specify distro below)_
- [ ] _Other (specify below)_

## Checklist

_Ensure **all** of these are met:_

- [ ] _If this is a code change, areas your change affects have been linted using (`cargo fmt`)_
- [ ] _If this is a code change, your changes pass `cargo clippy --all -- -D warnings`_
- [ ] _If this is a code change, new tests were added if relevant_
- [ ] _If this is a code change, your changes pass `cargo test`_
- [ ] _The change has been tested to work (see above) and doesn't appear to break other things_
- [ ] _Documentation has been updated if needed (`README.md`, help menu, docs, configs, etc.)_
- [ ] _There are no merge conflicts_
- [ ] _You have reviewed the changes first_
- [ ] _The pull request passes the provided CI pipeline_

## Other

_Anything else that maintainers should know about this PR:_


================================================
FILE: .github/workflows/bsd_vm_check.yml
================================================
# Run BSD VM jobs with manually-implemented retries.

name: "BSD VM Check"

on:
  workflow_call:
    inputs:
      os-target:
        type: string
        description: "BSD target (x86_64-unknown-freebsd, x86_64-unknown-netbsd, or x86_64-unknown-openbsd)"
        required: true
      os-version:
        type: string
        description: "Release version"
        required: true

# Duplicated because GHA doesn't support passing env vars through without making them all inputs or something.
env:
  RUST_BACKTRACE: 1
  CARGO_INCREMENTAL: 0
  CARGO_PROFILE_DEV_DEBUG: 0
  CARGO_HUSKY_DONT_INSTALL_HOOKS: true

jobs:
  bsd-vm-test:
    runs-on: ubuntu-24.04
    timeout-minutes: 20
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      - name: OpenBSD Test (Attempt 1)
        uses: vmactions/openbsd-vm@9a8e4351a4a0dc6238e7c69276dcbf6c03bea576 # v1.3.6
        if: ${{ inputs.os-target == 'x86_64-unknown-openbsd' }}
        with:
          release: "${{ inputs.os-version }}"
          envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
          usesh: true
          run: sh ./scripts/ci/ci_bsd.sh ${{ inputs.os-target }}
        id: openbsd_attempt_1
        continue-on-error: true

      - name: OpenBSD Test (Attempt 2)
        uses: vmactions/openbsd-vm@9a8e4351a4a0dc6238e7c69276dcbf6c03bea576 # v1.3.6
        if: ${{ inputs.os-target == 'x86_64-unknown-openbsd' && steps.openbsd_attempt_1.outcome == 'failure' }}
        with:
          release: "${{ inputs.os-version }}"
          envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
          usesh: true
          run: sh ./scripts/ci/ci_bsd.sh ${{ inputs.os-target }}
        id: openbsd_attempt_2
        continue-on-error: true

      - name: OpenBSD Test (Attempt 3)
        uses: vmactions/openbsd-vm@9a8e4351a4a0dc6238e7c69276dcbf6c03bea576 # v1.3.6
        if: ${{ inputs.os-target == 'x86_64-unknown-openbsd' && steps.openbsd_attempt_2.outcome == 'failure' }}
        with:
          release: "${{ inputs.os-version }}"
          envs: "RUST_BACKTRACE CARGO_INCREMENTAL CARGO_PROFILE_DEV_DEBUG CARGO_HUSKY_DONT_INSTALL_HOOKS"
          usesh: true
          run: sh ./scripts/ci/ci_bsd.sh ${{ inputs.os-target }}
        id: openbsd_attempt_3

      - name: Check result
        if: ${{ failure() }}
        run: exit 1


================================================
FILE: .github/workflows/build_releases.yml
================================================
# Builds the following releases:
# - Binaries
# - Binaries via VMs
# - Cirrus binaries (currently just Linux 2.17)
# - MSI installer for Windows (.msi)
# - .deb releases
# - .rpm releases
#
# Note that for musl targets, we use cross to avoid having to set up the dependencies for musl.
#
# TODO: Break this up into scripts instead.
# TODO: Trigger this in CI as well if this file changes, so I don't have to spam nightly builds.

name: "build releases"

on:
  workflow_dispatch:
  workflow_call:
    inputs:
      caller:
        description: "The calling workflow."
        default: ""
        required: false
        type: string

env:
  RUST_BACKTRACE: 1
  CARGO_INCREMENTAL: 0
  CARGO_PROFILE_DEV_DEBUG: 0
  CARGO_HUSKY_DONT_INSTALL_HOOKS: true
  COMPLETION_DIR: "target/tmp/bottom/completion/"
  MANPAGE_DIR: "target/tmp/bottom/manpage/"
  CROSS_VERSION: "git:588b3c99db52b5a9c5906fab96cfadcf1bde7863"

permissions:
  id-token: write
  contents: read
  attestations: write

jobs:
  build-binaries:
    name: "Build binaries"
    runs-on: ${{ matrix.info.os }}
    container: ${{ matrix.info.container }}
    timeout-minutes: 12
    strategy:
      fail-fast: false
      matrix:
        info:
          # ======= Supported targets =======
          # Linux (x86-64, x86, aarch64)
          - {
              target: "x86_64-unknown-linux-gnu",
              os: "ubuntu-22.04",
              cross: false,
              generate-other-artifacts: true,
            }
          - {
              target: "i686-unknown-linux-gnu",
              os: "ubuntu-22.04",
              cross: true,
            }
          - {
              target: "x86_64-unknown-linux-musl",
              os: "ubuntu-22.04",
              cross: true,
            }
          - {
              target: "i686-unknown-linux-musl",
              os: "ubuntu-22.04",
              cross: true,
            }
          - {
              target: "aarch64-unknown-linux-gnu",
              os: "ubuntu-22.04-arm",
              cross: false,
            }
          - {
              target: "aarch64-unknown-linux-musl",
              os: "ubuntu-22.04",
              cross: true,
            }

          # macOS (x86-64 and aarch64)
          - {
              target: "x86_64-apple-darwin",
              os: "macos-15-intel",
              cross: false,
            }
          - { target: "aarch64-apple-darwin", os: "macos-15", cross: false }

          # Windows (x86-64, x86)
          - {
              target: "x86_64-pc-windows-msvc",
              os: "windows-2022",
              cross: false,
            }
          - { target: "i686-pc-windows-msvc", os: "windows-2022", cross: false }
          - {
              target: "x86_64-pc-windows-gnu",
              os: "windows-2022",
              cross: false,
            }

          # ======= Unsupported targets =======
          # armv7
          - {
              target: "armv7-unknown-linux-gnueabihf",
              os: "ubuntu-22.04",
              cross: true,
            }
          - {
              target: "armv7-unknown-linux-musleabihf",
              os: "ubuntu-22.04",
              cross: true,
            }

          # PowerPC 64 LE
          - {
              target: "powerpc64le-unknown-linux-gnu",
              os: "ubuntu-22.04",
              cross: true,
            }

          # Risc-V 64gc
          - {
              target: "riscv64gc-unknown-linux-gnu",
              os: "ubuntu-22.04",
              cross: true,
            }

          # Android
          - {
              target: "aarch64-linux-android",
              os: "ubuntu-24.04",
              cross: true,
              no-default-features: true,
            }

          # Loongarch
          - {
              target: "loongarch64-unknown-linux-gnu",
              os: "ubuntu-22.04",
              cross: true,
            }

          # Windows ARM, may promote to official.
          - {
              target: "aarch64-pc-windows-msvc",
              os: "windows-11-arm",
              cross: false,
            }

          # FreeBSD
          - {
              target: "x86_64-unknown-freebsd",
              os: "ubuntu-22.04",
              cross: true,
            }

          # NetBSD
          - { target: "x86_64-unknown-netbsd", os: "ubuntu-22.04", cross: true }
    steps:
      - name: Checkout repository
        if: matrix.info.container == ''
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      # TODO: Make this and the toolchain step a separate wrapper action?
      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        if: matrix.info.container == ''
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ matrix.info.rust || env.RUST_VERSION }}
          target: ${{ matrix.info.target }}

      - name: Set up Rust toolchain (non-GitHub container)
        if: matrix.info.container != ''
        shell: bash
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs --output rustup.sh
          sh rustup.sh --default-toolchain stable -y
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH

      - name: Set features
        shell: bash
        run: |
          if [[ "${{ matrix.info.no-default-features }}" == "true" ]]; then
            BUILD_FEATURES="--no-default-features"
          else
            BUILD_FEATURES="--features deploy"
          fi
          echo "Will build with the following features: $BUILD_FEATURES"
          echo "BUILD_FEATURES=$BUILD_FEATURES" >> $GITHUB_ENV

      - name: Build
        uses: ClementTsang/cargo-action@2438cc5f3ba4e971289fffca2a00dedea6911f14 # v0.0.7
        env:
          BTM_GENERATE: true
          BTM_BUILD_RELEASE_CALLER: ${{ inputs.caller }}
        with:
          command: build
          args: --release --locked --target=${{ matrix.info.target }} ${{ env.BUILD_FEATURES }}
          use-cross: ${{ matrix.info.cross }}
          cross-version: ${{ matrix.info.cross-version || env.CROSS_VERSION }}

      - name: Move automatically generated completion/manpage
        shell: bash
        run: |
          mv "$COMPLETION_DIR" completion
          mv "$MANPAGE_DIR" manpage

      - name: Determine signing slug for Windows signing
        id: get-signing-slug
        if: startsWith(matrix.info.os, 'windows')
        shell: bash
        run: |
          mkdir -p signed
          if [[ ${{ inputs.caller }} == "nightly" ]]; then
            echo "slug=test-signing" >> $GITHUB_OUTPUT
          else
            echo "slug=release-signing" >> $GITHUB_OUTPUT
          fi

      - name: Upload unsigned Windows artifact
        id: upload-unsigned-artifact
        if: startsWith(matrix.info.os, 'windows')
        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        with:
          retention-days: 1
          name: "unsigned-${{ matrix.info.target }}"
          path: target/${{ matrix.info.target }}/release/btm.exe

      - name: Sign Windows artifacts
        if: startsWith(matrix.info.os, 'windows')
        uses: signpath/github-action-submit-signing-request@3f9250c56651ff692d6729a2fbb0603a42d7d322 # v2.0
        with:
          api-token: "${{ secrets.SIGNPATH_API_TOKEN }}"
          organization-id: "06b1a1ff-74e1-4d9d-93b1-fa8180c67727"
          project-slug: "bottom"
          signing-policy-slug: "${{ steps.get-signing-slug.outputs.slug }}"
          github-artifact-id: "${{ steps.upload-unsigned-artifact.outputs.artifact-id }}"
          wait-for-completion: true
          output-artifact-directory: "signed"

      - name: Bundle release and completion (Windows)
        if: startsWith(matrix.info.os, 'windows')
        shell: bash
        run: |
          mv signed/btm.exe btm.exe
          7z a bottom_${{ matrix.info.target }}.zip "btm.exe"
          7z a bottom_${{ matrix.info.target }}.zip "completion"
          echo "ASSET=bottom_${{ matrix.info.target }}.zip" >> $GITHUB_ENV

      - name: Bundle release and completion (Linux and macOS)
        if: ${{ !(startsWith(matrix.info.os, 'windows')) }}
        shell: bash
        run: |
          cp target/${{ matrix.info.target }}/release/btm ./btm
          tar -czvf bottom_${{ matrix.info.target }}.tar.gz btm completion
          echo "ASSET=bottom_${{ matrix.info.target }}.tar.gz" >> $GITHUB_ENV

      - name: Generate artifact attestation for file
        uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2
        with:
          subject-path: ${{ env.ASSET }}

      - name: Create release directory for artifact, move file
        shell: bash
        run: |
          mkdir release
          mv ${{ env.ASSET }} release/

      - name: Compress completion files
        if: matrix.info.generate-other-artifacts == true
        shell: bash
        run: |
          tar -C ./completion -czvf completion.tar.gz .
          mv completion.tar.gz release/

      - name: Compress manpage files
        if: matrix.info.generate-other-artifacts == true
        shell: bash
        run: |
          gzip ./manpage/btm.1
          tar -C ./manpage -czvf manpage.tar.gz .
          mv manpage.tar.gz release/

      - name: Copy over .desktop file
        if: matrix.info.generate-other-artifacts == true
        shell: bash
        run: |
          cp ./desktop/bottom.desktop release/

      - name: Save release as artifact
        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        with:
          retention-days: 3
          name: "release-${{ matrix.info.target }}"
          path: release

  build-msi:
    name: "Build MSI (WiX) installer"
    timeout-minutes: 12
    strategy:
      fail-fast: false
      matrix:
        info:
          - {
              os: "windows-2022",
              target: "x86_64-pc-windows-msvc",
              output: "bottom_x86_64_installer.msi",
            }
          - {
              os: "windows-11-arm",
              target: "aarch64-pc-windows-msvc",
              output: "bottom_aarch64_installer.msi",
            }
    runs-on: ${{ matrix.info.os }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      - name: Install Net-Framework-Core
        shell: powershell
        run: |
          choco install dotnet-sdk --pre -y --no-progress;

      - name: Install wixtoolset
        shell: powershell
        run: |
          choco install -y wixtoolset --no-progress;

      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ env.RUST_VERSION }}
          target: ${{ matrix.info.target }}

      - name: Install cargo-wix
        shell: powershell
        run: |
          cargo install cargo-wix --version 0.3.8 --locked

      - name: Build MSI file
        shell: powershell
        env:
          BTM_GENERATE: true
        run: |
          Import-Module "$env:ChocolateyInstall/helpers/chocolateyInstaller.psm1"
          refreshenv
          cargo wix --nocapture
          mv bottom_installer.msi ${{ matrix.info.output }}

      - name: Generate artifact attestation for file
        uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2
        with:
          subject-path: ${{ matrix.info.output }}

      - name: Create release directory for artifact, move files
        shell: bash
        run: |
          mkdir release
          mv ${{ matrix.info.output }} release/

      - name: Save release as artifact
        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        with:
          retention-days: 3
          name: "release-${{ matrix.info.target }}-msi"
          path: release

  build-cirrus:
    name: "Build using Cirrus CI"
    runs-on: "ubuntu-24.04"
    timeout-minutes: 12
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 0

      - name: Create release directory
        run: |
          mkdir -p release

      - name: Execute Cirrus CI build script
        env:
          CIRRUS_KEY: ${{ secrets.CIRRUS_TOKEN }}
        run: |
          if [[ "${{ github.ref_type }}" == "branch" ]]; then
            BRANCH="${{ github.ref_name }}";
          else
            raw=$(git branch -r --contains '${{ github.ref_name }}');
            BRANCH=${raw##*/};
          fi
          python ./scripts/ci/cirrus_release.py "$BRANCH" "release/" "${{ inputs.caller }}"

      - name: Generate artifact attestation for file
        uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2
        with:
          subject-path: "release/**/*.tar.gz"

      - name: Save release as artifact
        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        with:
          retention-days: 3
          name: release-build-cirrus
          path: release

  build-deb:
    name: "Build .deb software packages"
    runs-on: ${{ matrix.info.os || 'ubuntu-24.04' }}
    timeout-minutes: 12
    strategy:
      fail-fast: false
      matrix:
        info:
          - { target: "x86_64-unknown-linux-gnu", dpkg: amd64 }
          - { target: "x86_64-unknown-linux-musl", cross: true, dpkg: amd64 }
          - {
              target: "aarch64-unknown-linux-gnu",
              cross: false,
              dpkg: arm64,
              os: "ubuntu-22.04-arm",
            }
          # The cross images don't work with ARM runners, unfortunately. We could build it on x86 with cross
          # and then copy it over to an ARM runner but that's kind of annoying, so I'll skip this for now.
          # TODO: Maybe improve how we do the .deb software building step?
          - {
              target: "aarch64-unknown-linux-musl",
              cross: true,
              dpkg: arm64,
              container: "ghcr.io/clementtsang/cargo-deb-aarch64-unknown-linux-gnu",
            }
          - {
              target: "armv7-unknown-linux-gnueabihf",
              cross: true,
              dpkg: armhf,
              container: "ghcr.io/clementtsang/cargo-deb-armv7-unknown-linux-gnueabihf",
            }
          - {
              target: "armv7-unknown-linux-musleabihf",
              cross: true,
              dpkg: armhf,
              container: "ghcr.io/clementtsang/cargo-deb-armv7-unknown-linux-gnueabihf",
            }
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ matrix.info.rust || env.RUST_VERSION }}
          target: ${{ matrix.info.target }}

      - name: Build
        uses: ClementTsang/cargo-action@2438cc5f3ba4e971289fffca2a00dedea6911f14 # v0.0.7
        env:
          BTM_GENERATE: true
          BTM_BUILD_RELEASE_CALLER: ${{ inputs.caller }}
        with:
          command: build
          args: --release --locked --features deploy --target ${{ matrix.info.target }}
          use-cross: ${{ matrix.info.cross || false }}
          cross-version: ${{ env.CROSS_VERSION }}

      - name: Move automatically generated completion/manpage
        shell: bash
        run: |
          mv "$COMPLETION_DIR" completion
          mv "$MANPAGE_DIR" manpage

      - name: Zip manpage
        run: |
          gzip ./manpage/btm.1

      - name: Build Debian release (non-container)
        if: ${{ matrix.info.container == '' }}
        env:
          BTM_GENERATE: true
        run: |
          cargo install cargo-deb --version 3.5.0 --locked
          cargo deb --no-build --target ${{ matrix.info.target }}
          cp ./target/debian/bottom_*.deb .

      - name: Build Debian release (container)
        if: ${{ matrix.info.container != '' }}
        env:
          BTM_GENERATE: true
        run: |
          docker pull ${{ matrix.info.container }}
          docker run -t --rm --mount type=bind,source="$(pwd)",target=/volume ${{ matrix.info.container }} "--no-build --variant ${{ matrix.info.dpkg }} --target ${{ matrix.info.target }}" "/volume"
          cp ./target/debian/bottom-*.deb .
          TMP_NAME=$(find bottom-*.deb)
          VERSION=${{ matrix.info.dpkg }}
          mv $TMP_NAME $(echo $TMP_NAME | sed "s/-$VERSION//")

      - name: Rename if it is a musl target
        if: contains(matrix.info.target, 'musl')
        run: |
          TMP_NAME=$(find bottom_*.deb)
          mv $TMP_NAME $(echo $TMP_NAME | sed "s/bottom/bottom-musl/")

      # TODO: Maybe rename version if nightly?
      - name: Verify Debian release
        id: verify
        run: |
          DEB_FILE=$(find bottom*_*.deb)
          dpkg -I $DEB_FILE
          dpkg -I $DEB_FILE | grep ${{ matrix.info.dpkg }} && echo "Found correct architecture"
          echo "DEB_FILE=$DEB_FILE" >> $GITHUB_OUTPUT

      - name: Delete generated Debian folder
        run: |
          sudo chown $USER ./target/debian/ 2>/dev/null || true
          rm -r ./target/debian/

      - name: Generate artifact attestation for file
        uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2
        with:
          subject-path: ${{ steps.verify.outputs.DEB_FILE }}

      - name: Create release directory for artifact, move file
        shell: bash
        run: |
          mkdir release
          mv ${{ steps.verify.outputs.DEB_FILE }} release/

      - name: Save release as artifact
        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        with:
          retention-days: 3
          name: release-build-deb-${{ matrix.info.target }}
          path: release

  build-rpm:
    name: "Build .rpm software packages"
    runs-on: ubuntu-24.04
    container: ghcr.io/clementtsang/almalinux-8
    timeout-minutes: 12
    strategy:
      fail-fast: false
      matrix:
        info:
          - { target: "x86_64-unknown-linux-gnu" }
          - { target: "x86_64-unknown-linux-musl", cross: true }
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ matrix.info.rust || env.RUST_VERSION }}
          target: ${{ matrix.info.target }}

      - name: Build
        uses: ClementTsang/cargo-action@2438cc5f3ba4e971289fffca2a00dedea6911f14 # v0.0.7
        env:
          BTM_GENERATE: true
          BTM_BUILD_RELEASE_CALLER: ${{ inputs.caller }}
          CROSS_CONTAINER_IN_CONTAINER: true
        with:
          command: build
          use-cross: ${{ matrix.info.cross || false }}
          args: --release --locked --features deploy --target ${{ matrix.info.target }}
          cross-version: ${{ env.CROSS_VERSION }}

      - name: Move automatically generated completion/manpage
        shell: bash
        run: |
          mv "$COMPLETION_DIR" completion
          mv "$MANPAGE_DIR" manpage

      - name: Zip manpage
        run: |
          gzip ./manpage/btm.1

      - name: Build rpm release
        env:
          BTM_GENERATE: true
        run: |
          cargo install cargo-generate-rpm --version 0.20.0 --locked
          cargo generate-rpm --target ${{ matrix.info.target }}
          cp ./target/${{ matrix.info.target }}/generate-rpm/bottom-*.rpm .

      - name: Rename if it is a musl target
        if: contains(matrix.info.target, 'musl')
        run: |
          TMP_NAME=$(find bottom-*.rpm)
          mv $TMP_NAME $(echo $TMP_NAME | sed "s/bottom/bottom-musl/")

      - name: Verify generated rpm file
        id: verify
        run: |
          RPM_FILE=$(find bottom-*.rpm)
          rpm -qip $RPM_FILE
          # Save for future jobs
          echo "RPM_FILE=$RPM_FILE" >> $GITHUB_OUTPUT

      - name: Check generated rpm file signatures
        run: |
          rpm --checksig --verbose ${{ steps.verify.outputs.RPM_FILE }}
          # Validate modern signature digest exist, see https://github.com/ClementTsang/bottom/issues/1848
          rpm --checksig --verbose ${{ steps.verify.outputs.RPM_FILE }} | grep -q "SHA256"

      - name: Test installing generated rpm file
        run: |
          yum localinstall -y ${{ steps.verify.outputs.RPM_FILE }}
          btm -V

      - name: Delete generated rpm folder
        run: |
          sudo chown $USER ./target/${{ matrix.info.target }}/generate-rpm/ 2>/dev/null || true
          rm -r ./target/${{ matrix.info.target }}/generate-rpm/

      - name: Generate artifact attestation for file
        uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2
        with:
          subject-path: ${{ steps.verify.outputs.RPM_FILE }}

      - name: Create release directory for artifact, move file
        shell: bash
        run: |
          mkdir release
          mv ${{ steps.verify.outputs.RPM_FILE }} release/

      - name: Save release as artifact
        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        with:
          retention-days: 3
          name: release-build-rpm-${{ matrix.info.target }}
          path: release

  test-installing:
    name: "Test Installing"
    runs-on: ${{ matrix.info.os }}
    container: ${{ matrix.info.container }}
    timeout-minutes: 12
    strategy:
      fail-fast: false
      matrix:
        info:
          - { os: "ubuntu-22.04", target: "x86_64-unknown-linux-gnu" }
          - { os: "macos-15", target: "aarch64-apple-darwin" }
          - { os: "windows-2022", target: "x86_64-pc-windows-msvc" }
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ matrix.info.rust || env.RUST_VERSION }}
          target: ${{ matrix.info.target }}

      - name: Install (locked)
        shell: bash
        run: |
          cargo install --path . --locked
          btm -V
          cargo uninstall bottom

      - name: Install (not locked)
        shell: bash
        run: |
          cargo install --path .
          btm -V
          cargo uninstall bottom


================================================
FILE: .github/workflows/ci.yml
================================================
# Main CI workflow to validate that files are formatted correctly, pass tests,
# and pass lints.
#
# CI workflow was based on a lot of work from other people:
# - https://github.com/heim-rs/heim/blob/master/.github/workflows/ci.yml
# - https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/ci.yml
# - https://www.reillywood.com/blog/rust-faster-ci/
# - https://matklad.github.io/2021/09/04/fast-rust-builds.html

name: ci

on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main

env:
  RUST_BACKTRACE: 1
  CARGO_INCREMENTAL: 0
  CARGO_PROFILE_DEV_DEBUG: 0
  CARGO_HUSKY_DONT_INSTALL_HOOKS: true
  COMPLETION_DIR: "target/tmp/bottom/completion/"
  MANPAGE_DIR: "target/tmp/bottom/manpage/"
  CROSS_VERSION: "git:588b3c99db52b5a9c5906fab96cfadcf1bde7863"

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' || github.repository != 'ClementTsang/bottom' }}

jobs:
  # Check if things should be skipped.
  pre-job:
    runs-on: ubuntu-24.04
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - name: Check if this action should be skipped
        id: skip_check
        uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
        with:
          skip_after_successful_duplicate: "true"
          paths: '[".cargo/**", ".github/workflows/ci.yml", ".github/ci/**", "sample_configs/**", "src/**", "tests/**", "build.rs", "Cargo.lock", "Cargo.toml", "clippy.toml", "rustfmt.toml", "Cross.toml"]'
          do_not_skip: '["workflow_dispatch", "push"]'

  # Runs rustfmt + tests + clippy on the main supported platforms.
  supported:
    needs: pre-job
    if: ${{ needs.pre-job.outputs.should_skip != 'true' }}
    runs-on: ${{ matrix.info.os }}
    timeout-minutes: 12
    strategy:
      fail-fast: false
      matrix:
        info:
          - {
              os: "ubuntu-24.04",
              target: "x86_64-unknown-linux-gnu",
              cross: false,
            }
          - {
              os: "ubuntu-24.04-arm",
              target: "aarch64-unknown-linux-gnu",
              cross: false,
            }
          - { os: "macos-15", target: "x86_64-apple-darwin", cross: false }
          - { os: "macos-15", target: "aarch64-apple-darwin", cross: false }
          - {
              os: "windows-2022",
              target: "x86_64-pc-windows-msvc",
              cross: false,
            }
        features: ["--all-features", "--no-default-features"]
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ env.RUST_VERSION }}
          components: rustfmt, clippy
          target: ${{ matrix.info.target }}

      - name: Enable Rust cache
        uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # 2.8.1
        if: ${{ github.event_name != 'pull_request' || ! github.event.pull_request.head.repo.fork }} # If it is a PR, only if not a fork
        with:
          key: ${{ matrix.info.target }}
          cache-all-crates: true

      - name: Check cargo fmt
        run: cargo fmt --all -- --check

      # TODO: add junit output using nextest for codecov (https://docs.codecov.com/docs/test-analytics)
      - name: Run tests
        uses: ClementTsang/cargo-action@2438cc5f3ba4e971289fffca2a00dedea6911f14 # v0.0.7
        with:
          command: test
          args: --no-fail-fast --locked ${{ matrix.features }} --target=${{ matrix.info.target }} -- --nocapture --quiet
          use-cross: ${{ matrix.info.cross }}
          cross-version: ${{ env.CROSS_VERSION }}
        env:
          RUST_BACKTRACE: full

      - name: Run clippy
        uses: ClementTsang/cargo-action@2438cc5f3ba4e971289fffca2a00dedea6911f14 # v0.0.7
        with:
          command: clippy
          args: ${{ matrix.features }} --all-targets --workspace --locked --target=${{ matrix.info.target }} -- -D warnings
          use-cross: ${{ matrix.info.cross }}
          cross-version: ${{ env.CROSS_VERSION }}
        env:
          RUST_BACKTRACE: full

  # Run checks for unsupported platforms.
  #
  # Each target specifies a list of checks to run via the 'checks' array property.
  # Available checks:
  #   - format: Run cargo fmt --check
  #   - clippy: Clippy with all features (warnings allowed)
  #   - clippy-deny: Clippy with all features (deny on warnings, implies clippy)
  #   - clippy-no-features: Clippy with no features (warnings allowed)
  #   - test: Run cargo test
  #
  # Note: 'clippy-deny' implies 'clippy' and is mutually exclusive with it.
  # Also, 'clippy' and 'clippy-deny' cannot be combined with 'clippy-no-features'.
  #
  # TODO: Maybe some of these should be allowed to fail? If so, I guess we can add back the "unofficial" MSRV,
  # I would also put android there.
  unsupported-check:
    needs: pre-job
    strategy:
      fail-fast: false
      matrix:
        info:
          # x86 or x86-64
          - {
              os: "ubuntu-24.04",
              target: "i686-unknown-linux-gnu",
              cross: true,
              checks: ["format", "clippy-deny", "test"],
            }
          - {
              os: "ubuntu-24.04",
              target: "x86_64-unknown-linux-musl",
              cross: false,
              checks: ["format", "clippy-deny", "test"],
            }
          - {
              os: "ubuntu-24.04",
              target: "i686-unknown-linux-musl",
              cross: true,
              checks: ["format", "clippy-deny", "test"],
            }

          - {
              os: "windows-2022",
              target: "i686-pc-windows-msvc",
              cross: false,
              checks: ["format", "clippy-deny", "test"],
            }
          - {
              os: "windows-2022",
              target: "x86_64-pc-windows-gnu",
              cross: false,
              checks: ["format", "clippy-deny", "test"],
            }

          # Windows ARM
          # TODO: Promote to official?
          - {
              os: "windows-11-arm",
              target: "aarch64-pc-windows-msvc",
              cross: false,
              checks: ["format", "clippy-deny", "test"],
            }

          # Beta
          - {
              os: "ubuntu-24.04",
              target: "x86_64-unknown-linux-gnu",
              cross: false,
              rust: "beta",
              checks: ["format", "clippy-deny", "test"],
            }
          - {
              os: "macos-15",
              target: "aarch64-apple-darwin",
              cross: false,
              rust: "beta",
              checks: ["format", "clippy-deny", "test"],
            }
          - {
              os: "windows-2022",
              target: "x86_64-pc-windows-msvc",
              cross: false,
              rust: "beta",
              checks: ["format", "clippy-deny", "test"],
            }

          # armv7
          - {
              os: "ubuntu-24.04",
              target: "armv7-unknown-linux-gnueabihf",
              cross: true,
              checks: ["clippy-no-features"],
            }

          # armv6
          - {
              os: "ubuntu-24.04",
              target: "arm-unknown-linux-gnueabihf",
              cross: true,
              checks: ["clippy-no-features"],
            }

          # PowerPC 64 LE
          - {
              os: "ubuntu-24.04",
              target: "powerpc64le-unknown-linux-gnu",
              cross: true,
              checks: ["clippy-no-features"],
            }

          # Risc-V 64gc
          - {
              os: "ubuntu-24.04",
              target: "riscv64gc-unknown-linux-gnu",
              cross: true,
              checks: ["clippy-no-features"],
            }

          # Loongarch
          - {
              os: "ubuntu-24.04",
              target: "loongarch64-unknown-linux-gnu",
              cross: true,
              checks: ["clippy-no-features"],
            }

          # Android ARM64
          - {
              os: "ubuntu-24.04",
              target: "aarch64-linux-android",
              cross: true,
              checks: ["clippy-no-features"],
            }

          # FreeBSD
          - {
              os: "ubuntu-24.04",
              target: "x86_64-unknown-freebsd",
              cross: true,
              os-version: "15.0",
              checks: ["format", "clippy", "test"],
            }

          # NetBSD
          - {
              os: "ubuntu-24.04",
              target: "x86_64-unknown-netbsd",
              cross: true,
              os-version: "10.1",
              checks: ["clippy", "test"],
            }
    runs-on: ${{ matrix.info.os }}
    if: ${{ needs.pre-job.outputs.should_skip != 'true' }}
    timeout-minutes: 12
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ matrix.info.rust || env.RUST_VERSION }}
          target: ${{ matrix.info.target }}
          components: ${{ contains(matrix.info.checks, 'format') && 'rustfmt, clippy' || 'clippy' }}

      - name: Enable Rust cache
        uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # 2.8.1
        if: ${{ github.event_name != 'pull_request' || ! github.event.pull_request.head.repo.fork }} # If it is a PR, only if not a fork
        with:
          key: ${{ matrix.info.target }}
          cache-all-crates: true

      - name: Check cargo fmt
        if: ${{ contains(matrix.info.checks, 'format') }}
        run: cargo fmt --all -- --check

      - name: Run tests
        uses: ClementTsang/cargo-action@2438cc5f3ba4e971289fffca2a00dedea6911f14 # v0.0.7
        if: ${{ contains(matrix.info.checks, 'test') && !contains(matrix.info.target, 'bsd') }}
        with:
          command: test
          args: --no-fail-fast --locked --target=${{ matrix.info.target }} -- --nocapture --quiet
          use-cross: ${{ matrix.info.cross }}
          cross-version: ${{ matrix.info.cross-version || env.CROSS_VERSION }}
        env:
          RUST_BACKTRACE: full

      # *BSD targets run tests in a VM due to cross limitations.
      - name: Run tests (BSD)
        if: ${{ contains(matrix.info.checks, 'test') && contains(matrix.info.target, 'bsd') }}
        uses: ./.github/actions/test-bsd-target
        with:
          target: ${{ matrix.info.target }}
          os-version: ${{ matrix.info.os-version }}

      - name: Set up clippy configuration
        shell: bash
        run: |
          if [[ "${{ contains(matrix.info.checks, 'clippy') && contains(matrix.info.checks, 'clippy-deny') }}" == "true" ]]; then
            echo "Error: Cannot have both 'clippy' and 'clippy-deny'. 'clippy-deny' implies 'clippy' with stricter warnings."
            exit 1
          fi

          if [[ "${{ contains(matrix.info.checks, 'clippy-deny') && contains(matrix.info.checks, 'clippy-no-features') }}" == "true" ]]; then
            echo "Error: Cannot have both 'clippy-deny' (all-features) and 'clippy-no-features'. They are mutually exclusive."
            exit 1
          fi

          if [[ "${{ contains(matrix.info.checks, 'clippy') && contains(matrix.info.checks, 'clippy-no-features') }}" == "true" ]]; then
            echo "Error: Cannot have both 'clippy' (all-features) and 'clippy-no-features' in the same checks array. They are mutually exclusive."
            exit 1
          fi

          # Determine deny vs warn flags
          if [[ "${{ contains(matrix.info.checks, 'clippy-deny') }}" == "true" ]]; then
            echo "CLIPPY_FLAGS_EXTRA=-D warnings" >> $GITHUB_ENV
          else
            echo "CLIPPY_FLAGS_EXTRA=" >> $GITHUB_ENV
          fi

          # Determine all-features (default) vs no-features
          if [[ "${{ contains(matrix.info.checks, 'clippy-no-features') }}" == "true" ]]; then
            echo "FEATURE_FLAGS=--no-default-features" >> $GITHUB_ENV
          else
            echo "FEATURE_FLAGS=" >> $GITHUB_ENV
          fi

      - name: Run clippy
        uses: ClementTsang/cargo-action@2438cc5f3ba4e971289fffca2a00dedea6911f14 # v0.0.7
        if: ${{ contains(matrix.info.checks, 'clippy') || contains(matrix.info.checks, 'clippy-deny') || contains(matrix.info.checks, 'clippy-no-features') }}
        with:
          command: clippy
          args: --all-targets --workspace --target=${{ matrix.info.target }} --locked ${{ env.FEATURE_FLAGS }} -- ${{ env.CLIPPY_FLAGS_EXTRA }}
          use-cross: ${{ matrix.info.cross }}
          cross-version: ${{ matrix.info.cross-version || env.CROSS_VERSION }}

  # # Check BSD platforms using a VM layer.
  # check-bsd-vm:
  #   needs: pre-job
  #   if: ${{ needs.pre-job.outputs.should_skip != 'true' }}
  #   strategy:
  #     fail-fast: false
  #     matrix:
  #       info:
  #         # OpenBSD is not very well-supported, given that it's tier 3. We skip clippy and only run basic tests + fmt.
  #         # We also use `--no-default-features` when building as starship-battery does not support OpenBSD.
  #         # Cross also doesn't support OpenBSD, so we will do it with VMs here too.
  #         - { os_release: "7.8", target: "x86_64-unknown-openbsd" } # Supports Rust 1.90
  #   uses: ./.github/workflows/bsd_vm_check.yml
  #   with:
  #     os-target: ${{ matrix.info.target }}
  #     os-version: ${{ matrix.info.os_release }}

  completion:
    name: "CI Pass Check"
    needs: [supported, unsupported-check]
    if: ${{ needs.supported.result != 'skipped' || needs.unsupported-check.result != 'skipped' }}
    runs-on: "ubuntu-24.04"
    steps:
      - name: CI Passed
        if: ${{ (needs.supported.result == 'success' || needs.supported.result == 'skipped') && (needs.unsupported-check.result == 'success' || needs.unsupported-check.result == 'skipped') }}
        run: |
          echo "CI workflow completed successfully.";

      - name: CI Failed
        if: ${{ needs.supported.result == 'failure' || needs.unsupported-check.result == 'failure' }}
        run: |
          echo "CI workflow failed.";
          exit 1;

      - name: CI Cancelled
        if: ${{ needs.supported.result == 'cancelled' || needs.unsupported-check.result == 'cancelled' }}
        run: |
          echo "CI workflow was cancelled.";
          exit 1;


================================================
FILE: .github/workflows/clear_workflow_cache.yml
================================================
# Simple job to clear the cache used by a workflow. This automatically runs when a PR is closed/merged
# to clean up the corresponding PR's cache.

name: "clear workflow cache"

on:
  workflow_dispatch:
    inputs:
      id:
        description: "Which id to clear. Type main/master/all to clean all, and keep-main/keep-master to clean all but the main branch."
        required: false
  pull_request:
    types:
      - closed
  schedule:
    - cron: "0 11 * * 0"

jobs:
  clear-cache:
    if: ${{ github.event_name != 'pull_request' || ! github.event.pull_request.head.repo.fork }} # If it is a PR, only if not a fork
    runs-on: ubuntu-24.04
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      # We run each script twice with a small delay in between to try and catch everything.
      - name: Clear cache
        run: |
          if [[ -n "${{ github.event.schedule }}" ]]; then
            python ./scripts/clear_cache.py keep-main
            sleep 5
            python ./scripts/clear_cache.py keep-main
          elif [[ -z "${{ github.event.inputs.id }}" ]]; then
            python ./scripts/clear_cache.py ${{ github.event.pull_request.number }}
            sleep 5
            python ./scripts/clear_cache.py ${{ github.event.pull_request.number }}
          else
            python ./scripts/clear_cache.py ${{ github.event.inputs.id }}
            sleep 5
            python ./scripts/clear_cache.py ${{ github.event.inputs.id }}
          fi


================================================
FILE: .github/workflows/coverage.yml
================================================
# Code coverage generation via cargo-llvm-cov, which is then uploaded to Codecov.
# Codecov will report back via a comment if run on a PR.
#
# Note that Codecov will report back the average all uploaded coverage files.

name: codecov

on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main

env:
  CARGO_INCREMENTAL: 0
  CARGO_HUSKY_DONT_INSTALL_HOOKS: true

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' || github.repository != 'ClementTsang/bottom' }}

jobs:
  pre-job:
    runs-on: ubuntu-24.04
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - id: skip_check
        uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
        with:
          skip_after_successful_duplicate: "false"
          paths: '["tests/**", "src/**", ".github/workflows/coverage.yml", ".github/ci", ".cargo/**", "Cargo.toml", "Cargo.lock", "build.rs"]'
          do_not_skip: '["workflow_dispatch", "push"]'

  coverage:
    needs: pre-job
    if: ${{ needs.pre-job.outputs.should_skip != 'true' }}
    runs-on: ${{ matrix.info.os }}
    timeout-minutes: 12
    strategy:
      fail-fast: false
      matrix:
        info:
          - { os: "ubuntu-24.04", target: "x86_64-unknown-linux-gnu" }
          - { os: "macos-14", target: "aarch64-apple-darwin", cross: false }
          - { os: "windows-2022", target: "x86_64-pc-windows-msvc" }
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Read Rust version
        shell: bash
        run: |
          VER=$(cat .github/ci/rust_version.txt)
          echo "RUST_VERSION=$VER" >> $GITHUB_ENV
          echo "$VER"

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
        with:
          toolchain: ${{ env.RUST_VERSION }}

      - name: Enable Rust cache
        uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # 2.8.1
        if: ${{ github.event_name != 'pull_request' || ! github.event.pull_request.head.repo.fork }} # If it is a PR, only if not a fork
        with:
          key: ${{ matrix.info.target }}
          cache-all-crates: true

      - name: Install cargo-llvm-cov
        run: |
          rustup component add llvm-tools-preview
          cargo install cargo-llvm-cov --version 0.6.22 --locked

      - name: Generate code coverage
        run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info --locked --target=${{ matrix.info.target }}

      # The token is generally not needed, but sometimes the default shared token hits limits.
      # Yes this is ugly as hell. Why retrying is not a built-in feature of GHA, I have no idea.

      - name: Upload to codecov.io (Attempt 1)
        uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
        with:
          files: lcov.info
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}
          flags: ${{ matrix.info.os }}
        id: upload_attempt_1
        continue-on-error: true

      - name: Upload to codecov.io (Attempt 2)
        uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
        with:
          files: lcov.info
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}
          flags: ${{ matrix.info.os }}
        if: steps.upload_attempt_1.outcome == 'failure'
        id: upload_attempt_2
        continue-on-error: true

      - name: Upload to codecov.io (Attempt 3)
        uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
        with:
          files: lcov.info
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}
          flags: ${{ matrix.info.os }}
        if: steps.upload_attempt_2.outcome == 'failure'
        id: upload_attempt_3


================================================
FILE: .github/workflows/deployment.yml
================================================
# How we deploy a release. Covers binary builds. Also manages packaging for choco.
#
# Binaries are primarily built by GHA, though some Linux, M1 macOS, and FreeBSD builds are
# handled by CirrusCI.

name: deployment

on:
  workflow_dispatch:
    inputs:
      tag:
        description: "Which tag to deploy as:"
        required: true
  push:
    tags:
      - "[0-9]+.[0-9]+.[0-9]+"

env:
  CARGO_INCREMENTAL: 0
  CARGO_PROFILE_DEV_DEBUG: 0
  CARGO_HUSKY_DONT_INSTALL_HOOKS: true

jobs:
  initialize:
    name: initialize
    runs-on: ubuntu-24.04
    outputs:
      version: ${{ env.VERSION }}
    steps:
      - name: Get the release version from the tag
        if: env.VERSION == ''
        run: |
          if [[ -n "${{ github.event.inputs.tag }}" ]]; then
            echo "Manual run against a tag; overriding actual tag in the environment..."
            echo "VERSION=${{ github.event.inputs.tag }}" >> $GITHUB_ENV
          else
            echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
          fi

      - name: Validate version environment variable
        run: |
          echo "Version being built against is version ${{ env.VERSION }}"!

  build-release:
    needs: [initialize]
    uses: ./.github/workflows/build_releases.yml
    with:
      caller: "deployment"
    secrets: inherit

  generate-choco:
    needs: [initialize, build-release]
    name: "Generate Chocolatey files"
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      - name: Set release version
        shell: bash
        run: |
          echo "RELEASE_VERSION=${{ needs.initialize.outputs.version }}" >> $GITHUB_ENV

      - name: Validate release version
        run: |
          echo "Release version: ${{ env.RELEASE_VERSION }}"

      - name: Get release artifacts
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          pattern: release-*
          path: release
          merge-multiple: true

      - name: Execute choco packaging script
        run: |
          python "./scripts/windows/choco/choco_packager.py" "./release/bottom_x86_64-pc-windows-msvc.zip" ${{ env.RELEASE_VERSION }} "./scripts/windows/choco/bottom.nuspec.template" "./scripts/windows/choco/chocolateyinstall.ps1.template" "bottom.nuspec" "tools/chocolateyinstall.ps1" "tools/"
          zip -r choco.zip "bottom.nuspec" "tools"

      - name: Move release file into release directory
        shell: bash
        run: mv choco.zip release/

      - name: Save release as artifact
        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
        with:
          retention-days: 3
          name: release-choco
          path: release

  upload-release:
    name: upload-release
    runs-on: ubuntu-24.04
    needs: [initialize, generate-choco, build-release]
    steps:
      - name: Set release version
        shell: bash
        run: |
          echo "RELEASE_VERSION=${{ needs.initialize.outputs.version }}" >> $GITHUB_ENV

      - name: Validate release version
        run: |
          echo "Release version: ${{ env.RELEASE_VERSION }}"

      - name: Get release artifacts
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          pattern: release-*
          path: release
          merge-multiple: true

      - name: Print out all release files
        run: |
          echo "Generated $(ls ./release | wc -l) files:"
          du -h -d 0 ./release/*

      - name: Create release and add release files
        uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # 2.0.8
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          prerelease: false
          tag_name: ${{ env.RELEASE_VERSION }}
          draft: true
          fail_on_unmatched_files: true
          name: ${{ env.RELEASE_VERSION }} Release
          body: |
            <!-- Write summary here -->

            ---

            ## Bug Fixes
              
            ## Features
              
            ## Changes

            ## Other

            ## Internal Changes

            ## New Contributors

            ---

            **Full Changelog:**
          files: |
            ./release/*


================================================
FILE: .github/workflows/docs.yml
================================================
# Workflow to deploy mkdocs documentation.

name: docs

on:
  workflow_dispatch:
  workflow_call:
    inputs:
      nightly:
        description: "Optional nightly redirect override"
        default: ""
        required: false
        type: string
  push:
    branches:
      - main
    paths:
      - "docs/**"
      - ".github/workflows/docs.yml"

env:
  # Assign commit authorship to official GitHub Actions bot when pushing to the `gh-pages` branch:
  GIT_USER: "github-actions[bot]"
  GIT_EMAIL: "41898282+github-actions[bot]@users.noreply.github.com"

jobs:
  build-documentation:
    name: Build and deploy docs
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 0

      - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
        with:
          python-version: 3.12

      - name: Install Python dependencies
        run: pip install -r docs/requirements.txt

      - name: Configure git user and email
        run: ./scripts/ci/configure_git.sh

      - name: Build and deploy docs with mike
        env:
          MKDOCS_NIGHTLY_RELEASE_OVERRIDE: ${{ inputs.nightly || '' }}
        run: |
          cd docs
          mike deploy nightly --push

  publish-gh-pages:
    needs: [build-documentation]
    uses: ./.github/workflows/publish_github_pages.yml
    secrets: inherit


================================================
FILE: .github/workflows/nightly.yml
================================================
# Creates nightly deployment builds for main targets. Note this does not cover package distribution channels,
# such as choco.

name: nightly

on:
  schedule:
    - cron: "0 0 * * *"
  workflow_dispatch:
    inputs:
      isMock:
        description: "Mock run"
        default: true
        required: false
        type: boolean

env:
  CARGO_INCREMENTAL: 0
  CARGO_PROFILE_DEV_DEBUG: 0
  CARGO_HUSKY_DONT_INSTALL_HOOKS: true

jobs:
  # Check if things should be skipped, or if this is a mock job.
  initialize-job:
    name: initialize-job
    runs-on: ubuntu-24.04
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - name: Check if this action should be skipped
        id: skip_check
        uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
        with:
          skip_after_successful_duplicate: "true"
          do_not_skip: '["workflow_dispatch"]'

      - name: Check if mock
        run: |
          if [[ -z "${{ github.event.inputs.isMock }}" ]]; then
            echo "This is a scheduled nightly run."
          elif [[ "${{ github.event.inputs.isMock }}" == "true" ]]; then
            echo "This is a mock run."
          else
            echo "This is NOT a mock run. Watch for the generated files!"
          fi

  build-release:
    needs: initialize-job
    if: ${{ needs.initialize-job.outputs.should_skip != 'true' }}
    uses: ./.github/workflows/build_releases.yml
    with:
      caller: "nightly"
    secrets: inherit

  upload-release:
    name: upload-release
    needs: build-release
    runs-on: ubuntu-24.04
    outputs:
      TAG_NAME: ${{ steps.tag_release_name.outputs.TAG_NAME }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 1

      - name: Get release artifacts
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          pattern: release-*
          path: release
          merge-multiple: true

      - name: Print out all release files
        run: |
          echo "Generated $(ls ./release | wc -l) files:"
          du -h -d 0 ./release/*

      - name: Create and set tag name and release name
        if: github.event.inputs.isMock != 'true'
        id: tag_release_name
        run: |
          COMMIT_HASH=$(git rev-parse --short=8 HEAD)
          TIME=$(date +%s)
          TAG_NAME=$(echo "nightly-$COMMIT_HASH-$TIME")
          echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV
          echo "TAG_NAME=$$TAG_NAME" >> "$GITHUB_OUTPUT"
          echo "$TAG_NAME"

          DATE=$(date '+%Y-%m-%d')
          RELEASE_NAME=$(echo "Nightly ($DATE)")
          echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV
          echo "$RELEASE_NAME"

      # Delete all but last three nightly runs, as well as nightly runs that are a duplicate of today.
      - name: Delete old tags and release if not mock
        if: github.event.inputs.isMock != 'true'
        run: |
          echo "Deleting any nightly runs with the same name as today's nightly run..."
          while true; do
            TO_DELETE_NIGHTLY=$(gh release list --json name,tagName,publishedAt | jq --arg RELEASE_NAME "$RELEASE_NAME" -c '[.[] | select (.tagName | contains("nightly-")) | select (.name == $RELEASE_NAME)][0] | .tagName' | tr -d '"')
            if [[ "$TO_DELETE_NIGHTLY" != "null" && "$TO_DELETE_NIGHTLY" == *"nightly-"* ]]; then
              echo "Will delete nightly release with tag '$TO_DELETE_NIGHTLY'";
              gh release delete $TO_DELETE_NIGHTLY --cleanup-tag || { echo "couldn't delete previous nightly release, halting"; break; }
            else
              echo "no nightly releases left, done";
              break;
            fi
          done

          echo "Now pruning all but the last two nightly runs (so we end up with 3 releases after)..."
          while true; do
            # Very gross trick - keep deleting the 3rd nightly element ([2]) until null.
            TO_DELETE_NIGHTLY=$(gh release list --json name,tagName,publishedAt | jq --arg RELEASE_NAME "$RELEASE_NAME" -c '[.[] | select (.tagName | contains("nightly-"))][2] | .tagName' | tr -d '"')
            if [[ "$TO_DELETE_NIGHTLY" != "null" && "$TO_DELETE_NIGHTLY" == *"nightly-"* ]]; then
              echo "Will delete nightly release with tag '$TO_DELETE_NIGHTLY'";
              gh release delete $TO_DELETE_NIGHTLY --cleanup-tag || { echo "couldn't delete previous nightly release, halting"; break; }
            else
              echo "no nightly releases left, done";
              break;
            fi
          done
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # As a workaround to immutable releases, we create it as a draft first, then manually publish it after.
      - name: Add all release files and create nightly release if not mock
        uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # 2.0.8
        if: github.event.inputs.isMock != 'true'
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          draft: true
          fail_on_unmatched_files: true
          name: ${{ env.RELEASE_NAME }}
          files: |
            ./release/*

      - name: Publish the draft release
        if: github.event.inputs.isMock != 'true'
        run: gh release edit "$TAG_NAME" --draft=false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  docs:
    needs: [initialize-job, upload-release]
    if: ${{ needs.initialize-job.outputs.should_skip != 'true' && github.event.inputs.isMock != 'true' }}
    uses: ./.github/workflows/docs.yml
    secrets: inherit
    with:
      nightly: ${{needs.job1.outputs.output1}}


================================================
FILE: .github/workflows/post_release.yml
================================================
# Actions to run after releasing a version, like:
# - Generating documentation via mkdocs
# - Notifying packaging repos

name: post-release

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      tag:
        description: "Which tag to deploy as:"
        required: true

env:
  # Assign commit authorship to official GitHub Actions bot when pushing to the `gh-pages` branch:
  GIT_USER: "github-actions[bot]"
  GIT_EMAIL: "41898282+github-actions[bot]@users.noreply.github.com"

jobs:
  initialize:
    name: initialize
    runs-on: ubuntu-24.04
    outputs:
      version: ${{ env.VERSION }}
    steps:
      - name: Get the release version from the tag
        run: |
          if [[ -n "${{ github.event.inputs.tag }}" ]]; then
            echo "Manual run against a tag; overriding actual tag in the environment..."
            echo "VERSION=${{ github.event.inputs.tag }}" >> "$GITHUB_ENV"
          else
            echo "VERSION=${{ github.event.release.tag_name }}" >> "$GITHUB_ENV"
          fi

      - name: Make sure you're not on master/main/nightly
        run: |
          echo ${{ env.VERSION }}
          if [[ ${{ env.VERSION }} == "master" || ${{ env.VERSION }}  == "main" || ${{ env.VERSION }}  == "nightly" ]]; then
            exit 1
          fi

  docs:
    needs: [initialize]
    runs-on: ubuntu-24.04
    steps:
      - name: Set release version
        shell: bash
        run: |
          echo "RELEASE_VERSION=${{ needs.initialize.outputs.version }}" >> $GITHUB_ENV

      - name: Validate release version
        run: |
          echo "Release version: ${{ env.RELEASE_VERSION }}"

      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 0

      - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
        with:
          python-version: 3.12

      - name: Install Python dependencies
        run: pip install -r docs/requirements.txt

      - name: Configure git user and email
        run: ./scripts/ci/configure_git.sh

      - name: Build and deploy docs with mike as the latest stable branch
        run: |
          cd docs
          mike deploy --push --update-aliases ${RELEASE_VERSION} stable

  publish-gh-pages:
    needs: [docs]
    uses: ./.github/workflows/publish_github_pages.yml
    secrets: inherit

  chocolatey:
    needs: [initialize]
    runs-on: ubuntu-24.04
    steps:
      - name: Set release version
        shell: bash
        run: |
          echo "RELEASE_VERSION=${{ needs.initialize.outputs.version }}" >> $GITHUB_ENV

      - name: Validate release version
        run: |
          echo "Release version: ${{ env.RELEASE_VERSION }}"
      - name: Trigger choco
        run: |
          curl -X POST https://api.github.com/repos/ClementTsang/choco-bottom/dispatches \
          -H 'Accept: application/vnd.github.everest-preview+json' \
          -u ${{ secrets.BOTTOM_PACKAGE_DEPLOYMENT }} \
          --data '{ "event_type": "update", "client_payload": { "version": "'"$RELEASE_VERSION"'" } }'


================================================
FILE: .github/workflows/publish_github_pages.yml
================================================
# Workflow to publish to GitHub Pages. Based on the normal
# job (e.g. https://github.com/ClementTsang/bottom/actions/runs/19805277892),
# but re-implemented so I can pin hashes.
#
# This action uses actions/upload-pages-artifact, which uses actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 (v4.6.2).

name: Publish GitHub Pages

on:
  workflow_dispatch:
  workflow_call:

jobs:
  build:
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          ref: gh-pages
          submodules: recursive
          fetch-depth: 1

      - name: Upload artifact
        id: upload
        uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0
        with:
          path: "./"

  deploy:
    runs-on: ubuntu-24.04
    needs: build
    if: github.ref == 'refs/heads/main'
    environment:
      name: github-pages
      url: ${{ steps.deploy.outputs.page_url }}
    permissions:
      pages: write
      id-token: write
    steps:
      - name: Deploy to GitHub Pages
        id: deploy
        uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5


================================================
FILE: .github/workflows/test_docs.yml
================================================
# Small CI workflow to test if mkdocs documentation can be successfully built.

name: test docs

on:
  workflow_dispatch:
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' || github.repository != 'ClementTsang/bottom' }}

jobs:
  pre-job:
    runs-on: ubuntu-24.04
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - id: skip_check
        uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
        with:
          skip_after_successful_duplicate: "true"
          paths: '["docs/**", ".github/workflows/docs.yml", ".github/workflows/test_docs.yml"]'
          do_not_skip: '["workflow_dispatch"]'

  test-build-documentation:
    name: Test building docs
    needs: pre-job
    if: ${{ needs.pre-job.outputs.should_skip != 'true' }}
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 0

      - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
        with:
          python-version: 3.12

      - name: Install Python dependencies
        run: pip install -r docs/requirements.txt

      - name: Build docs with mkdocs
        run: |
          cd docs
          mkdocs build


================================================
FILE: .github/workflows/validate_schema.yml
================================================
# Workflow to validate the latest schema.

name: "validate schema"
on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main
    paths:
      - "schema/**"
      - "scripts/schema/**"
      - ".github/workflows/validate_schema.yml"
      - "src/bin/schema.rs"
      - "Cargo.toml"

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' || github.repository != 'ClementTsang/bottom' }}

jobs:
  pre-job:
    runs-on: ubuntu-24.04
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - id: skip_check
        uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
        with:
          skip_after_successful_duplicate: "true"
          paths: '["schema/**", "scripts/schema/**", ".github/workflows/validate_schema.yml", ".github/ci", "src/bin/schema.rs", "Cargo.toml"]'
          do_not_skip: '["workflow_dispatch"]'

  test-build-documentation:
    name: Test validating schema
    needs: pre-job
    if: ${{ needs.pre-job.outputs.should_skip != 'true' }}
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout repository
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          fetch-depth: 0

      - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
        with:
          python-version: 3.12

      - name: Install Python dependencies
        run: pip install -r scripts/schema/requirements.txt

      - name: Test nightly validates on valid sample configs
        run: |
          python3 scripts/schema/validator.py -s ./schema/nightly/bottom.json -f ./sample_configs/default_config.toml
          python3 scripts/schema/validator.py --uncomment -s ./schema/nightly/bottom.json -f ./sample_configs/default_config.toml
          python3 scripts/schema/validator.py -s ./schema/nightly/bottom.json -f ./sample_configs/demo_config.toml

      - name: Test nightly catches on a bad sample config
        run: |
          python3 scripts/schema/validator.py -s ./schema/nightly/bottom.json -f scripts/schema/bad_file.toml --should_fail


================================================
FILE: .gitignore
================================================
# Generated by Cargo
# will have compiled files and executables
/target/

# These are backup files generated by rustfmt
**/*.rs.bk

# Logging
*.log

# Flamegraph stuff
flamegraphs/
rust-unmangle
./*.svg
flamegraph.svg
*.data
*.data.old

# IntelliJ
.idea/

# Heaptrack files
*.zst

# For testing
sample_configs/testing*.toml

# Cargo-deny
deny.toml

# Editors
.vscode
.zed
.idea

# mkdocs
site/

# dhat heap profiling
dhat-heap.json
dhat/

# cargo vet
supply-chain/

# samply profiling
profile.json
profile.json.gz

**/venv/

# Sometimes used for scripts
.ruff_cache


================================================
FILE: .markdownlint.json
================================================
{
  "MD013": false,
  "MD041": false,
  "MD033": false,
  "MD040": false,
  "MD024": false,
  "MD025": false,
  "MD046": false,
  "MD059": false,
}


================================================
FILE: CHANGELOG.md
================================================
# Changelog

All notable changes to this project will be documented in this file. The format is based on
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

Versioning for this project is based on [Semantic Versioning](https://semver.org/spec/v2.0.0.html). More specifically:

**Pre 1.0.0 (current)**:

- Patch versions should aim to only contain bug fixes or non-breaking features/changes.
- Minor versions may break things.

**Post 1.0.0**:

- Patch versions should only contain bug fixes.
- Minor versions should only contain forward-compatible features/changes.
- Major versions may break things.

That said, these are more guidelines rather than hard rules, though the project will generally try to follow them.

---

## [0.12.4]/[0.13.0] - Unreleased

### Features

- [#1938](https://github.com/ClementTsang/bottom/pull/1938), [#1980](https://github.com/ClementTsang/bottom/pull/1980): Report average packet size and packet rate.

### Other

- [#1955](https://github.com/ClementTsang/bottom/pull/1955): Fix mirrored documentation deploy to GitHub Pages.
- [#1957](https://github.com/ClementTsang/bottom/pull/1957): Fix CI bug around deploying docs on release.
- [#1958](https://github.com/ClementTsang/bottom/pull/1958): Fix cosmetic banner issue on docs page.

## [0.12.3] - 2026-01-01

### Bug Fixes

- [#1943](https://github.com/ClementTsang/bottom/pull/1943): Fix a crash caused by multibyte UTF8 chars in process names.

### Other

- [#1939](https://github.com/ClementTsang/bottom/pull/1935): Update Fedora install instructions.

## [0.12.2] - 2025-12-25

### Bug Fixes

- [#1933](https://github.com/ClementTsang/bottom/pull/1933): Fix a memory leak in Windows while getting process priority information.

## [0.12.1] - 2025-12-25

### Other

- [#1920](https://github.com/ClementTsang/bottom/pull/1920), [#1921](https://github.com/ClementTsang/bottom/pull/1921):
  Fix issues with installing via Cargo when locked dependencies aren't used.

## [0.12.0] - 2025-12-25

### Features

- [#1830](https://github.com/ClementTsang/bottom/pull/1830): Add spacebar shortcut to toggle process tree expansion.
- [#1861](https://github.com/ClementTsang/bottom/pull/1861): Add read-only mode, where things like killing processes is
  disabled.
- [#1890](https://github.com/ClementTsang/bottom/pull/1890): Add enter key shortcut to close process search widget.
- [#1881](https://github.com/ClementTsang/bottom/pull/1881): Add nice (UNIX-only) and priority columns to the process
  widget.

### Bug Fixes

- [#1910](https://github.com/ClementTsang/bottom/pull/1910): Fix a bug around quote parsing in the process widget's
  search.

### Other

- [#1888](https://github.com/ClementTsang/bottom/pull/1888): Make automatically generated `.deb` package conflict with
  the official one.
- [#1891](https://github.com/ClementTsang/bottom/pull/1891): Fix typos in codebase.
- [#1896](https://github.com/ClementTsang/bottom/pull/1896): Rename Linux icon to avoid collision with generic "bottom"
  icon.
- [#1913](https://github.com/ClementTsang/bottom/pull/1913): Add `loongarch64-unknown-linux-gnu` binary build target in
  CI.
- [#1914](https://github.com/ClementTsang/bottom/pull/1914): Add `aarch64-linux-android` binary build target in CI (with
  no default features).

## [0.11.4] - 2025-11-16

### Bug Fixes

- [#1859](https://github.com/ClementTsang/bottom/pull/1859): Ensure average CPU is drawn on top in "All" mode.
- [#1867](https://github.com/ClementTsang/bottom/pull/1867): Fix network graph y-axis height cache not updating
  correctly.
- [#1867](https://github.com/ClementTsang/bottom/pull/1867): Fix network graph y-axis occasionally starting with a range
  of zero.

### Other

- [#1863](https://github.com/ClementTsang/bottom/pull/1863): Replace bottom icon with a square version.
- [#1865](https://github.com/ClementTsang/bottom/pull/1865): Improve help dialog width calculation.

## [0.11.3] - 2025-11-06

### Features

- [#1812](https://github.com/ClementTsang/bottom/pull/1812): Add `free_arc` option to subtract ARC from total memory
  usage.

### Bug Fixes

- [#1833](https://github.com/ClementTsang/bottom/pull/1833): Sort disk I/O using actual value rather than string
  representation.
- [#1812](https://github.com/ClementTsang/bottom/pull/1812): Fix ARC collection on FreeBSD.
- [#1846](https://github.com/ClementTsang/bottom/pull/1846): Fix displayed average CPU value being wrong in graphs.

### Other

- [#1838](https://github.com/ClementTsang/bottom/pull/1838): Add icon for application.

## [0.11.2] - 2025-10-07

### Features

- [#1793](https://github.com/ClementTsang/bottom/pull/1793): Add support for threads in Linux.
- [#1719](https://github.com/ClementTsang/bottom/pull/1719): Support ignoring all keypresses.
- [#1772](https://github.com/ClementTsang/bottom/pull/1772): Support hiding kernel threads.

### Bug Fixes

- [#1800](https://github.com/ClementTsang/bottom/pull/1800): Fix colon at end of process name in Linux.
- [#1804](https://github.com/ClementTsang/bottom/pull/1804): Draw average CPU last again.
- [#1811](https://github.com/ClementTsang/bottom/pull/1811): Fix drawing average CPU in basic mode when dedicated row is
  enabled.
- [#1817](https://github.com/ClementTsang/bottom/pull/1817): Fix builds for FreeBSD on ARM/PowerPC due to `libc::c_char`
  data type being different.
- [#1821](https://github.com/ClementTsang/bottom/pull/1821): Use alpha version of ratatui version which fixes drawing at
  high resolutions.
- [#1827](https://github.com/ClementTsang/bottom/pull/1827): Fix crash for Windows where the network widget could cause
  a crash if the program started too quickly after boot under certain settings.

### Other

- [#1801](https://github.com/ClementTsang/bottom/pull/1801): Build and check Windows ARM.
- [#1816](https://github.com/ClementTsang/bottom/pull/1816): Optimize username cloning on Unix.

## [0.11.1] - 2025-08-15

### Bug Fixes

- [#1776](https://github.com/ClementTsang/bottom/pull/1776): Fix `disk.columns` being incorrectly interpreted as blank.
- [#1787](https://github.com/ClementTsang/bottom/pull/1787): Fix issue with battery widget time and small widths.

### Other

- [#1779](https://github.com/ClementTsang/bottom/pull/1779), [#1788](https://github.com/ClementTsang/bottom/pull/1788):
  Speed up time between startup and displaying data.

## [0.11.0] - 2025-08-05

### Features

- [#1625](https://github.com/ClementTsang/bottom/pull/1625): Add the ability to configure the disk widget's table
  columns.
- [#1641](https://github.com/ClementTsang/bottom/pull/1641) + [#1692](https://github.com/ClementTsang/bottom/pull/1692):
  Support AMD GPU data collection on Linux.
- [#1642](https://github.com/ClementTsang/bottom/pull/1642): Support changing the widget borders.
- [#1717](https://github.com/ClementTsang/bottom/pull/1717): Support delete key (fn + delete on macOS) to kill
  processes.
- [#1306](https://github.com/ClementTsang/bottom/pull/1306): Support using left/right key to collapse/expand process
  trees respectively.
- [#1767](https://github.com/ClementTsang/bottom/pull/1767): Add a virtual memory column for processes.
- [#1770](https://github.com/ClementTsang/bottom/pull/1770) (
  originally [#1627](https://github.com/ClementTsang/bottom/pull/1627)): Add option to have process tree entries be
  collapsed by default.

### Bug Fixes

- [#1551](https://github.com/ClementTsang/bottom/pull/1551): Fix missing parent section names in default config.
- [#1552](https://github.com/ClementTsang/bottom/pull/1552): Fix typo in default config.
- [#1565](https://github.com/ClementTsang/bottom/pull/1565): Fix issue where CPU usage in basic mode looks weird if core
  count isn't divisible by four.
- [#1578](https://github.com/ClementTsang/bottom/pull/1578): Fix missing selected text background colour in
  `default-light` theme.
- [#1593](https://github.com/ClementTsang/bottom/pull/1593): Fix using `"none"` for chart legend position in configs.
- [#1594](https://github.com/ClementTsang/bottom/pull/1594): Fix incorrect default config definitions for chart legends.
- [#1596](https://github.com/ClementTsang/bottom/pull/1596): Fix support for nilfs2 file system.
- [#1660](https://github.com/ClementTsang/bottom/pull/1660): Fix properly cleaning up the terminal if the program is
  terminated due to an `Err` bubbling to the top.
- [#1663](https://github.com/ClementTsang/bottom/pull/1663): Fix network graphs using log scaling having broken lines
  when a point was 0.
- [#1667](https://github.com/ClementTsang/bottom/pull/1667): Fix for ARC/SWAP not being hidden in basic mode after
  refactor.
- [#1683](https://github.com/ClementTsang/bottom/pull/1683): Fix graph lines potentially showing up behind legends.
- [#1701](https://github.com/ClementTsang/bottom/pull/1701): Fix process kill dialog occasionally causing panics.
- [#1755](https://github.com/ClementTsang/bottom/pull/1755): Fix missing stats/incorrect mount name for certain entries
  in the disk widget.
- [#1759](https://github.com/ClementTsang/bottom/pull/1759): Fix increment for data tables if the change is greater than
  the number of entries left.

### Changes

- [#1559](https://github.com/ClementTsang/bottom/pull/1559): Rename `--enable_gpu` to `--disable_gpu`, and make GPU
  features enabled by default.
- [#1570](https://github.com/ClementTsang/bottom/pull/1570): Consider `$XDG_CONFIG_HOME` on macOS when looking for a
  default config path in a backwards-compatible fashion.
- [#1686](https://github.com/ClementTsang/bottom/pull/1686): Allow hyphenated arguments to work as well (e.g.
  `--autohide-time`).
- [#1701](https://github.com/ClementTsang/bottom/pull/1701): Redesign process kill dialog.
- [#1706](https://github.com/ClementTsang/bottom/pull/1706): Disable mouse capture when `disable_click` is set.
- [#1769](https://github.com/ClementTsang/bottom/pull/1769): Change how we calculate swap usage in Windows.

### Other

- [#1655](https://github.com/ClementTsang/bottom/pull/1655): Better handle NVIDIA GPUs on Linux with only
  libnvidia-ml.so.1.
- [#1658](https://github.com/ClementTsang/bottom/pull/1658): Make it possible to override completion/manpage generation
  output directory via env.
- [#1663](https://github.com/ClementTsang/bottom/pull/1663): Rework how data is stored internally, reducing memory usage
  a bit.
- [#1749](https://github.com/ClementTsang/bottom/pull/1749): Fix invalid desktop file values.

## [0.10.2] - 2024-08-05

### Features

- [#1487](https://github.com/ClementTsang/bottom/pull/1487): Add option to move the AVG CPU bar to another row in basic
  mode.

### Bug Fixes

- [#1541](https://github.com/ClementTsang/bottom/pull/1541): Fix some process details not updating for macOS and
  Windows.
- [#1542](https://github.com/ClementTsang/bottom/pull/1542): Fix confusing process run times being reported on macOS.
- [#1543](https://github.com/ClementTsang/bottom/pull/1543): Fix the `--default_cpu_entry` argument not being checked.

## [0.10.1] - 2024-08-01

### Bug Fixes

- [#1526](https://github.com/ClementTsang/bottom/pull/1526): Fix `--help` description being incorrectly set for a flag,
  breaking the output.

## [0.10.0] - 2024-08-01

### Features

- [#1276](https://github.com/ClementTsang/bottom/pull/1276): Add GPU process info.
- [#1353](https://github.com/ClementTsang/bottom/pull/1353): Support selecting the average CPU graph as a default.
- [#1373](https://github.com/ClementTsang/bottom/pull/1373): Add support for bcachefs in disk widget.
- [#1430](https://github.com/ClementTsang/bottom/pull/1430): Support controlling the graph legend position for memory
  and network graph widgets.
- [#1512](https://github.com/ClementTsang/bottom/pull/1512): Support bold text styling options.
- [#1514](https://github.com/ClementTsang/bottom/pull/1514): Support italic text styling options.

### Changes

- [#1276](https://github.com/ClementTsang/bottom/pull/1276): NVIDIA GPU functionality is now tied behind the
  `--enable_gpu` flag. This will likely be changed in the future.
- [#1344](https://github.com/ClementTsang/bottom/pull/1344): Change the `group` command line-argument to
  `group_processes` for consistency with the config file option.
- [#1376](https://github.com/ClementTsang/bottom/pull/1376): Group together related command-line arguments in `-h` and
  `--help`.
- [#1411](https://github.com/ClementTsang/bottom/pull/1411): Add `time` as a default column.
- [#1436](https://github.com/ClementTsang/bottom/pull/1436): Use actual "swap" value for Windows.
- [#1441](https://github.com/ClementTsang/bottom/pull/1441): The following arguments have changed names:
  - `--left_legend/-l` is now `--cpu_left_legend`.
- [#1441](https://github.com/ClementTsang/bottom/pull/1441): The following config fields have changed names:
  - `expanded_on_startup` is now `expanded`.
  - `left_legend` is now `cpu_left_legend`.
- [#1458](https://github.com/ClementTsang/bottom/pull/1458): Fix a bug with `--hide_table_gap` with the battery widget.
- [#1472](https://github.com/ClementTsang/bottom/pull/1472): The following arguments have changed names:
  - `--mem_as_value` is now `process_memory_as_value`.
- [#1472](https://github.com/ClementTsang/bottom/pull/1472): The following config fields have changed names:
  - `mem_as_value` is now `process_memory_as_value`.
- [#1481](https://github.com/ClementTsang/bottom/pull/1481): The following config fields have changed names:
  - `disk_filter` is now `disk.name_filter`.
  - `mount_filter` is now `disk.mount_filter`.
  - `temp_filter` is now `temperature.sensor_filter`
  - `net_filter` is now `network.interface_filter`
- [#1499](https://github.com/ClementTsang/bottom/pull/1499): Redesign how styling is configured.
- [#1499](https://github.com/ClementTsang/bottom/pull/1499): The following arguments have changed names:
  - `--colors` is now `--theme`
- [#1513](https://github.com/ClementTsang/bottom/pull/1513): Table headers are now bold by default.
- [#1515](https://github.com/ClementTsang/bottom/pull/1515): Show the config path in the error message if unable to
  read/create a config.
- [#1682](https://github.com/ClementTsang/bottom/pull/1682): On Linux, temperature sensor labels now always have their
  first letter capitalized (e.g. "k10temp: tctl" -> "k10temp: Tctl").

### Bug Fixes

- [#1314](https://github.com/ClementTsang/bottom/pull/1314): Fix fat32 mounts not showing up in macOS.
- [#1355](https://github.com/ClementTsang/bottom/pull/1355): Reduce chances of non-D0 devices waking up due to
  temperature checks on Linux.
- [#1410](https://github.com/ClementTsang/bottom/pull/1410): Fix uptime calculation for Linux.

### Other

- [#1394](https://github.com/ClementTsang/bottom/pull/1394): Add JSON Schema support.

## [0.9.7] - 2024-07-26

## Bug Fixes

- [#1500](https://github.com/ClementTsang/bottom/issues/1500): Fix builds for Rust 1.80.

## [0.9.6] - 2023-08-26

### Other

- [#1286](https://github.com/ClementTsang/bottom/pull/1286): Pin serde to 1.0.188 to help with potential `cargo install`
  issues. Note this version should be fine and not pull in binaries.

## [0.9.5] - 2023-08-26

### Other

- [#1278](https://github.com/ClementTsang/bottom/pull/1278): Pin serde to 1.0.171.

## [0.9.4] - 2023-08-05

### Features

- [#1248](https://github.com/ClementTsang/bottom/pull/1248): Add I/O counters from ZFS for Linux and FreeBSD.

### Changes

- [#1236](https://github.com/ClementTsang/bottom/pull/1236): Hide the battery tab selector if there is only one battery
  detected.
- [#1251](https://github.com/ClementTsang/bottom/pull/1251): Make the charge meter take the entire width of the battery
  widget.

### Bug Fixes

- [#1230](https://github.com/ClementTsang/bottom/pull/1230): Fix core dump if the terminal is closed while bottom is
  open.
- [#1245](https://github.com/ClementTsang/bottom/pull/1245): Fix killing processes in Windows leaving a handle open.
- [#1264](https://github.com/ClementTsang/bottom/pull/1264): Fix ARC usage showing max system memory instead of max ARC
  size.

## [0.9.3] - 2023-06-25

### Features

- [#1221](https://github.com/ClementTsang/bottom/pull/1221): Support human times for `rate`.

### Bug Fixes

- [#1216](https://github.com/ClementTsang/bottom/pull/1216): Fix arguments not being sorted alphabetically.
- [#1219](https://github.com/ClementTsang/bottom/pull/1219): Fix overflow/underflow in graph timespan zoom.

### Other

- [#1206](https://github.com/ClementTsang/bottom/pull/1206): Add `.rpm` package generation.
- [#1220](https://github.com/ClementTsang/bottom/pull/1220): Update documentation for features supporting human times.

## [0.9.2] - 2023-06-11

### Features

- [#1172](https://github.com/ClementTsang/bottom/pull/1172): Support human times for `time_delta` and
  `default_time_value`.
- [#1187](https://github.com/ClementTsang/bottom/pull/1187): Use better names for duplicate temp sensors found by
  `/sys/class/thermal`.
- [#1188](https://github.com/ClementTsang/bottom/pull/1188): Also check `/sys/devices/platform/coretemp.*` for temp
  sensors.

### Bug Fixes

- [#1186](https://github.com/ClementTsang/bottom/pull/1186): Fix for temperature sensor data gathering on Linux
  immediately halting if any method failed.
- [#1191](https://github.com/ClementTsang/bottom/pull/1191): Fix ntfs3 mounts not being counted as a physical drive
  type.
- [#1195](https://github.com/ClementTsang/bottom/pull/1195): Fix battery health being incorrectly reported on M1 macOS.
- [#1188](https://github.com/ClementTsang/bottom/pull/1188): Don't fail fast with temperature sensor name generation on
  Linux.

### Other

- [#1199](https://github.com/ClementTsang/bottom/pull/1199): bottom should build on `aarch64-linux-android` with
  features disabled.

## [0.9.1] - 2023-05-14

### Bug Fixes

- [#1148](https://github.com/ClementTsang/bottom/pull/1148): Fix Gruvbox colour string being invalid when cache usage is
  enabled.

## [0.9.0] - 2023-05-10

### Features

- [#1016](https://github.com/ClementTsang/bottom/pull/1016): Add support for displaying process usernames on Windows.
- [#1022](https://github.com/ClementTsang/bottom/pull/1022): Support three-character hex colour strings for styling.
- [#1024](https://github.com/ClementTsang/bottom/pull/1024): Support FreeBSD temperature sensors based on
  `hw.temperature`.
- [#1063](https://github.com/ClementTsang/bottom/pull/1063): Add buffer and cache memory tracking.
- [#1106](https://github.com/ClementTsang/bottom/pull/1106): Add current battery charging state.
- [#1115](https://github.com/ClementTsang/bottom/pull/1115): Add customizable process columns to config file.
- [#801](https://github.com/ClementTsang/bottom/pull/801): Add optional process time column and querying.

### Changes

- [#1025](https://github.com/ClementTsang/bottom/pull/1025): Officially support M1 macOS.
- [#1035](https://github.com/ClementTsang/bottom/pull/1035): Migrate away from heim for CPU information.
- [#1036](https://github.com/ClementTsang/bottom/pull/1036): Migrate away from heim for memory information; bottom will
  now try to use `MemAvailable` on Linux to determine used memory.
- [#1041](https://github.com/ClementTsang/bottom/pull/1041): Migrate away from heim for network information.
- [#1064](https://github.com/ClementTsang/bottom/pull/1064): Migrate away from heim for storage information.
- [#812](https://github.com/ClementTsang/bottom/issues/812): Fully remove heim from bottom.
- [#1075](https://github.com/ClementTsang/bottom/issues/1075): Update how drives are named in Windows.
- [#1106](https://github.com/ClementTsang/bottom/pull/1106): Rename battery consumption field to rate.

### Bug Fixes

- [#1021](https://github.com/ClementTsang/bottom/pull/1021): Fix selected text background colour being wrong if only the
  foreground colour was set.
- [#1037](https://github.com/ClementTsang/bottom/pull/1037): Fix `is_list_ignored` accepting all results if set to
  `false`.
- [#1064](https://github.com/ClementTsang/bottom/pull/1064): Disk name/mount filter now doesn't always show all entries
  if one filter wasn't set.
- [#1064](https://github.com/ClementTsang/bottom/pull/1064): macOS disk I/O is potentially working now.
- [#597](https://github.com/ClementTsang/bottom/issues/597): Resolve RUSTSEC-2021-0119 by removing heim.

### Other

- [#1100](https://github.com/ClementTsang/bottom/pull/1100): Speed up first draw and first data collection.
- [#1107](https://github.com/ClementTsang/bottom/pull/1107): Update to clap v4.
- [#1111](https://github.com/ClementTsang/bottom/pull/1111): Update to
  regex [1.8.0](https://github.com/rust-lang/regex/blob/93316a3b1adc43cc12fab6c73a59f646658cd984/CHANGELOG.md#180-2023-04-20),
  supporting more escapable characters and named captures.

## [0.8.0] - 2023-01-22

### Features

- [#950](https://github.com/ClementTsang/bottom/pull/950): Split usage into both usage percentage and usage value.

### Changes

- [#974](https://github.com/ClementTsang/bottom/pull/974): Hide battery duration section if the value is unknown. Also
  update shortened text.
- [#975](https://github.com/ClementTsang/bottom/pull/975): Automatically hide the battery widget if no batteries are
  found but `--battery` is enabled.

### Bug Fixes

- [#950](https://github.com/ClementTsang/bottom/pull/950): Update help menu for disk and temperature widgets with
  sorting support.
- [#994](https://github.com/ClementTsang/bottom/pull/994): Fix time graph labels not being styled.

### Other

- [#969](https://github.com/ClementTsang/bottom/pull/969): Follow Debian conventions for naming generated `.deb`
  binaries.

## [0.7.1] - 2023-01-06

### Bug Fixes

- [#950](https://github.com/ClementTsang/bottom/pull/950): Fix invalid sorting order for disk usage percentage.
- [#952](https://github.com/ClementTsang/bottom/pull/952), [#960](https://github.com/ClementTsang/bottom/pull/960):
  Partially fix battery text getting cut off in small windows.
- [#953](https://github.com/ClementTsang/bottom/pull/953): Fix CPU widget's 'all' label being missing on small sizes.

### Other

- [#951](https://github.com/ClementTsang/bottom/pull/951): Nightly builds now have their version number (`btm -V`)
  tagged with the commit hash.

## [0.7.0] - 2022-12-31

### Features

- [#676](https://github.com/ClementTsang/bottom/pull/676): Add support for NVIDIA GPU temperature sensors.
- [#760](https://github.com/ClementTsang/bottom/pull/760): Add a check for whether bottom is being run in a terminal.
- [#766](https://github.com/ClementTsang/bottom/pull/766): Add FreeBSD support.
- [#774](https://github.com/ClementTsang/bottom/pull/774): Add half page scrolling with `ctrl-u` and `ctrl-d`.
- [#784](https://github.com/ClementTsang/bottom/pull/784): Add ZFS ARC support.
- [#794](https://github.com/ClementTsang/bottom/pull/794): Add GPU memory support for NVIDIA GPUs.
- [#806](https://github.com/ClementTsang/bottom/pull/806): Update sysinfo to support M1 macOS temperature sensors.
- [#836](https://github.com/ClementTsang/bottom/pull/836): Add CLI options for GPU memory.
- [#841](https://github.com/ClementTsang/bottom/pull/841): Add page up/page down support for the help screen.
- [#868](https://github.com/ClementTsang/bottom/pull/868): Make temperature widget sortable.
- [#870](https://github.com/ClementTsang/bottom/pull/870): Make disk widget sortable.
- [#881](https://github.com/ClementTsang/bottom/pull/881): Add pasting to the search bar.
- [#892](https://github.com/ClementTsang/bottom/pull/892): Add custom retention periods for data.
- [#899](https://github.com/ClementTsang/bottom/pull/899), [#910](https://github.com/ClementTsang/bottom/pull/910), [#912](https://github.com/ClementTsang/bottom/pull/912):
  Add non-normalized CPU usage to processes.
- [#919](https://github.com/ClementTsang/bottom/pull/919): Add an option to expand the default widget on startup.

### Changes

- [#690](https://github.com/ClementTsang/bottom/pull/690): Add some colour to `-h`/`--help` as part of updating to clap
  3.0.
- [#726](https://github.com/ClementTsang/bottom/pull/726): Add ARM musl binary build tasks.
- [#807](https://github.com/ClementTsang/bottom/pull/807): Add more human friendly temperature sensor names for Linux.
- [#845](https://github.com/ClementTsang/bottom/pull/845), [#922](https://github.com/ClementTsang/bottom/pull/922): Add
  macOS M1, FreeBSD 12, and FreeBSD 13 binary build tasks.
- [#916](https://github.com/ClementTsang/bottom/pull/916), [#937](https://github.com/ClementTsang/bottom/pull/937):
  Improve CPU usage by optimizing draw logic of charts and tables.

### Bug Fixes

- [#711](https://github.com/ClementTsang/bottom/pull/711): Fix building in Rust beta 1.61 due to `as_ref()` calls
  causing type inference issues.
- [#717](https://github.com/ClementTsang/bottom/pull/717): Fix clicking on empty space in tables selecting the very last
  entry of a list in some cases.
- [#720](https://github.com/ClementTsang/bottom/pull/720): Fix panic if battery feature was disabled during compilation.
- [#805](https://github.com/ClementTsang/bottom/pull/805): Fix bottom keeping devices awake in certain scenarios.
- [#825](https://github.com/ClementTsang/bottom/pull/825): Use alternative method of getting parent PID in some cases on
  macOS devices to avoid needing root access.
- [#916](https://github.com/ClementTsang/bottom/pull/916): Fix possible gaps with widget layout spacing.
- [#938](https://github.com/ClementTsang/bottom/pull/938): Fix search scrolling with wider Unicode characters.

## [0.6.8] - 2022-02-01

### Bug Fixes

- [#655](https://github.com/ClementTsang/bottom/pull/669): Fix a bug where the number of CPUs is never refreshed.

## [0.6.7] - 2022-01-31

### Features

- [#646](https://github.com/ClementTsang/bottom/pull/646): Add `PgUp`/`PgDown` keybind support to scroll up and down a
  page in a table.

### Bug Fixes

- [#655](https://github.com/ClementTsang/bottom/pull/665): Fix bug where the program would stall in an infinite loop if
  the width of the terminal was too small.

### Other

- [#658](https://github.com/ClementTsang/bottom/pull/658): Update sysinfo.

## [0.6.6] - 2021-12-22

### Changes

- [#637](https://github.com/ClementTsang/bottom/pull/637): Remove duplicate guest time in process CPU calculation

### Bug Fixes

- [#637](https://github.com/ClementTsang/bottom/pull/637): Fix process CPU calculation if /proc/stat CPU line has fewer
  values than expected

## [0.6.5] - 2021-12-19

### Bug Fixes

- [#600](https://github.com/ClementTsang/bottom/pull/600): Address RUSTSEC-2020-0071
- [#627](https://github.com/ClementTsang/bottom/pull/627): Fix `process_command` breaking process widget sorting.

### Internal Changes

- [#608](https://github.com/ClementTsang/bottom/pull/608): Add codecov integration to pipeline.

## [0.6.4] - 2021-09-12

### Changes

- [#557](https://github.com/ClementTsang/bottom/pull/557): Add '/s' to network usage legend to better indicate that it's
  a per-second change.

### Bug Fixes

- [#575](https://github.com/ClementTsang/bottom/pull/575): Updates the procfs library to not crash on kernel version >
    255.

### Internal Changes

- [#551](https://github.com/ClementTsang/bottom/pull/551): Disable AUR package generation in release pipeline since it's
  now in community.
- [#570](https://github.com/ClementTsang/bottom/pull/570): Make battery features optional in compilation.

## [0.6.3] - 2021-07-18

### Changes

- [#547](https://github.com/ClementTsang/bottom/pull/547): Switch Linux memory usage calculation to match htop.

### Bug Fixes

- [#536](https://github.com/ClementTsang/bottom/pull/536): Prevent tests from creating a config file.

- [#542](https://github.com/ClementTsang/bottom/pull/542): Fix missing config options in the default generated config
  file.

- [#545](https://github.com/ClementTsang/bottom/pull/545): Fix inaccurate memory usage/totals in macOS and Linux, switch
  unit to binary prefix.

## [0.6.2] - 2021-06-26

### Features

- [#518](https://github.com/ClementTsang/bottom/pull/518): Add `F9` key as an alternative process kill key.

### Bug Fixes

- [#504](https://github.com/ClementTsang/bottom/pull/504): Fix two bugs causing the battery widget colours and mouse
  events to be broken.

- [#525](https://github.com/ClementTsang/bottom/pull/525): Fix Windows process CPU usage not being divided by the number
  of cores.

### Internal Changes

- [#506](https://github.com/ClementTsang/bottom/pull/506): Migrate a large portion of documentation over to mkdocs.

## [0.6.1] - 2021-05-11

### Bug Fixes

- [#473](https://github.com/ClementTsang/bottom/pull/473): Fix missing string creation for memory usage in collapsed
  entries.

## [0.6.0] - 2021-05-09

### Features

- [#263](https://github.com/ClementTsang/bottom/pull/263): Add the option for fine-grained kill signals on Unix-like
  systems.

- [#333](https://github.com/ClementTsang/bottom/pull/333): Add an "out of" indicator that can be enabled using
  `--show_table_scroll_position` (and its corresponding config option) to help keep track of scrolled position.

- [#379](https://github.com/ClementTsang/bottom/pull/379): Add `--process_command` flag and corresponding config option
  to default to showing a process' command.

- [#381](https://github.com/ClementTsang/bottom/pull/381): Add a filter in the config file for network interfaces.

- [#392](https://github.com/ClementTsang/bottom/pull/392): Add CPU load averages (1, 5, 15) for Unix-based systems.

- [#406](https://github.com/ClementTsang/bottom/pull/406): Add the Nord colour scheme, as well as a light variant.

- [#409](https://github.com/ClementTsang/bottom/pull/409): Add `Ctrl-w` and `Ctrl-h` shortcuts in search, to delete a
  word and delete a character respectively.

- [#413](https://github.com/ClementTsang/bottom/pull/413): Add mouse support for sorting process columns.

- [#425](https://github.com/ClementTsang/bottom/pull/425): Add user into the process widget for Unix-based systems.

- [#437](https://github.com/ClementTsang/bottom/pull/437): Redo dynamic network y-axis, add linear scaling, unit type,
  and prefix options.

- [#445](https://github.com/ClementTsang/bottom/pull/445): Add collapsing in tree mode sums usage to parent.

### Changes

- [#372](https://github.com/ClementTsang/bottom/pull/372): Hide the SWAP graph and legend in normal mode if SWAP is 0.

- [#390](https://github.com/ClementTsang/bottom/pull/390): macOS shouldn't need elevated privileges to see CPU usage on
  all processes now.

- [#391](https://github.com/ClementTsang/bottom/pull/391): Show degree symbol on Celsius and Fahrenheit.

- [#418](https://github.com/ClementTsang/bottom/pull/418): Removed automatically jumping to the top of the list for
  process sort shortcuts. The standard behaviour is to now stay in place.

- [#420](https://github.com/ClementTsang/bottom/pull/420): Updated tui-rs, allowing for prettier looking tables!

- [#437](https://github.com/ClementTsang/bottom/pull/437): Add linear interpolation step in drawing step to pr event
  missing entries on the right side of charts.

- [#443](https://github.com/ClementTsang/bottom/pull/443): Make process widget consistent with disk widget in using
  decimal prefixes (kilo, mega, etc.) for writes/reads.

- [#449](https://github.com/ClementTsang/bottom/pull/449): Add decimal place to actual memory usage in process widget
  for values greater or equal to 1GiB.

- [#450](https://github.com/ClementTsang/bottom/pull/450): Tweak `default-light` colour scheme to look less terrible on
  white terminals.

- [#451](https://github.com/ClementTsang/bottom/pull/451): Add decimal place to disk values larger than 1GB for total
  read/write in process widgets, and read/write per second in process widgets and disk widgets.

- [#455](https://github.com/ClementTsang/bottom/pull/455): Add a mount point filter for the disk widget. Also tweaked
  how the filter system works - see the PR for details.

### Bug Fixes

- [#416](https://github.com/ClementTsang/bottom/pull/416): Fix grouped vs ungrouped modes in the processes widget having
  inconsistent spacing.

- [#417](https://github.com/ClementTsang/bottom/pull/417): Fix the sort menu and sort shortcuts not syncing up.

- [#423](https://github.com/ClementTsang/bottom/pull/423): Fix disk encryption causing the disk widget to fail or not
  properly map I/O statistics.

- [#425](https://github.com/ClementTsang/bottom/pull/425): Fixed a bug allowing grouped mode in tree mode if already in
  grouped mode.

- [#467](https://github.com/ClementTsang/bottom/pull/467): Switched CPU usage data source to fix a bug on Windows where
  occasionally CPU usage would be stuck at 0%.

## [0.5.7] - 2021-01-30

### Bug Fixes

- [#373](https://github.com/ClementTsang/bottom/pull/373): Fix incorrect colours being used the CPU widget in basic
  mode.

- [#386](https://github.com/ClementTsang/bottom/pull/386): Fix `hide_table_gap` not working in the battery widget.

- [#389](https://github.com/ClementTsang/bottom/pull/389): Fix the sorting arrow disappearing in proc widget under some
  cases.

- [#398](https://github.com/ClementTsang/bottom/pull/398): Fix basic mode failing to report CPUs if there are less than
  4 entries to report.

## [0.5.6] - 2020-12-17

### Bug Fixes

- [#361](https://github.com/ClementTsang/bottom/pull/361): Fix temperature sensors not working on non-Linux platforms.

## [0.5.5] - 2020-12-14

### Bug Fixes

- [#349](https://github.com/ClementTsang/bottom/pull/349): Fix CPU graph colours not matching the legend in the "all"
  state.

## [0.5.4] - 2020-12-10

### Changes

- [#344](https://github.com/ClementTsang/bottom/pull/344): Removed the `--debug` option for now.

### Bug Fixes

- [#344](https://github.com/ClementTsang/bottom/pull/344): Fix a performance regression causing high memory and CPU
  usage over time.

- [#345](https://github.com/ClementTsang/bottom/pull/345): Fix process states not showing.

## [0.5.3] - 2020-11-26

### Bug Fixes

- [#331](https://github.com/ClementTsang/bottom/pull/331): Fix custom battery colour levels being inverted.

## [0.5.2] - 2020-11-25

### Bug Fixes

- [#327](https://github.com/ClementTsang/bottom/pull/327): Fix `hide_avg_cpu` being inverted in config files.

## [0.5.1] - 2020-11-22

### Bug Fixes

- [6ef1d66](https://github.com/ClementTsang/bottom/commit/6ef1d66b2bca49452572a2cabb87d338dcf56e7b): Remove nord as a
  valid colour for now.

- [e04ce4f](https://github.com/ClementTsang/bottom/commit/e04ce4fa1b42e99f00cf8825bcd58da43552214e): Fix
  `--use_old_network_legend`.

- [99d0402](https://github.com/ClementTsang/bottom/commit/99d04029f0ebfc73d36adb06ea58ad68f090017c): Fix config
  detection for built-in colours.

## [0.5.0] - 2020-11-20

### Features

- [#206](https://github.com/ClementTsang/bottom/pull/206): Adaptive network graphs --- prior to this update, graphs were
  stuck at a range from 0B to 1GiB. Now, they adjust to your current usage and time span, so if you're using, say, less
  than a MiB, it will cap at a MiB. If you're using 10GiB, then the graph will reflect that and span to a bit greater
  than 10GiB.

- [#208](https://github.com/ClementTsang/bottom/pull/208): Mouse support for tables and moving to widgets.

- [#217](https://github.com/ClementTsang/bottom/pull/217): (Kinda) ARM support.

- [#220](https://github.com/ClementTsang/bottom/pull/220): Add ability to hide specific temperature and disk entries via
  config.

- [#223](https://github.com/ClementTsang/bottom/pull/223): Add tree mode for processes.

  - [#312](https://github.com/ClementTsang/bottom/pull/312): Add a `tree` flag to default to the tree mode.

- [#269](https://github.com/ClementTsang/bottom/pull/269): Add simple indicator for when data updating is frozen.

- [#296](https://github.com/ClementTsang/bottom/pull/296): Built-in colour themes.

- [#309](https://github.com/ClementTsang/bottom/pull/309): Add a `mem_as_value` flag to default displaying process
  memory as value rather than percentage.

### Changes

- [#213](https://github.com/ClementTsang/bottom/pull/213), [#214](https://github.com/ClementTsang/bottom/pull/214):
  Updated help descriptions, added auto-complete generation.

- [#296](https://github.com/ClementTsang/bottom/pull/296): Changed how we do battery theming. We now only set high,
  medium, and low colours, and we deal with the ratios.

### Bug Fixes

- [#211](https://github.com/ClementTsang/bottom/pull/211): Fix a bug where you could move down in the process widget
  even if the process widget search was closed.

- [#215](https://github.com/ClementTsang/bottom/pull/215): Add labels to Linux temperature values.

- [#224](https://github.com/ClementTsang/bottom/pull/224): Implements sorting by count. It previously did absolutely
  nothing.

- [#238](https://github.com/ClementTsang/bottom/pull/238): Fix being able to cause an index out-of-bounds by resizing
  to a smaller terminal _just_ after the program got the terminal size, but right before the terminal started drawing.

- [#238](https://github.com/ClementTsang/bottom/pull/238): Fixed not clearing screen before drawing, which caused issues
  for some environments.

- [#253](https://github.com/ClementTsang/bottom/pull/253): Fix highlighted entries being stuck in another colour when
  the widget is not selected.

- [#253](https://github.com/ClementTsang/bottom/pull/253), [#266](https://github.com/ClementTsang/bottom/pull/266):
  Expanding a widget no longer overrides the widget/dialog title colour.

- [#261](https://github.com/ClementTsang/bottom/pull/261): Fixed process names occasionally showing up as truncated, due
  to only using `/proc/<PID>/stat` as our data source.

- [#262](https://github.com/ClementTsang/bottom/pull/262): Fixed missing thread termination steps as well as improper
  polling causing blocking in input thread.

- [#289](https://github.com/ClementTsang/bottom/pull/289): Fixed the CPU basic widget showing incorrect data due to an
  incorrect offset when displaying the data.

- [#290](https://github.com/ClementTsang/bottom/pull/290): Fixed an incorrect offset affecting the CPU colour when
  scrolling.

- [#291](https://github.com/ClementTsang/bottom/pull/291): Fixed spacing problems in basic CPU mode.

- [#296](https://github.com/ClementTsang/bottom/pull/296): Fixed an incorrect offset affecting the graph CPU colour
  mismatching the legend.

- [#296](https://github.com/ClementTsang/bottom/pull/296): Removes an accidental extra comma in one of the headers in
  the disk widget.

- [#308](https://github.com/ClementTsang/bottom/pull/308): Removes the automatically generated CPU colours method.

## [0.4.7] - 2020-08-26

### Bug Fixes

- [#204](https://github.com/ClementTsang/bottom/pull/204): Fix searching by command name being broken.

## [0.4.6] - 2020-08-25

### Features

- [#179](https://github.com/ClementTsang/bottom/pull/179): Show full command/process path as an option.

- [#183](https://github.com/ClementTsang/bottom/pull/183): Added sorting capabilities to any column.

- [#188](https://github.com/ClementTsang/bottom/pull/188): Add (estimated) memory usage values, toggle this from percent
  to values for processes with `%`.

- [#196](https://github.com/ClementTsang/bottom/pull/196): Support searching processes by process state.

- Added `WASD` as an alternative widget movement system.

- [#198](https://github.com/ClementTsang/bottom/pull/198): Allow `e` to also escape expanded mode.

### Changes

- [#181](https://github.com/ClementTsang/bottom/pull/181): Changed to just support stable (and newer) Rust, due to
  library incompatibilities.

- [#182](https://github.com/ClementTsang/bottom/pull/182): For macOS, support `$HOME/Library/Application Support`
  instead of `$HOME/.config` for config files. For backwards compatibility's sake, for macOS, this will still check
  `.config` if it exists first, but otherwise, it will default to the new location.

### Bug Fixes

- [#183](https://github.com/ClementTsang/bottom/pull/183): Fixed bug in basic mode where the battery widget was placed
  incorrectly.

- [#186](https://github.com/ClementTsang/bottom/pull/186): Fixed a bug caused by hitting `Enter` when a process kill
  fails, breaking future process kills.

- [#187](https://github.com/ClementTsang/bottom/pull/187): Fix bug caused by incorrectly reading the `/proc/{pid}/stats`
  file.

## [0.4.5] - 2020-07-08

- No changes in this update, just an uptick for Crates.io using the wrong Cargo.lock.

## [0.4.4] - 2020-07-06

### Features

- [#114](https://github.com/ClementTsang/bottom/pull/114): Show process state per process (originally in 0.4.0, moved to
  later). This only shows if the processes are not merged together; I couldn't think of a nice way to show it when
  grouped together, unfortunately.

### Changes

- [#156](https://github.com/ClementTsang/bottom/issues/156) - Removal of the `/` CPU core showing in the chart. It felt
  clunky to use, was not really useful, and hard to work with large core counts.

  Furthermore:

  - `show_disabled_data` option and flag is removed.

  - Average CPU is now on by _default_. You can disable it via `-a, --hide_avg_cpu` or `hide_avg_cpu = true`.

  - Make highlighted CPU persist even if widget is not selected - this should help make it easier to know what CPU you
      are looking at even if you aren't currently on the CPU widget.

### Bug Fixes

- [#164](https://github.com/ClementTsang/bottom/issues/164) - Fixed a bug where bottom would incorrectly read the wrong
  values to calculate the read/write columns for processes in Linux.

- [#165](https://github.com/ClementTsang/bottom/issues/165) - Fixed a bug where OR operations in the process query
  wouldn't properly for some cases.

- The process query should hopefully be a bit more usable now. There were issues with how spaces (which are treated as
  an AND if it was between keywords, so something like `btm cpu > 0 mem > 0` would look for a process named `btm` with
  cpu usage > 0 and mem usage > 0). This has been hopefully improved.

## [0.4.3] - 2020-05-15

### Other

- Update sysinfo version that fixes an overflow issue.

## [0.4.2] - 2020-05-11

### Changes

- Automatically hide time axis labels if the widget gets too small.

- Automatically hide table gap if the widget gets too small.

### Bug Fixes

- The `<Space>` character can be used as an "AND" again (properly) in queries. For example:

```bash
(btm cpu > 0) (discord mem > 0)
```

is equivalent to:

```bash
(btm AND cpu > 0) AND (discord AND mem > 0)
```

- [#151](https://github.com/ClementTsang/bottom/issues/151) - Fixed an issue where if the drive I/O label didn't match
  any disk, the entire disk widget would display nothing.

- Display SWAP and MEM legends even if the total amount is 0 to avoid a weird blank spot in the legend.

## [0.4.1] - 2020-05-05

### Bug Fixes

- [#146](https://github.com/ClementTsang/bottom/pull/146): Fixed a typo in the help menu (credit
  to [HarHarLinks](https://github.com/HarHarLinks)).

## [0.4.0] - 2020-05-04

### Features

- [#58](https://github.com/ClementTsang/bottom/issues/58): I/O stats per process.

- [#55](https://github.com/ClementTsang/bottom/issues/55): Battery monitoring widget.

- [#134](https://github.com/ClementTsang/bottom/pull/134): `hjkl` movement to delete dialog (credit
  to [andys8](https://github.com/andys8)).

- [#59](https://github.com/ClementTsang/bottom/issues/59): `Alt-h` and `Alt-l` to move left/right in query (and rest of
  the app actually).

- [#59](https://github.com/ClementTsang/bottom/issues/59): Added a more advanced querying system.

### Changes

- Changed default colours for highlighted borders and table headers to light blue - this is mostly to deal with
  Powershell colour conflicts.

- Updated the widget type keyword list to accept the following keywords as existing types:

  - `"memory"`
  - `"network"`
  - `"process"`
  - `"processes"`
  - `"temperature"`

- [#117](https://github.com/ClementTsang/bottom/issues/117): Update tui to 0.9:

  - Removed an (undocumented) feature in allowing modifying total RX/TX colours. This is mainly due to the legend
      change.

  - Use custom legend-hiding to stop hiding legends for memory and network widgets.

  - In addition, changed to using only legends within the graph for network, as well as redesigned the legend.
      The old legend style can still be used via the `--use_old_network_legend` flag or `use_old_network_legend = true`
      config option.

  - Allow for option to hide the header gap on tables via `--hide_table_gap` or `hide_table_gap = true`.

- [#126](https://github.com/ClementTsang/bottom/pull/126): Updated error messages to be a bit more consistent/helpful.

- [#70](https://github.com/ClementTsang/bottom/issues/70): Redesigned help menu to allow for scrolling.

- [#59](https://github.com/ClementTsang/bottom/issues/59): Moved maximization key to `e`, renamed feature to _expanding_
  the widget. Done to allow for the `<Enter>` key to be used later for a more intuitive usage.

### Bug Fixes

- Fixed `dd` not working on non-first entries.

- Fixed bug where a single empty row as a layout would crash without a proper warning.
  The behaviour now errors out with a more helpful message.

- Fixed bug where empty widgets in layout would cause widget movement to not work properly when moving vertically.

### Internal changes

- [#38](https://github.com/ClementTsang/bottom/issues/38): Updated arg tests and added config testing.

- Add MSRV, starting with 1.40.0.

## [0.3.0] - 2020-04-07

### Features

- [#20](https://github.com/ClementTsang/bottom/issues/20): Time scaling was added to allow users to zoom in/out based on
  their desired time intervals. Time markers on the charts can be hidden or automatically hidden.

- [#37](https://github.com/ClementTsang/bottom/issues/37): Automatically populate a config file if one does not exist.

- [#21](https://github.com/ClementTsang/bottom/issues/21): Basic mode added.

- [#51](https://github.com/ClementTsang/bottom/issues/51): Modularity with widget placement or inclusion added.

### Changes

- Removed redundant dependencies.

- [#17](https://github.com/ClementTsang/bottom/issues/17): Add colouring options to the total RX/TX labels.

- [#29](https://github.com/ClementTsang/bottom/issues/29): Added `F1-F3` keys as alternatives for selecting search
  options

- [#42](https://github.com/ClementTsang/bottom/issues/42), [#45](https://github.com/ClementTsang/bottom/issues/45), [#35](https://github.com/ClementTsang/bottom/issues/35):
  Change the arrow used for sorting processes to work with other terminals.

- [#61](https://github.com/ClementTsang/bottom/issues/61): Search box changed to not block if the window is small.

- [#40](https://github.com/ClementTsang/bottom/issues/40): Rewrote README to be more clear and explicit.

- [#109](https://github.com/ClementTsang/bottom/issues/109): Sorting processes by name is case-insensitive.

### Bug Fixes

- [#33](https://github.com/ClementTsang/bottom/issues/33): Fix bug with search and graphemes bigger than a byte crashing
  due to the cursor.

- [#41](https://github.com/ClementTsang/bottom/issues/41): Fix bug that caused the cursor to go off-screen while
  searching.

- [#61](https://github.com/ClementTsang/bottom/issues/61): Dialog boxes set to be a constant width/height.

- [#80](https://github.com/ClementTsang/bottom/issues/80): Fix bug with resizing and scrolling causing issues with
  tables.

- [#77](https://github.com/ClementTsang/bottom/issues/77): Fixed hidden CPU entries from being scrolled to.

- [#79](https://github.com/ClementTsang/bottom/issues/79): Fixed CPU entries being a different colour if the one above
  it was hidden.

- [#85](https://github.com/ClementTsang/bottom/pull/85): A div-by-zero error when the memory values were zero was fixed.

### Other

- Various Travis changes.

- Scoop install option added.

## [0.2.2] - 2020-02-26

### Features

- Added support for colouring the average CPU core separately in config files.

- [#15](https://github.com/ClementTsang/bottom/issues/15) - Added support for (some) named colours and RGB values in
  config files.

### Bug Fixes

- [#28](https://github.com/ClementTsang/bottom/issues/30): Fixed broken Cargo.toml for Cargo installs.

- Fixed Windows issue with shift key.

- [#14](https://github.com/ClementTsang/bottom/issues/14): Ignore certain characters in search

## [0.2.1] - 2020-02-21

### Bug Fixes

- [#14](https://github.com/ClementTsang/bottom/issues/11): Fixed default config paths not being read properly.

## [0.2.0] - 2020-02-20

### Features

- Searching in processes was added.

- The option of a config file was added. Config files follow the TOML spec. These support boot flags by default, and
  colour schemes.

- The capability of maximizing a widget to take up all draw space was added.

- Filtering out CPU cores on the graph/legend was added.

### Changes

- Default colours were changed for better support on macOS Terminal and PowerShell.

- Rewrote and refactored how I get data to be less spaghetti. This might also have the added benefit of running better,
  with less duplicated logic.

- Changed how the dd dialog and help dialog look. Hopefully they'll be nicer to look at and more intuitive to use!

### Bug Fixes

- [#2](https://github.com/ClementTsang/bottom/issues/2): Fixed issues where the program would crash if the window was
  too small.

- Added a panic handler so terminals won't get all broken if a panic _does_ still occur.

- Fixed some sizing issues, hopefully this means that it's still readable at smaller sizes (within reason).

- [#10](https://github.com/ClementTsang/bottom/issues/10): Fixed scroll issue caused by resizing.

## [0.1.2] - 2020-01-11

### Changes

- Added a bit more complexity to how we determine column widths for tables. This should fix an issue where columns would
  glitch out at smaller widths, and hopefully look nicer.

### Bug Fixes

- Rewrote scroll logic in tables to avoid some strange scroll behaviour I encountered where it would jump around.

- Attempt to patch a panic caused by the change in how we determine time in the data collection stage.

## [0.1.1] - 2020-01-11

### Features

- `Tab` in the processes widget will now group similarly-named processes together (as well as their total CPU and MEM
  usage). `dd`-ing this will try to kill all entries with that process name.

- A flag to enable this by default is also now available.

### Bug Fixes

- Accidentally left in a bug in which the disk widget was using megabytes instead of bytes as their unit during data
  collection... but during data conversion for the display I treated them as bytes.

## [0.1.0] - 2020-01-11

Initial release.


================================================
FILE: CONTRIBUTING.md
================================================
# Contribution

Contribution in any way is appreciated, whether it is reporting problems, fixing bugs, implementing features, improving the documentation, etc.

## Opening an issue

### Bug reports

When filing a bug report, fill out the [bug report template](https://github.com/ClementTsang/bottom/issues/new?assignees=&labels=bug&template=bug_report.yml). Be sure to give all the necessary details! It is _incredibly_ difficult for a maintainer to fix a bug when it cannot be reproduced,
so that makes it much easier to reproduce the problem!

### Feature requests

Please fill out the [feature request template](https://github.com/ClementTsang/bottom/issues/new?assignees=&labels=feature&template=feature_request.yml). Remember to give details about what the feature is along with why you think this suggestion will be useful.

## Pull requests

If you want to directly contribute documentation changes or code, follow this! The expected workflow for a pull request is:

1. Fork the project.
2. Make your changes.
3. Make any documentation changes if necessary - if you add a new feature, it'll probably need documentation changes. See [here](https://bottom.pages.dev/nightly/contribution/documentation/) for tips on documentation.
4. Commit and create a pull request to merge into the `main` branch. **Please fill out the pull request template**.
5. Ask a maintainer to review your pull request.
   - Check if the CI workflow passes. These consist of clippy lints, rustfmt checks, and basic tests. If you are a
     first-time contributor, you may need to wait for a maintainer to let CI run.
   - If changes are suggested or any comments are made, they should probably be addressed.
6. Once it looks good, it'll be merged! Note that _generally_, PRs are squashed to maintain repo cleanliness, though
   feel free to ask otherwise if that isn't preferable.

For more details, see [here](https://bottom.pages.dev/nightly/contribution/issues-and-pull-requests/).

### Documentation

For contributing to documentation, see [here](https://bottom.pages.dev/nightly/contribution/documentation/).

### Packaging

If you want to become a package maintainer, see [here](https://bottom.pages.dev/nightly/contribution/packaging-and-distribution/)
for details on how to build bottom, how to generate/obtain completion files and manpages, and how to add installation instructions for the package to the README.


================================================
FILE: Cargo.toml
================================================
[package]
name = "bottom"
version = "0.12.3"
repository = "https://github.com/ClementTsang/bottom"
license = "MIT"
description = "A customizable cross-platform graphical process/system monitor for the terminal. Supports Linux, macOS, and Windows."
documentation = "https://bottom.pages.dev/stable"
readme = "README.md"
default-run = "btm"
build = "build.rs"
authors = ["Clement Tsang <cjhtsang@uwaterloo.ca>"]
keywords = ["cross-platform", "monitoring", "cli", "top", "tui"]
categories = ["command-line-utilities", "visualization"]
exclude = [
    ".cargo-husky/",
    ".github/",
    ".idea/",
    ".vscode/",
    "assets/",
    "desktop/",
    "docs/",
    "flamegraphs/",
    "sample_configs/",
    "schema/",
    "scripts/",
    "wix/",
    ".all-contributorsrc",
    ".cirrus.yml",
    ".gitignore",
    ".markdownlint.json",
    "CHANGELOG.md",
    "clippy.toml",
    "codecov.yml",
    "CONTRIBUTING.md",
    "Cross.toml",
    "debug.log",
    "flamegraph.svg",
    "profile.json.gz",
    "rustfmt.toml",
]
edition = "2024"
# The oldest version I've tested that should still build - note this is not an official MSRV!
rust-version = "1.85"

[lib]
test = true
doctest = true
doc = true

[[bin]]
name = "btm"
path = "src/bin/main.rs"
doc = false

[[bin]]
name = "schema"
path = "src/bin/schema.rs"
test = false
doctest = false
doc = false
required-features = ["generate_schema"]

[features]
# Used for general builds.
battery = ["starship-battery"]
nvidia = ["nvml-wrapper"]
gpu = ["nvidia"]
zfs = []
deploy = ["battery", "gpu", "zfs"]
default = ["deploy"]

# Should not be included in builds.
logging = ["fern", "log", "time"]
generate_schema = ["schemars", "serde_json", "strum"]

[dependencies]
anyhow = "1.0.101"
cfg-if = "1.0.4"
clap = { version = "4.5.57", features = ["default", "cargo", "wrap_help", "derive"] }
concat-string = "1.0.1"
crossterm = "0.29.0"
ctrlc = { version = "3.5.0", features = ["termination"] }
dirs = "6.0.0"
humantime = "2.3.0"
indexmap = "2.13.0"
indoc = "2.0.7"
itertools = "0.14.0"
nohash = "0.2.0"
nvml-wrapper = { version = "0.11.0", optional = true, features = ["legacy-functions"] }
ratatui-core = "0.1.0"
regex = "1.12.3"
rustc-hash = "2.1.1"
serde = { version = "1.0.228", features = ["derive"] }
starship-battery = { version = "0.10.3", optional = true }
sysinfo = "=0.38.0"
timeless = "0.0.14-alpha"
toml_edit = { version = "0.24.0", features = ["serde"] }
tui = { version = "0.30.0", package = "ratatui", features = [
    "unstable-rendered-line-info",
    "layout-cache",
    "crossterm",
] }
unicode-ellipsis = "0.3.0"
unicode-segmentation = "1.12.0"
unicode-width = "0.2.2"

# Used for logging. Mostly a debugging tool.
fern = { version = "0.7.1", optional = true }
log = { version = "0.4.29", optional = true }
time = { version = "0.3.47", features = ["local-offset", "formatting", "macros"], optional = true }

# These are just used for JSON schema generation.
schemars = { version = "1.2.1", optional = true }
serde_json = { version = "1.0.149", optional = true }
strum = { version = "0.27.2", features = ["derive"], optional = true }

[target.'cfg(unix)'.dependencies]
libc = "0.2.180"

[target.'cfg(target_os = "linux")'.dependencies]
rustix = { version = "1.1.2", features = ["fs", "param"] }

[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.10.1"
mach2 = "0.6.0"

[target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.62.2", features = [
    "Win32_Foundation",
    "Win32_Security",
    "Win32_Storage_FileSystem",
    "Win32_System_IO",
    "Win32_System_Ioctl",
    "Win32_System_Performance",
    "Win32_System_ProcessStatus",
    "Win32_System_Threading",
] }

[target.'cfg(target_os = "freebsd")'.dependencies]
serde_json = { version = "1.0.145" }
sysctl = { version = "0.7.1" }
filedescriptor = "0.8.3"

[dev-dependencies]
assert_cmd = "2.1.2"
predicates = "3.1.3"
tempfile = { version = "3.23.0", default-features = false }

[target.'cfg(all(target_arch = "x86_64", target_os = "linux"))'.dev-dependencies]
portable-pty = "0.9.0"

[build-dependencies]
clap = { version = "4.5.57", features = ["default", "cargo", "wrap_help", "derive"] }
clap_complete = "4.5.62"
clap_complete_nushell = "4.5.10"
clap_complete_fig = "4.5.2"
clap_mangen = "0.2.31"
indoc = "2.0.7"

# Compile dependencies with optimizations enabled, even in debug mode.
[profile.dev.package."*"]
opt-level = 3

[profile.release]
debug = 0
strip = "symbols"
lto = true
opt-level = 3
codegen-units = 1

[profile.profiling]
inherits = "release"
debug = true
strip = false

[package.metadata.deb]
section = "utility"
assets = [
    [
        "target/release/btm",
        "usr/bin/",
        "755",
    ],
    [
        "LICENSE",
        "usr/share/doc/btm/",
        "644",
    ],
    [
        "manpage/btm.1.gz",
        "usr/share/man/man1/btm.1.gz",
        "644",
    ],
    [
        "completion/btm.bash",
        "usr/share/bash-completion/completions/btm",
        "644",
    ],
    [
        "completion/btm.fish",
        "usr/share/fish/vendor_completions.d/btm.fish",
        "644",
    ],
    [
        "completion/_btm",
        "usr/share/zsh/vendor-completions/",
        "644",
    ],
    [
        "desktop/bottom.desktop",
        "usr/share/applications/bottom.desktop",
        "644",
    ],
    [
        "assets/icons/bottom-system-monitor.svg",
        "/usr/share/icons/hicolor/scalable/apps/bottom-system-monitor.svg",
        "644",
    ],
]
conflicts = "btm"
extended-description = """

By default, bottom will look for a config file in ~/.config/bottom/bottom.toml. A config file can be specified \
using `-C`. If a config file does not exist at the specified or default location, a default one will be created \
for the user there.
"""

[package.metadata.deb.variants.arm64]
depends = "libc6:arm64 (>= 2.28)"

[package.metadata.deb.variants.armhf]
depends = "libc6:armhf (>= 2.28)"

[package.metadata.wix]
output = "bottom_installer.msi"
product-icon = "assets/icons/bottom.ico"

[package.metadata.generate-rpm]
assets = [
    { source = "target/release/btm", dest = "/usr/bin/", mode = "755" },
    { source = "LICENSE", dest = "/usr/share/doc/btm/", mode = "644" },
    { source = "manpage/btm.1.gz", dest = "/usr/share/man/man1/btm.1.gz", mode = "644", doc = true },
    { source = "completion/btm.bash", dest = "/usr/share/bash-completion/completions/btm", mode = "644" },
    { source = "completion/btm.fish", dest = "/usr/share/fish/vendor_completions.d/btm.fish", mode = "644" },
    { source = "completion/_btm", dest = "/usr/share/zsh/vendor-completions/", mode = "644" },
    { source = "desktop/bottom.desktop", dest = "/usr/share/applications/bottom.desktop", mode = "644" },
    { source = "assets/icons/bottom-system-monitor.svg", dest = "/usr/share/icons/hicolor/scalable/apps/bottom-system-monitor.svg", mode = "644" },
]

[lints.rust]
rust_2018_idioms = "deny"
# missing_docs = "deny"

[lints.rustdoc]
broken_intra_doc_links = "deny"
private_intra_doc_links = "deny"
missing_crate_level_docs = "deny"

[lints.clippy]
todo = "deny"
unimplemented = "deny"
missing_safety_doc = "deny"
unwrap_used = "deny"


================================================
FILE: Cross.toml
================================================
[build.env]
passthrough = ["RUST_BACKTRACE", "BTM_GENERATE"]

[target.x86_64-unknown-netbsd]
pre-build = [
    "apt-get update && apt-get install -y --no-install-recommends curl xz-utils && td=$(mktemp -d) && mkdir -p \"$td/netbsd\" && curl -4 --retry 3 -sSfL 'http://ftp.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/base.tar.xz' | tar -C \"$td/netbsd\" -xJ ./usr/lib ./lib && curl -4 --retry 3 -sSfL 'http://ftp.netbsd.org/pub/NetBSD/NetBSD-9.3/amd64/binary/sets/comp.tar.xz' | tar -C \"$td/netbsd\" -xJ ./usr/lib && cp \"$td\"/netbsd/usr/lib/libkvm* /usr/local/x86_64-unknown-netbsd/lib/ && rm -rf \"$td\"",
]


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Clement Tsang

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<div align="center">
  <h1>bottom (btm)</h1>

  <p>
    A customizable cross-platform graphical process/system monitor for the terminal.<br />Supports Linux, macOS, and Windows. Inspired by <a href=https://github.com/aksakalli/gtop>gtop</a>, <a href=https://github.com/xxxserxxx/gotop>gotop</a>, and <a href=https://github.com/htop-dev/htop>htop</a>.
  </p>

[<img src="https://img.shields.io/github/checks-status/ClementTsang/bottom/main?style=flat-square&logo=github" alt="CI status">](https://github.com/ClementTsang/bottom/actions?query=branch%3Amain)
[<img src="https://img.shields.io/crates/v/bottom.svg?style=flat-square" alt="crates.io link">](https://crates.io/crates/bottom)
[<img src="https://img.shields.io/badge/docs-stable-66c2a5?style=flat-square&labelColor=555555&logoColor=white" alt="Stable documentation">](https://bottom.pages.dev/stable)
[<img src="https://img.shields.io/badge/docs-nightly-88c0d0?style=flat-square&labelColor=555555&logoColor=white" alt="Nightly documentation">](https://bottom.pages.dev/nightly)
[<img src="https://img.shields.io/badge/docs-mirror-8A2BE2?style=flat-square&labelColor=555555&logoColor=white" alt="Doc mirror on GitHub Pages">](https://clementtsang.github.io/bottom/stable)

</div>

<div align="center">
  <img src="assets/demo.gif" alt="Quick demo recording showing off bottom's searching, expanding, and process killing."/>
  <p>
    <sub>
      Demo using the <a href="https://github.com/morhetz/gruvbox">Gruvbox</a> theme (<code>--theme gruvbox</code>), along with <a href="https://www.ibm.com/plex/">IBM Plex Mono</a> and <a href="https://sw.kovidgoyal.net/kitty/">Kitty</a>
    </sub>
  </p>
</div>

## Table of contents <!-- omit in toc -->

- [Features](#features)
- [Support](#support)
  - [Official](#official)
  - [Unofficial](#unofficial)
- [Installation](#installation)
  - [Cargo](#cargo)
  - [Alpine](#alpine)
  - [Arch Linux](#arch-linux)
  - [Debian / Ubuntu](#debian--ubuntu)
  - [Exherbo Linux](#exherbo-linux)
  - [Fedora / CentOS / AlmaLinux / Rocky Linux](#fedora--centos--almalinux--rocky-linux)
    - [COPR](#copr)
    - [Terra](#terra)
    - [RPM](#rpm)
  - [Gentoo](#gentoo)
  - [Nix](#nix)
  - [openSUSE](#opensuse)
  - [Snap](#snap)
  - [Solus](#solus)
  - [Void](#void)
  - [gah](#gah)
  - [Homebrew](#homebrew)
  - [MacPorts](#macports)
  - [Chocolatey](#chocolatey)
  - [Scoop](#scoop)
  - [winget](#winget)
  - [Windows installer](#windows-installer)
  - [Conda](#conda)
  - [mise](#mise)
  - [Pre-built binaries](#pre-built-binaries)
    - [Auto-completion](#auto-completion)
- [Usage](#usage)
- [Configuration](#configuration)
- [Troubleshooting](#troubleshooting)
- [Documentation](#documentation)
- [Contribution](#contribution)
  - [Contributors](#contributors)
- [Thanks](#thanks)

## Features

As (yet another) process/system visualization and management application, bottom supports the typical features:

- Graphical visualization widgets for:

  - [CPU usage](https://bottom.pages.dev/nightly/usage/widgets/cpu/) over time, at an average and per-core level
  - [RAM and swap usage](https://bottom.pages.dev/nightly/usage/widgets/memory/) over time
  - [Network I/O usage](https://bottom.pages.dev/nightly/usage/widgets/network/) over time

  with support for zooming in/out the current time interval displayed.

- Widgets for displaying info about:

  - [Disk capacity/usage](https://bottom.pages.dev/nightly/usage/widgets/disk/)
  - [Temperature sensors](https://bottom.pages.dev/nightly/usage/widgets/temperature/)
  - [Battery usage](https://bottom.pages.dev/nightly/usage/widgets/battery/)

- [A process widget](https://bottom.pages.dev/nightly/usage/widgets/process/) for displaying, sorting, and searching info about processes, as well as support for:

  - [Kill signals](https://bottom.pages.dev/nightly/usage/widgets/process/#process-termination)
  - [Tree mode](https://bottom.pages.dev/nightly/usage/widgets/process/#tree-mode)

- [Cross-platform support](https://github.com/ClementTsang/bottom#support) for Linux, macOS, and Windows, with more planned in the future.

- [Customizable behaviour](https://bottom.pages.dev/nightly/configuration/command-line-options/) that can be controlled with command-line options or a config file, such as:

  - Custom and built-in colour themes
  - Customizing widget behaviour
  - Changing the layout of widgets
  - Filtering out entries in some widgets

- And more:

  - [An htop-inspired basic mode](https://bottom.pages.dev/nightly/usage/basic-mode/)
  - [Expansion, which focuses on just one widget](https://bottom.pages.dev/nightly/usage/general-usage/#expansion)

- And more!

You can find more details in [the documentation](https://bottom.pages.dev/nightly/usage/general-usage/).

## Support

### Official

bottom _officially_ supports the following operating systems and corresponding architectures:

- macOS (`x86_64`, `aarch64`)
- Linux (`x86_64`, `i686`, `aarch64`)
- Windows (`x86_64`, `i686`)

These platforms are tested to work for the most part and issues on these platforms will be fixed if possible.
Furthermore, binaries are built and tested using the most recent version of stable Rust at the time.

For more details on supported platforms and known problems, check out [the documentation](https://bottom.pages.dev/nightly/support/official/).

### Unofficial

bottom may work on a number of platforms that aren't officially supported. Note that unsupported platforms:

- Might not be tested in CI to build or pass tests (see [here](./.github/workflows/ci.yml) for checked platforms).
- Might not be properly tested by maintainers prior to a stable release.
- May only receive limited support, such as missing features or bugs that may not be fixed.

Note that some unsupported platforms may eventually be officially supported (e.g., FreeBSD).

A non-comprehensive list of some currently unofficially-supported platforms that may compile/work include:

- FreeBSD (`x86_64`)
- Linux (`armv6`, `armv7`, `powerpc64le`, `riscv64gc`, `loongarch64`)
- Android (`arm64`)
- Windows (`arm64`)

For more details on unsupported platforms and known problems, check out [the documentation](https://bottom.pages.dev/nightly/support/unofficial/).

## Installation

### Cargo

Installation via `cargo` can be done by installing the [`bottom`](https://crates.io/crates/bottom) crate:

```bash
# You might need to update the stable version of Rust first.
# Other versions might work, but this is not guaranteed.
rustup update stable

# Install the binary from crates.io.
cargo install bottom --locked

# If you use another channel by default, you can specify
# the what channel to use like so:
cargo +stable install bottom --locked

# --locked may be omitted if you wish to not use the
# locked crate versions in Cargo.lock. However, be
# aware that this may cause problems with dependencies.
cargo install bottom
```

Alternatively, you can use `cargo install` using the repo as the source.

```bash
# You might need to update the stable version of Rust first.
# Other versions might work, but this is not guaranteed.
rustup update stable

# Option 1 - Download an archive from releases and install
curl -LO https://github.com/ClementTsang/bottom/archive/0.12.3.tar.gz
tar -xzvf 0.12.3.tar.gz
cargo install --path . --locked

# Option 2 - Manually clone the repo and install
git clone https://github.com/ClementTsang/bottom
cd bottom
cargo install --path . --locked

# Option 3 - Install using cargo with the repo as the source
cargo install --git https://github.com/ClementTsang/bottom --locked

# You can also pass in the target-cpu=native flag to try to
# use better CPU-specific optimizations. For example:
RUSTFLAGS="-C target-cpu=native" cargo install --path . --locked
```

### Alpine

bottom is available as a [package](https://pkgs.alpinelinux.org/packages?name=bottom&branch=edge&repo=&arch=&origin=&flagged=&maintainer=) for Alpine Linux via `apk`:

```bash
apk add bottom
```

Packages for documentation ([`bottom-doc`](https://pkgs.alpinelinux.org/packages?name=bottom-doc&branch=edge&repo=&arch=&origin=&flagged=&maintainer=)) and completions for Bash ([`bottom-bash-completion`](https://pkgs.alpinelinux.org/packages?name=bottom-bash-completion&branch=edge&repo=&arch=&origin=&flagged=&maintainer=)), Fish ([`bottom-fish-completion`](https://pkgs.alpinelinux.org/packages?name=bottom-fish-completion&branch=edge&repo=&arch=&origin=&flagged=&maintainer=)), and Zsh ([`bottom-zsh-completion`](https://pkgs.alpinelinux.org/packages?name=bottom-zsh-completion&branch=edge&repo=&arch=&origin=&flagged=&maintainer=)) are also available.

### Arch Linux

bottom is available as an [official package](https://archlinux.org/packages/extra/x86_64/bottom/) that can be installed with `pacman`:

```bash
sudo pacman -S bottom
```

If you want the latest changes that are not yet stable, you can also install `bottom-git` [from the AUR](https://aur.archlinux.org/packages/bottom-git):

```bash
# Using paru
paru -S bottom-git

# Using yay
yay -S bottom-git
```

### Debian / Ubuntu

A `.deb` file is provided on each [stable release](https://github.com/ClementTsang/bottom/releases/latest) and
[nightly builds](https://bottom.pages.dev/nightly/nightly-release) for x86, aarch64, and armv7.
Some examples of installing it this way:

```bash
# x86-64
curl -LO https://github.com/ClementTsang/bottom/releases/download/0.12.3/bottom_0.12.3-1_amd64.deb
sudo dpkg -i bottom_0.12.3-1_amd64.deb

# ARM64
curl -LO https://github.com/ClementTsang/bottom/releases/download/0.12.3/bottom_0.12.3-1_arm64.deb
sudo dpkg -i bottom_0.12.3-1_arm64.deb

# ARM
curl -LO https://github.com/ClementTsang/bottom/releases/download/0.12.3/bottom_0.12.3-1_armhf.deb
sudo dpkg -i bottom_0.12.3-1_armhf.deb

# musl-based
curl -LO https://github.com/ClementTsang/bottom/releases/download/0.12.3/bottom-musl_0.12.3-1_amd64.deb
sudo dpkg -i bottom-musl_0.12.3-1_amd64.deb
```

### Exherbo Linux

bottom is available as a [rust package](https://gitlab.exherbo.org/exherbo/rust/-/tree/master/packages/sys-process/bottom) that can be installed with `cave`:

```bash
cave resolve -x repository/rust
cave resolve -x bottom
```

### Fedora / CentOS / AlmaLinux / Rocky Linux

#### COPR

> [!WARNING]
>
> `atim/bottom` seems to be unmaintained and may be outdated ([relevant issue](https://github.com/ClementTsang/bottom/issues/1904))

bottom is available on [COPR](https://copr.fedorainfracloud.org/coprs/atim/bottom/):

```bash
sudo dnf copr enable atim/bottom -y
sudo dnf install bottom
```

#### Terra

bottom is also available via [Terra](https://terra.fyralabs.com/):

```bash
sudo dnf install --repofrompath 'terra,https://repos.fyralabs.com/terra$releasever' --setopt='terra.gpgkey=https://repos.fyralabs.com/terra$releasever/key.asc' terra-release
sudo dnf install bottom
```

#### RPM

`.rpm` files are also generated for x86 in the [releases](https://github.com/ClementTsang/bottom/releases) page.
For example:

```bash
curl -LO https://github.com/ClementTsang/bottom/releases/download/0.12.3/bottom-0.12.3-1.x86_64.rpm
sudo dnf install ./bottom-0.12.3-1.x86_64.rpm
```

### Gentoo

Available in the [official Gentoo repo](https://packages.gentoo.org/packages/sys-process/bottom):

```bash
sudo emerge --ask sys-process/bottom
```

### Nix

Available [in Nixpkgs](https://search.nixos.org/packages?channel=unstable&show=bottom&from=0&size=1&sort=relevance&type=packages) as `bottom`:

```bash
nix profile install nixpkgs#bottom
```

`bottom` can also be installed and configured through the [home-manager](https://nix-community.github.io/home-manager) module:

```nix
{
  programs.bottom.enable = true;
}
```

### openSUSE

Available in openSUSE Tumbleweed:

```bash
zypper in bottom
```

### Snap

bottom is available as a [snap](https://snapcraft.io/install/bottom/ubuntu):

```bash
sudo snap install bottom

# To allow the program to run as intended
sudo snap connect bottom:mount-observe
sudo snap connect bottom:hardware-observe
sudo snap connect bottom:system-observe
sudo snap connect bottom:process-control
```

### Solus

Available [in the Solus repos](https://dev.getsol.us/source/bottom/):

```bash
sudo eopkg it bottom
```

### Void

Available [in the void-packages repo](https://github.com/void-linux/void-packages/tree/master/srcpkgs/bottom):

```bash
sudo xbps-install bottom
```

### gah

bottom can also be installed on Linux or macOS using [gah](https://github.com/marverix/gah):

```bash
gah install bottom
```

### Homebrew

The formula is available [here](https://formulae.brew.sh/formula/bottom):

```bash
brew install bottom
```

### MacPorts

Available [here](https://ports.macports.org/port/bottom/):

```bash
sudo port selfupdate
sudo port install bottom
```

### Chocolatey

Chocolatey packages are located [here](https://chocolatey.org/packages/bottom):

```bash
choco install bottom
```

### Scoop

Available in the [Main bucket](https://github.com/ScoopInstaller/Main):

```bash
scoop install bottom
```

### winget

The winget package can be found [here](https://github.com/microsoft/winget-pkgs/tree/master/manifests/c/Clement/bottom):

```bash
winget install bottom

# If you need a more specific app id:
winget install Clement.bottom
```

You can uninstall via Control Panel, Options, or `winget --uninstall bottom`.

### Windows installer

You can manually install bottom as a Windows program by downloading and using the `.msi` file from the [latest release](https://github.com/ClementTsang/bottom/releases/latest).

### Conda

You can install bottom using `conda` with [this conda-smithy repository](https://github.com/conda-forge/bottom-feedstock):

```bash
# Add the channel
conda config --add channels conda-forge
conda config --set channel_priority strict

# Install
conda install bottom
```

### mise

bottom is available in [mise](https://github.com/jdx/mise). You can install it like so:

```
mise use -g bottom@latest
```

### Pre-built binaries

You can also use the pre-built release binaries:

- [Latest stable release](https://github.com/ClementTsang/bottom/releases/latest)
- [Latest nightly release](https://bottom.pages.dev/nightly/nightly-release)

To use, download and extract the binary that matches your system. You can then run by doing:

```bash
./btm
```

or by installing to your system following the procedures for installing binaries to your system.

#### Auto-completion

The release binaries in [the releases page](https://github.com/ClementTsang/bottom/releases) are packaged with
shell auto-completion files for Bash, Zsh, fish, Powershell, Elvish, Fig, and Nushell. To install them:

- For Bash, move `btm.bash` to `$XDG_CONFIG_HOME/bash_completion or /etc/bash_completion.d/`.
- For Zsh, move `_btm` to one of your `$fpath` directories.
- For fish, move `btm.fish` to `$HOME/.config/fish/completions/`.
- For PowerShell, add `_btm.ps1` to your PowerShell [profile](<https://docs.microsoft.com/en-us/previous-versions//bb613488(v=vs.85)>).
- For Elvish, the completion file is `btm.elv`.
- For Fig, the completion file is `btm.ts`.
- For Nushell, source `btm.nu`.

The individual auto-completion files are also included in the stable/nightly releases as `completion.tar.gz` if needed.

## Usage

You can run bottom using `btm`.

- For help on flags, use `btm -h` for a quick overview or `btm --help` for more details.
- For info on key and mouse bindings, press `?` inside bottom or refer to the [documentation page](https://bottom.pages.dev/nightly/).

You can find more information on usage in the [documentation](https://bottom.pages.dev/nightly/).

## Configuration

bottom accepts a number of command-line arguments to change the behaviour of the application as desired.
Additionally, bottom will automatically generate a configuration file on the first launch, which can be changed.

More details on configuration can be found [in the documentation](https://bottom.pages.dev/nightly/configuration/config-file/).

## Troubleshooting

If some things aren't working, give the [troubleshooting page](https://bottom.pages.dev/nightly/troubleshooting)
a look. If things still aren't working, then consider asking [a question](https://github.com/ClementTsang/bottom/discussions)
or filing a [bug report](https://github.com/ClementTsang/bottom/issues/new/choose) if you think it's a bug.

## Documentation

The main documentation page can be found at <https://bottom.pages.dev>, using Cloudflare Pages. If needed, a mirror hosted using
Github Pages is also available at <https://clementtsang.github.io/bottom>.

## Contribution

Whether it's reporting bugs, suggesting features, maintaining packages, or submitting a PR, contribution is always welcome! Please read
[CONTRIBUTING.md](./CONTRIBUTING.md) for details on how to contribute to bottom.

### Contributors

Thanks to all contributors:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tbody>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="http://shilangyu.github.io"><img src="https://avatars3.githubusercontent.com/u/29288116?v=4?s=100" width="100px;" alt="Marcin Wojnarowski"/><br /><sub><b>Marcin Wojnarowski</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=shilangyu" title="Code">💻</a> <a href="#platform-shilangyu" title="Packaging/porting to new platform">📦</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://neosmart.net/"><img src="https://avatars3.githubusercontent.com/u/606923?v=4?s=100" width="100px;" alt="Mahmoud Al-Qudsi"/><br /><sub><b>Mahmoud Al-Qudsi</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=mqudsi" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://andys8.de"><img src="https://avatars0.githubusercontent.com/u/13085980?v=4?s=100" width="100px;" alt="Andy"/><br /><sub><b>Andy</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=andys8" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/HarHarLinks"><img src="https://avatars0.githubusercontent.com/u/2803622?v=4?s=100" width="100px;" alt="Kim Brose"/><br /><sub><b>Kim Brose</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=HarHarLinks" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://svenstaro.org"><img src="https://avatars0.githubusercontent.com/u/1664?v=4?s=100" width="100px;" alt="Sven-Hendrik Haase"/><br /><sub><b>Sven-Hendrik Haase</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=svenstaro" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://liberapay.com/Artem4/"><img src="https://avatars0.githubusercontent.com/u/5614476?v=4?s=100" width="100px;" alt="Artem Polishchuk"/><br /><sub><b>Artem Polishchuk</b></sub></a><br /><a href="#platform-tim77" title="Packaging/porting to new platform">📦</a> <a href="https://github.com/ClementTsang/bottom/commits?author=tim77" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://ruby-journal.com/"><img src="https://avatars2.githubusercontent.com/u/135605?v=4?s=100" width="100px;" alt="Trung Lê"/><br /><sub><b>Trung Lê</b></sub></a><br /><a href="#platform-runlevel5" title="Packaging/porting to new platform">📦</a> <a href="#infra-runlevel5" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/dm9pZCAq"><img src="https://avatars1.githubusercontent.com/u/46228973?v=4?s=100" width="100px;" alt="dm9pZCAq"/><br /><sub><b>dm9pZCAq</b></sub></a><br /><a href="#platform-dm9pZCAq" title="Packaging/porting to new platform">📦</a> <a href="https://github.com/ClementTsang/bottom/commits?author=dm9pZCAq" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://lukor.org"><img src="https://avatars2.githubusercontent.com/u/10536802?v=4?s=100" width="100px;" alt="Lukas Rysavy"/><br /><sub><b>Lukas Rysavy</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=LlinksRechts" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://hamberg.no/erlend"><img src="https://avatars3.githubusercontent.com/u/16063?v=4?s=100" width="100px;" alt="Erlend Hamberg"/><br /><sub><b>Erlend Hamberg</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=ehamberg" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://onee3.org"><img src="https://avatars.githubusercontent.com/u/4507647?v=4?s=100" width="100px;" alt="Frederick Zhang"/><br /><sub><b>Frederick Zhang</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=Frederick888" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/pvanheus"><img src="https://avatars.githubusercontent.com/u/4154788?v=4?s=100" width="100px;" alt="pvanheus"/><br /><sub><b>pvanheus</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=pvanheus" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/briandipalma"><img src="https://avatars.githubusercontent.com/u/1597820?v=4?s=100" width="100px;" alt="Brian Di Palma"/><br /><sub><b>Brian Di Palma</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=briandipalma" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://dakyskye.github.io"><img src="https://avatars.githubusercontent.com/u/32128756?v=4?s=100" width="100px;" alt="Lasha Kanteladze"/><br /><sub><b>Lasha Kanteladze</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=dakyskye" title="Documentation">📖</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/herbygillot"><img src="https://avatars.githubusercontent.com/u/618376?v=4?s=100" width="100px;" alt="Herby Gillot"/><br /><sub><b>Herby Gillot</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=herbygillot" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/yellowsquid"><img src="https://avatars.githubusercontent.com/u/46519298?v=4?s=100" width="100px;" alt="Greg Brown"/><br /><sub><b>Greg Brown</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=yellowsquid" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/TotalCaesar659"><img src="https://avatars.githubusercontent.com/u/14265316?v=4?s=100" width="100px;" alt="TotalCaesar659"/><br /><sub><b>TotalCaesar659</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=TotalCaesar659" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/grawlinson"><img src="https://avatars.githubusercontent.com/u/4408051?v=4?s=100" width="100px;" alt="George Rawlinson"/><br /><sub><b>George Rawlinson</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=grawlinson" title="Documentation">📖</a> <a href="#platform-grawlinson" title="Packaging/porting to new platform">📦</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://www.frogorbits.com/"><img src="https://avatars.githubusercontent.com/u/101246?v=4?s=100" width="100px;" alt="adiabatic"/><br /><sub><b>adiabatic</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=adiabatic" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://electronsweatshop.com"><img src="https://avatars.githubusercontent.com/u/354506?v=4?s=100" width="100px;" alt="Randy Barlow"/><br /><sub><b>Randy Barlow</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=bowlofeggs" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://jackson.dev"><img src="https://avatars.githubusercontent.com/u/160646?v=4?s=100" width="100px;" alt="Patrick Jackson"/><br /><sub><b>Patrick Jackson</b></sub></a><br /><a href="#ideas-patricksjackson" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/ClementTsang/bottom/commits?author=patricksjackson" title="Documentation">📖</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/mati865"><img src="https://avatars.githubusercontent.com/u/1174646?v=4?s=100" width="100px;" alt="Mateusz Mikuła"/><br /><sub><b>Mateusz Mikuła</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=mati865" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://blog.guillaume-gomez.fr"><img src="https://avatars.githubusercontent.com/u/3050060?v=4?s=100" width="100px;" alt="Guillaume Gomez"/><br /><sub><b>Guillaume Gomez</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=GuillaumeGomez" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/shurizzle"><img src="https://avatars.githubusercontent.com/u/203655?v=4?s=100" width="100px;" alt="shura"/><br /><sub><b>shura</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=shurizzle" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://www.wezm.net/"><img src="https://avatars.githubusercontent.com/u/21787?v=4?s=100" width="100px;" alt="Wesley Moore"/><br /><sub><b>Wesley Moore</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=wezm" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/xgdgsc"><img src="https://avatars.githubusercontent.com/u/1189869?v=4?s=100" width="100px;" alt="xgdgsc"/><br /><sub><b>xgdgsc</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=xgdgsc" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/ViridiCanis"><img src="https://avatars.githubusercontent.com/u/49595344?v=4?s=100" width="100px;" alt="ViridiCanis"/><br /><sub><b>ViridiCanis</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=ViridiCanis" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/jamartin9"><img src="https://avatars.githubusercontent.com/u/7027701?v=4?s=100" width="100px;" alt="Justin Martin"/><br /><sub><b>Justin Martin</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=jamartin9" title="Code">💻</a> <a href="https://github.com/ClementTsang/bottom/commits?author=jamartin9" title="Documentation">📖</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/DianaNites"><img src="https://avatars.githubusercontent.com/u/5275194?v=4?s=100" width="100px;" alt="Diana"/><br /><sub><b>Diana</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=DianaNites" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://hervyqa.id"><img src="https://avatars.githubusercontent.com/u/45872139?v=4?s=100" width="100px;" alt="Hervy Qurrotul Ainur Rozi"/><br /><sub><b>Hervy Qurrotul Ainur Rozi</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=hervyqa" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://mrivnak.github.io"><img src="https://avatars.githubusercontent.com/u/7389355?v=4?s=100" width="100px;" alt="Mike Rivnak"/><br /><sub><b>Mike Rivnak</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=mrivnak" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/lroobrou"><img src="https://avatars.githubusercontent.com/u/35152113?v=4?s=100" width="100px;" alt="lroobrou"/><br /><sub><b>lroobrou</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=lroobrou" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://cube64128.xyz/"><img src="https://avatars.githubusercontent.com/u/18757988?v=4?s=100" width="100px;" alt="database64128"/><br /><sub><b>database64128</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=database64128" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/sou-chon"><img src="https://avatars.githubusercontent.com/u/35537528?v=4?s=100" width="100px;" alt="Chon Sou"/><br /><sub><b>Chon Sou</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=sou-chon" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Drsheppard01"><img src="https://avatars.githubusercontent.com/u/60893791?v=4?s=100" width="100px;" alt="DrSheppard"/><br /><sub><b>DrSheppard</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=Drsheppard01" title="Documentation">📖</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/RaresCon"><img src="https://avatars.githubusercontent.com/u/95525840?v=4?s=100" width="100px;" alt="Rareș Constantin"/><br /><sub><b>Rareș Constantin</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=RaresCon" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://felipesuri.com"><img src="https://avatars.githubusercontent.com/u/50281523?v=4?s=100" width="100px;" alt="felipesuri"/><br /><sub><b>felipesuri</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=felipesuri" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/spital"><img src="https://avatars.githubusercontent.com/u/11034264?v=4?s=100" width="100px;" alt="spital"/><br /><sub><b>spital</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=spital" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://bikodbg.com/"><img src="https://avatars.githubusercontent.com/u/1389811?v=4?s=100" width="100px;" alt="Michael Bikovitsky"/><br /><sub><b>Michael Bikovitsky</b></sub></a><br /><a href="https://github.com/ClementTsang/bottom/commits?author=mbikovitsky" title="Code">💻</a></td>
      
Download .txt
gitextract_vx6kr0uy/

├── .all-contributorsrc
├── .cargo/
│   └── config.toml
├── .cirrus.yml
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   ├── feature_request.yml
│   │   └── packaging.yml
│   ├── actions/
│   │   └── test-bsd-target/
│   │       └── action.yml
│   ├── ci/
│   │   └── rust_version.txt
│   ├── pull_request_template.md
│   └── workflows/
│       ├── bsd_vm_check.yml
│       ├── build_releases.yml
│       ├── ci.yml
│       ├── clear_workflow_cache.yml
│       ├── coverage.yml
│       ├── deployment.yml
│       ├── docs.yml
│       ├── nightly.yml
│       ├── post_release.yml
│       ├── publish_github_pages.yml
│       ├── test_docs.yml
│       └── validate_schema.yml
├── .gitignore
├── .markdownlint.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Cargo.toml
├── Cross.toml
├── LICENSE
├── README.md
├── build.rs
├── clippy.toml
├── codecov.yml
├── desktop/
│   └── bottom.desktop
├── docs/
│   ├── .gitignore
│   ├── README.md
│   ├── content/
│   │   ├── configuration/
│   │   │   ├── command-line-options.md
│   │   │   └── config-file/
│   │   │       ├── cpu.md
│   │   │       ├── disk-table.md
│   │   │       ├── flags.md
│   │   │       ├── index.md
│   │   │       ├── layout.md
│   │   │       ├── network.md
│   │   │       ├── processes.md
│   │   │       ├── styling.md
│   │   │       └── temperature-table.md
│   │   ├── contribution/
│   │   │   ├── development/
│   │   │   │   ├── build_process.md
│   │   │   │   ├── deploy_process.md
│   │   │   │   ├── dev_env.md
│   │   │   │   ├── logging.md
│   │   │   │   └── testing.md
│   │   │   ├── documentation.md
│   │   │   ├── issues-and-pull-requests.md
│   │   │   └── packaging-and-distribution.md
│   │   ├── index.md
│   │   ├── nightly-release.md
│   │   ├── stylesheets/
│   │   │   └── extra.css
│   │   ├── support/
│   │   │   ├── official.md
│   │   │   └── unofficial.md
│   │   ├── troubleshooting.md
│   │   └── usage/
│   │       ├── autocomplete.md
│   │       ├── basic-mode.md
│   │       ├── general-usage.md
│   │       └── widgets/
│   │           ├── battery.md
│   │           ├── cpu.md
│   │           ├── disk.md
│   │           ├── memory.md
│   │           ├── network.md
│   │           ├── process.md
│   │           └── temperature.md
│   ├── hooks/
│   │   ├── nightly_banner.py
│   │   └── nightly_redirect.py
│   ├── mike.sh
│   ├── mkdocs.yml
│   ├── overrides/
│   │   └── main.html
│   ├── requirements.txt
│   └── serve.sh
├── rustfmt.toml
├── sample_configs/
│   ├── default_config.toml
│   └── demo_config.toml
├── schema/
│   ├── README.md
│   ├── nightly/
│   │   └── bottom.json
│   ├── v0.10/
│   │   └── bottom.json
│   ├── v0.11/
│   │   └── bottom.json
│   ├── v0.12.0/
│   │   └── bottom.json
│   └── v0.9/
│       └── bottom.json
├── scripts/
│   ├── ci/
│   │   ├── bsd_tests.sh
│   │   ├── ci_bsd.sh
│   │   ├── cirrus_release.py
│   │   └── configure_git.sh
│   ├── clear_cache.py
│   ├── hooks/
│   │   ├── README.md
│   │   └── pre-push
│   ├── schema/
│   │   ├── bad_file.toml
│   │   ├── generate.sh
│   │   ├── nightly.sh
│   │   ├── requirements.txt
│   │   └── validator.py
│   └── windows/
│       └── choco/
│           ├── bottom.nuspec.template
│           ├── choco_packager.py
│           └── chocolateyinstall.ps1.template
├── src/
│   ├── app/
│   │   ├── data/
│   │   │   ├── mod.rs
│   │   │   ├── process.rs
│   │   │   ├── store.rs
│   │   │   ├── temperature.rs
│   │   │   └── time_series.rs
│   │   ├── filter.rs
│   │   ├── layout_manager.rs
│   │   └── states.rs
│   ├── app.rs
│   ├── bin/
│   │   ├── main.rs
│   │   └── schema.rs
│   ├── canvas/
│   │   ├── components/
│   │   │   ├── data_table/
│   │   │   │   ├── column.rs
│   │   │   │   ├── data_type.rs
│   │   │   │   ├── draw.rs
│   │   │   │   ├── props.rs
│   │   │   │   ├── sortable.rs
│   │   │   │   ├── state.rs
│   │   │   │   └── styling.rs
│   │   │   ├── data_table.rs
│   │   │   ├── mod.rs
│   │   │   ├── pipe_gauge.rs
│   │   │   ├── time_graph/
│   │   │   │   ├── base.rs
│   │   │   │   ├── variants/
│   │   │   │   │   ├── auto_y_axis.rs
│   │   │   │   │   └── percent.rs
│   │   │   │   ├── variants.rs
│   │   │   │   ├── vendored/
│   │   │   │   │   ├── canvas.rs
│   │   │   │   │   ├── grid.rs
│   │   │   │   │   └── points.rs
│   │   │   │   └── vendored.rs
│   │   │   ├── time_graph.rs
│   │   │   └── widget_carousel.rs
│   │   ├── dialogs/
│   │   │   ├── help_dialog.rs
│   │   │   ├── mod.rs
│   │   │   └── process_kill_dialog.rs
│   │   ├── drawing_utils.rs
│   │   └── widgets/
│   │       ├── battery_display.rs
│   │       ├── cpu_basic.rs
│   │       ├── cpu_graph.rs
│   │       ├── disk_table.rs
│   │       ├── mem_basic.rs
│   │       ├── mem_graph.rs
│   │       ├── mod.rs
│   │       ├── network_basic.rs
│   │       ├── network_graph.rs
│   │       ├── process_table.rs
│   │       └── temperature_table.rs
│   ├── canvas.rs
│   ├── collection/
│   │   ├── amd/
│   │   │   └── amd_gpu_marketing.rs
│   │   ├── amd.rs
│   │   ├── batteries.rs
│   │   ├── cpu/
│   │   │   └── sysinfo.rs
│   │   ├── cpu.rs
│   │   ├── disks/
│   │   │   ├── freebsd.rs
│   │   │   ├── io_counters.rs
│   │   │   ├── other.rs
│   │   │   ├── unix/
│   │   │   │   ├── file_systems.rs
│   │   │   │   ├── linux/
│   │   │   │   │   ├── counters.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   └── partition.rs
│   │   │   │   ├── macos/
│   │   │   │   │   ├── counters.rs
│   │   │   │   │   ├── io_kit/
│   │   │   │   │   │   ├── bindings.rs
│   │   │   │   │   │   ├── io_disks.rs
│   │   │   │   │   │   ├── io_iterator.rs
│   │   │   │   │   │   └── io_object.rs
│   │   │   │   │   ├── io_kit.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── other/
│   │   │   │   │   ├── bindings.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   └── partition.rs
│   │   │   │   └── usage.rs
│   │   │   ├── unix.rs
│   │   │   ├── windows/
│   │   │   │   └── bindings.rs
│   │   │   ├── windows.rs
│   │   │   └── zfs_io_counters.rs
│   │   ├── disks.rs
│   │   ├── error.rs
│   │   ├── linux/
│   │   │   └── utils.rs
│   │   ├── memory/
│   │   │   ├── arc.rs
│   │   │   ├── sysinfo.rs
│   │   │   └── windows.rs
│   │   ├── memory.rs
│   │   ├── network/
│   │   │   └── sysinfo.rs
│   │   ├── network.rs
│   │   ├── nvidia.rs
│   │   ├── processes/
│   │   │   ├── freebsd.rs
│   │   │   ├── linux/
│   │   │   │   ├── mod.rs
│   │   │   │   └── process.rs
│   │   │   ├── macos/
│   │   │   │   └── sysctl_bindings.rs
│   │   │   ├── macos.rs
│   │   │   ├── unix/
│   │   │   │   ├── process_ext.rs
│   │   │   │   └── user_table.rs
│   │   │   ├── unix.rs
│   │   │   └── windows.rs
│   │   ├── processes.rs
│   │   ├── temperature/
│   │   │   ├── linux.rs
│   │   │   └── sysinfo.rs
│   │   └── temperature.rs
│   ├── collection.rs
│   ├── constants.rs
│   ├── event.rs
│   ├── lib.rs
│   ├── options/
│   │   ├── args.rs
│   │   ├── config/
│   │   │   ├── cpu.rs
│   │   │   ├── disk.rs
│   │   │   ├── flags.rs
│   │   │   ├── ignore_list.rs
│   │   │   ├── layout.rs
│   │   │   ├── network.rs
│   │   │   ├── process.rs
│   │   │   ├── style/
│   │   │   │   ├── battery.rs
│   │   │   │   ├── borders.rs
│   │   │   │   ├── cpu.rs
│   │   │   │   ├── graphs.rs
│   │   │   │   ├── memory.rs
│   │   │   │   ├── network.rs
│   │   │   │   ├── tables.rs
│   │   │   │   ├── themes/
│   │   │   │   │   ├── default.rs
│   │   │   │   │   ├── gruvbox.rs
│   │   │   │   │   └── nord.rs
│   │   │   │   ├── themes.rs
│   │   │   │   ├── utils.rs
│   │   │   │   └── widgets.rs
│   │   │   ├── style.rs
│   │   │   └── temperature.rs
│   │   ├── config.rs
│   │   └── error.rs
│   ├── options.rs
│   ├── utils/
│   │   ├── cancellation_token.rs
│   │   ├── conversion.rs
│   │   ├── data_units.rs
│   │   ├── general.rs
│   │   ├── logging.rs
│   │   ├── process_killer.rs
│   │   └── strings.rs
│   └── widgets/
│       ├── battery_info.rs
│       ├── cpu_graph.rs
│       ├── disk_table.rs
│       ├── mem_graph.rs
│       ├── mod.rs
│       ├── network_graph.rs
│       ├── process_table/
│       │   ├── process_columns.rs
│       │   ├── process_data.rs
│       │   ├── query/
│       │   │   ├── and.rs
│       │   │   ├── attribute.rs
│       │   │   ├── error.rs
│       │   │   ├── or.rs
│       │   │   └── prefix.rs
│       │   ├── query.rs
│       │   └── sort_table.rs
│       ├── process_table.rs
│       └── temperature_table.rs
├── tests/
│   ├── integration/
│   │   ├── arg_tests.rs
│   │   ├── invalid_config_tests.rs
│   │   ├── layout_movement_tests.rs
│   │   ├── main.rs
│   │   ├── util.rs
│   │   └── valid_config_tests.rs
│   ├── invalid_configs/
│   │   ├── duplicate_temp_type.toml
│   │   ├── empty_layout.toml
│   │   ├── invalid_colour_hex.toml
│   │   ├── invalid_colour_hex_2.toml
│   │   ├── invalid_colour_hex_3.toml
│   │   ├── invalid_colour_name.toml
│   │   ├── invalid_colour_rgb.toml
│   │   ├── invalid_colour_rgb_2.toml
│   │   ├── invalid_colour_string.toml
│   │   ├── invalid_default_widget_count.toml
│   │   ├── invalid_disk_column.toml
│   │   ├── invalid_layout_widget_type.toml
│   │   ├── invalid_process_column.toml
│   │   ├── lone_default_widget_count.toml
│   │   └── toml_mismatch_type.toml
│   └── valid_configs/
│       ├── all_proc.toml
│       ├── cpu_doughnut.toml
│       ├── empty_config.toml
│       ├── filtering.toml
│       ├── many_proc.toml
│       ├── os_specific/
│       │   └── linux.toml
│       ├── proc_columns.toml
│       ├── styling.toml
│       ├── styling_2.toml
│       └── theme.toml
└── wix/
    ├── License.rtf
    └── main.wxs
Download .txt
SYMBOL INDEX (1377 symbols across 149 files)

FILE: build.rs
  function create_dir (line 21) | fn create_dir(dir: &Path) -> io::Result<()> {
  function generate_completions (line 31) | fn generate_completions<G>(to_generate: G, cmd: &mut Command, out_dir: &...
  function btm_generate (line 38) | fn btm_generate() -> io::Result<()> {
  function extract_sha (line 78) | fn extract_sha(sha: Option<&str>) -> Option<&str> {
  function output_nightly_version (line 82) | fn output_nightly_version(version: &str, git_hash: &str) {
  function nightly_version (line 86) | fn nightly_version() {
  function main (line 116) | fn main() -> io::Result<()> {

FILE: docs/hooks/nightly_banner.py
  function on_config (line 8) | def on_config(config):

FILE: docs/hooks/nightly_redirect.py
  function on_config (line 12) | def on_config(config):

FILE: scripts/ci/cirrus_release.py
  function make_query_request (line 29) | def make_query_request(key: str, branch: str, mutation_id: str):
  function check_build_status (line 78) | def check_build_status(key: str, build_id: str) -> Optional[str]:
  function check_build_tasks (line 110) | def check_build_tasks(key: str, build_id: str) -> Optional[List[str]]:
  function stop_build_tasks (line 145) | def stop_build_tasks(key: str, task_ids: List[str], mutation_id: str) ->...
  function try_download (line 180) | def try_download(build_id: str, dl_path: Path):
  function main (line 188) | def main():

FILE: scripts/clear_cache.py
  function cache_list_request (line 18) | def cache_list_request(key):
  function delete_cache_request (line 25) | def delete_cache_request(key, id):
  function main (line 32) | def main():

FILE: scripts/schema/validator.py
  function main (line 12) | def main():

FILE: src/app.rs
  constant STALE_MIN_MILLISECONDS (line 25) | const STALE_MIN_MILLISECONDS: u64 = 30 * 1000;
  type AxisScaling (line 28) | pub enum AxisScaling {
  type AppConfigFields (line 37) | pub struct AppConfigFields {
  type DataFilters (line 79) | pub struct DataFilters {
  type App (line 86) | pub struct App {
    method new (line 107) | pub fn new(
    method update_data (line 133) | pub fn update_data(&mut self) {
    method reset (line 164) | pub fn reset(&mut self) {
    method should_get_widget_bounds (line 189) | pub fn should_get_widget_bounds(&self) -> bool {
    method on_esc (line 193) | pub fn on_esc(&mut self) {
    method is_in_search_widget (line 257) | pub fn is_in_search_widget(&self) -> bool {
    method reset_multi_tap_keys (line 264) | fn reset_multi_tap_keys(&mut self) {
    method is_in_dialog (line 269) | fn is_in_dialog(&self) -> bool {
    method ignore_normal_keybinds (line 273) | fn ignore_normal_keybinds(&self) -> bool {
    method on_tab (line 277) | pub fn on_tab(&mut self) {
    method on_slash (line 293) | pub fn on_slash(&mut self) {
    method toggle_sort_menu (line 315) | pub fn toggle_sort_menu(&mut self) {
    method invert_sort (line 339) | pub fn invert_sort(&mut self) {
    method toggle_percentages (line 358) | pub fn toggle_percentages(&mut self) {
    method toggle_ignore_case (line 378) | pub fn toggle_ignore_case(&mut self) {
    method toggle_search_whole_word (line 393) | pub fn toggle_search_whole_word(&mut self) {
    method toggle_search_regex (line 408) | pub fn toggle_search_regex(&mut self) {
    method toggle_tree_mode (line 423) | pub fn toggle_tree_mode(&mut self) {
    method on_enter (line 447) | pub fn on_enter(&mut self) {
    method on_delete (line 485) | pub fn on_delete(&mut self) {
    method on_backspace (line 535) | pub fn on_backspace(&mut self) {
    method on_up_key (line 578) | pub fn on_up_key(&mut self) {
    method on_down_key (line 590) | pub fn on_down_key(&mut self) {
    method on_left_key (line 602) | pub fn on_left_key(&mut self) {
    method on_right_key (line 650) | pub fn on_right_key(&mut self) {
    method on_space_key (line 705) | pub fn on_space_key(&mut self) {
    method on_page_up (line 722) | pub fn on_page_up(&mut self) {
    method on_page_down (line 742) | pub fn on_page_down(&mut self) {
    method scroll_half_page_up (line 763) | pub fn scroll_half_page_up(&mut self) {
    method scroll_half_page_down (line 782) | pub fn scroll_half_page_down(&mut self) {
    method skip_cursor_beginning (line 801) | pub fn skip_cursor_beginning(&mut self) {
    method skip_cursor_end (line 831) | pub fn skip_cursor_end(&mut self) {
    method clear_search (line 858) | pub fn clear_search(&mut self) {
    method clear_previous_word (line 871) | pub fn clear_previous_word(&mut self) {
    method on_char_key (line 931) | pub fn on_char_key(&mut self, caught_char: char) {
    method kill_current_process (line 1011) | pub(crate) fn kill_current_process(&mut self) {
    method handle_char (line 1056) | fn handle_char(&mut self, caught_char: char) {
    method toggle_expand_widget (line 1300) | fn toggle_expand_widget(&mut self) {
    method expand_widget (line 1309) | fn expand_widget(&mut self) {
    method move_widget_selection (line 1324) | pub fn move_widget_selection(&mut self, direction: &WidgetDirection) {
    method move_widget_selection_logic (line 1331) | fn move_widget_selection_logic(&mut self, direction: &WidgetDirection) {
    method handle_left_expanded_movement (line 1703) | fn handle_left_expanded_movement(&mut self) {
    method handle_right_expanded_movement (line 1749) | fn handle_right_expanded_movement(&mut self) {
    method skip_to_first (line 1786) | pub fn skip_to_first(&mut self) {
    method skip_to_last (line 1845) | pub fn skip_to_last(&mut self) {
    method decrement_position_count (line 1906) | pub fn decrement_position_count(&mut self) {
    method increment_position_count (line 1910) | pub fn increment_position_count(&mut self) {
    method change_position_count (line 1914) | fn change_position_count(&mut self, amount: i64) {
    method change_process_sort_position (line 1929) | fn change_process_sort_position(&mut self, num_to_change_by: i64) {
    method change_cpu_legend_position (line 1941) | fn change_cpu_legend_position(&mut self, num_to_change_by: i64) {
    method change_process_position (line 1953) | fn change_process_position(&mut self, num_to_change_by: i64) -> Option...
    method change_temp_position (line 1965) | fn change_temp_position(&mut self, num_to_change_by: i64) {
    method change_disk_position (line 1976) | fn change_disk_position(&mut self, num_to_change_by: i64) {
    method help_scroll_up (line 1987) | fn help_scroll_up(&mut self) {
    method help_scroll_down (line 1993) | fn help_scroll_down(&mut self) {
    method help_scroll_to_or_max (line 2001) | fn help_scroll_to_or_max(&mut self, new_position: u16) {
    method handle_scroll_up (line 2010) | pub fn handle_scroll_up(&mut self) {
    method handle_scroll_down (line 2022) | pub fn handle_scroll_down(&mut self) {
    method on_plus (line 2034) | fn on_plus(&mut self) {
    method on_minus (line 2043) | fn on_minus(&mut self) {
    method toggle_collapsing_process_branch (line 2052) | fn toggle_collapsing_process_branch(&mut self) {
    method zoom_out (line 2063) | fn zoom_out(&mut self) {
    method zoom_in (line 2147) | fn zoom_in(&mut self) {
    method reset_cpu_zoom (line 2225) | fn reset_cpu_zoom(&mut self) {
    method reset_mem_zoom (line 2239) | fn reset_mem_zoom(&mut self) {
    method reset_net_zoom (line 2253) | fn reset_net_zoom(&mut self) {
    method reset_zoom (line 2267) | fn reset_zoom(&mut self) {
    method on_left_mouse_up (line 2278) | pub fn on_left_mouse_up(&mut self, x: u16, y: u16) {
    method is_drawing_border (line 2592) | fn is_drawing_border(&self) -> bool {
    method header_offset (line 2596) | fn header_offset(&self, widget: &BottomWidget) -> u16 {
    method handle_paste (line 2613) | pub fn handle_paste(&mut self, paste: String) {

FILE: src/app/data/process.rs
  type ProcessData (line 8) | pub struct ProcessData {
    method ingest (line 20) | pub(super) fn ingest(&mut self, list_of_processes: Vec<ProcessHarvest>) {

FILE: src/app/data/store.rs
  type StoredData (line 20) | pub struct StoredData {
    method reset (line 70) | pub fn reset(&mut self) {
    method eat_data (line 78) | fn eat_data(&mut self, mut data: Box<Data>, settings: &AppConfigFields) {
    method eat_disks (line 159) | fn eat_disks(
  method default (line 44) | fn default() -> Self {
  type FrozenState (line 271) | pub enum FrozenState {
  type DataStore (line 279) | pub struct DataStore {
    method toggle_frozen (line 286) | pub fn toggle_frozen(&mut self) {
    method is_frozen (line 296) | pub fn is_frozen(&self) -> bool {
    method get_data (line 302) | pub fn get_data(&self) -> &StoredData {
    method eat_data (line 310) | pub fn eat_data(&mut self, data: Box<Data>, settings: &AppConfigFields) {
    method clean_data (line 315) | pub fn clean_data(&mut self, max_duration: Duration) {
    method reset (line 320) | pub fn reset(&mut self) {

FILE: src/app/data/temperature.rs
  type TemperatureType (line 6) | pub enum TemperatureType {
    method convert_temp_unit (line 31) | pub fn convert_temp_unit(&self, celsius: f32) -> TypedTemperature {
  type Err (line 14) | type Err = String;
  method from_str (line 16) | fn from_str(s: &str) -> Result<Self, Self::Err> {
  type TypedTemperature (line 44) | pub enum TypedTemperature {
  method fmt (line 51) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  function temp_conversions (line 65) | fn temp_conversions() {

FILE: src/app/data/time_series.rs
  type Values (line 16) | pub type Values = ChunkedData<f64>;
  type TimeSeriesData (line 26) | pub struct TimeSeriesData {
    method add (line 62) | pub fn add(&mut self, data: &Data) {
    method prune (line 171) | pub fn prune(&mut self, max_age: Duration) {

FILE: src/app/filter.rs
  type Filter (line 6) | pub struct Filter {
    method new (line 19) | pub(crate) fn new(ignore_matches: bool, list: Vec<Regex>) -> Self {
    method should_keep (line 28) | pub(crate) fn should_keep(&self, entry: &str) -> bool {
    method has_match (line 41) | pub(crate) fn has_match(&self, value: &str) -> bool {
    method ignore_matches (line 47) | pub(crate) fn ignore_matches(&self) -> bool {
    method optional_should_keep (line 53) | pub(crate) fn optional_should_keep(filter: &Option<Self>, entry: &str)...
  function filter_is_list_ignored (line 69) | fn filter_is_list_ignored() {

FILE: src/app/layout_manager.rs
  type LineSegment (line 8) | type LineSegment = (u16, u16);
  type WidgetMappings (line 10) | type WidgetMappings = (u16, BTreeMap<LineSegment, u64>);
  type ColumnRowMappings (line 11) | type ColumnRowMappings = (u16, BTreeMap<LineSegment, WidgetMappings>);
  type ColumnMappings (line 12) | type ColumnMappings = (u16, BTreeMap<LineSegment, ColumnRowMappings>);
  type BottomLayout (line 19) | pub struct BottomLayout {
    method get_movement_mappings (line 40) | pub fn get_movement_mappings(&mut self) {
    method init_basic_default (line 559) | pub fn init_basic_default(use_battery: bool) -> Self {
  type Ratio (line 24) | trait Ratio {
    method ratio (line 25) | fn ratio(&self) -> u16;
    method ratio (line 29) | fn ratio(&self) -> u16 {
  type BottomRow (line 714) | pub struct BottomRow {
    method new (line 721) | pub fn new(children: Vec<BottomCol>) -> Self {
    method total_col_ratio (line 729) | pub fn total_col_ratio(mut self, total_col_ratio: u16) -> Self {
    method ratio (line 734) | pub fn ratio(mut self, value: u16) -> Self {
    method canvas_handled (line 739) | pub fn canvas_handled(mut self) -> Self {
  type BottomCol (line 749) | pub struct BottomCol {
    method new (line 756) | pub fn new(children: Vec<BottomColRow>) -> Self {
    method total_col_row_ratio (line 764) | pub fn total_col_row_ratio(mut self, total_col_row_ratio: u16) -> Self {
    method ratio (line 769) | pub fn ratio(mut self, value: u16) -> Self {
    method canvas_handled (line 774) | pub fn canvas_handled(mut self) -> Self {
  type BottomColRow (line 781) | pub struct BottomColRow {
    method new (line 788) | pub(crate) fn new(children: Vec<BottomWidget>) -> Self {
    method total_widget_ratio (line 796) | pub(crate) fn total_widget_ratio(mut self, total_widget_ratio: u16) ->...
    method ratio (line 801) | pub fn ratio(mut self, value: u16) -> Self {
    method canvas_handled (line 806) | pub fn canvas_handled(mut self) -> Self {
    method grow (line 811) | pub fn grow(mut self, minimum: Option<u16>) -> Self {
  type WidgetDirection (line 818) | pub enum WidgetDirection {
    method is_opposite (line 826) | pub fn is_opposite(&self, other_direction: &WidgetDirection) -> bool {
  type BottomWidget (line 840) | pub struct BottomWidget {
    method new (line 866) | pub(crate) fn new(widget_type: BottomWidgetType, widget_id: u64) -> Se...
    method left_neighbour (line 882) | pub(crate) fn left_neighbour(mut self, left_neighbour: Option<u64>) ->...
    method right_neighbour (line 887) | pub(crate) fn right_neighbour(mut self, right_neighbour: Option<u64>) ...
    method up_neighbour (line 892) | pub(crate) fn up_neighbour(mut self, up_neighbour: Option<u64>) -> Self {
    method down_neighbour (line 897) | pub(crate) fn down_neighbour(mut self, down_neighbour: Option<u64>) ->...
    method ratio (line 902) | pub(crate) fn ratio(mut self, value: u16) -> Self {
    method canvas_handled (line 907) | pub fn canvas_handled(mut self) -> Self {
    method grow (line 912) | pub fn grow(mut self, minimum: Option<u16>) -> Self {
    method with_ratio_override (line 919) | pub fn with_ratio_override(mut self, ratio_override: u16) -> Self {
    method parent_reflector (line 924) | pub(crate) fn parent_reflector(
  type BottomWidgetType (line 933) | pub enum BottomWidgetType {
    method is_widget_table (line 953) | pub fn is_widget_table(&self) -> bool {
    method is_widget_graph (line 958) | pub fn is_widget_graph(&self) -> bool {
    method get_pretty_name (line 963) | pub fn get_pretty_name(&self) -> &str {
    type Err (line 979) | type Err = OptionError;
    method from_str (line 981) | fn from_str(s: &str) -> Result<Self, Self::Err> {
  type UsedWidgets (line 1050) | pub struct UsedWidgets {

FILE: src/app/states.rs
  type AppWidgetStates (line 17) | pub struct AppWidgetStates {
  type CursorDirection (line 29) | pub enum CursorDirection {
  type AppHelpDialogState (line 34) | pub struct AppHelpDialogState {
  method default (line 42) | fn default() -> Self {
  type AppSearchState (line 53) | pub struct AppSearchState {
    method reset (line 89) | pub fn reset(&mut self) {
    method is_invalid_or_blank_search (line 97) | pub fn is_invalid_or_blank_search(&self) -> bool {
    method get_start_position (line 102) | pub fn get_start_position(&mut self, available_width: usize, is_force_...
    method walk_forward (line 179) | pub(crate) fn walk_forward(&mut self) {
    method walk_backward (line 202) | pub(crate) fn walk_backward(&mut self) {
    method update_sizes (line 225) | pub(crate) fn update_sizes(&mut self) {
  method default (line 70) | fn default() -> Self {
  type ProcState (line 243) | pub struct ProcState {
    method init (line 248) | pub fn init(widget_states: HashMap<u64, ProcWidgetState>) -> Self {
    method get_mut_widget_state (line 252) | pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut ...
    method get_widget_state (line 256) | pub fn get_widget_state(&self, widget_id: u64) -> Option<&ProcWidgetSt...
  type NetState (line 261) | pub struct NetState {
    method init (line 266) | pub fn init(widget_states: HashMap<u64, NetWidgetState>) -> Self {
  type CpuState (line 271) | pub struct CpuState {
    method init (line 276) | pub fn init(widget_states: HashMap<u64, CpuWidgetState>) -> Self {
    method get_mut_widget_state (line 280) | pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut ...
    method get_widget_state (line 284) | pub fn get_widget_state(&self, widget_id: u64) -> Option<&CpuWidgetSta...
  type MemState (line 289) | pub struct MemState {
    method init (line 294) | pub fn init(widget_states: HashMap<u64, MemWidgetState>) -> Self {
  type TempState (line 299) | pub struct TempState {
    method init (line 304) | pub fn init(widget_states: HashMap<u64, TempWidgetState>) -> Self {
    method get_mut_widget_state (line 308) | pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut ...
    method get_widget_state (line 312) | pub fn get_widget_state(&self, widget_id: u64) -> Option<&TempWidgetSt...
  type DiskState (line 317) | pub struct DiskState {
    method init (line 322) | pub fn init(widget_states: HashMap<u64, DiskTableWidget>) -> Self {
    method get_mut_widget_state (line 326) | pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut ...
    method get_widget_state (line 330) | pub fn get_widget_state(&self, widget_id: u64) -> Option<&DiskTableWid...
  type BasicTableWidgetState (line 334) | pub struct BasicTableWidgetState {
  type AppBatteryState (line 346) | pub struct AppBatteryState {
    method init (line 351) | pub fn init(widget_states: HashMap<u64, BatteryWidgetState>) -> Self {
    method get_mut_widget_state (line 355) | pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut ...
  type ParagraphScrollState (line 361) | pub struct ParagraphScrollState {
  function move_right (line 370) | fn move_right(state: &mut AppSearchState) {
  function move_left (line 375) | fn move_left(state: &mut AppSearchState) {
  function search_cursor_moves (line 381) | fn search_cursor_moves() {

FILE: src/bin/main.rs
  function main (line 5) | fn main() -> anyhow::Result<()> {

FILE: src/bin/schema.rs
  type SchemaOptions (line 14) | struct SchemaOptions {
  function generate_schema (line 19) | fn generate_schema(schema_options: SchemaOptions) -> anyhow::Result<()> {
  function main (line 102) | fn main() -> anyhow::Result<()> {

FILE: src/canvas.rs
  type Painter (line 29) | pub struct Painter {
    method init (line 43) | pub fn init(layout: BottomLayout, styling: Styles) -> anyhow::Result<S...
    method get_border_style (line 55) | pub fn get_border_style(&self, widget_id: u64, selected_widget_id: u64...
    method draw_frozen_indicator (line 64) | fn draw_frozen_indicator(&self, f: &mut Frame<'_>, draw_loc: Rect) {
    method draw_data (line 77) | pub fn draw_data<B: Backend>(
    method draw_widgets_with_constraints (line 432) | fn draw_widgets_with_constraints(

FILE: src/canvas/components/data_table.rs
  type DataTable (line 34) | pub struct DataTable<DataType, Header, S = Unsortable, C = Column<Header...
  function new (line 47) | pub fn new<C: Into<Vec<Column<H>>>>(
  function first_draw_index (line 68) | pub fn first_draw_index(mut self, first_index: usize) -> Self {
  function scroll_to_first (line 74) | pub fn scroll_to_first(&mut self) {
  function scroll_to_last (line 80) | pub fn scroll_to_last(&mut self) {
  function set_data (line 86) | pub fn set_data(&mut self, data: Vec<DataType>) {
  function increment_position (line 102) | pub fn increment_position(&mut self, change: i64) -> Option<usize> {
  function set_position (line 131) | pub fn set_position(&mut self, new_index: usize) {
  function current_index (line 142) | pub fn current_index(&self) -> usize {
  function current_item (line 147) | pub fn current_item(&self) -> Option<&DataType> {
  function ratatui_selected (line 152) | pub fn ratatui_selected(&self) -> Option<usize> {
  type TestType (line 164) | struct TestType {
    method to_cell_text (line 169) | fn to_cell_text(
    method column_widths (line 175) | fn column_widths<C: DataTableColumn<&'static str>>(
  function create_test_table (line 185) | fn create_test_table() -> DataTable<TestType, &'static str> {
  function test_scrolling (line 201) | fn test_scrolling() {
  function test_set_position (line 215) | fn test_set_position() {
  function test_increment_position (line 230) | fn test_increment_position() {
  function test_lose_data (line 283) | fn test_lose_data() {

FILE: src/canvas/components/data_table/column.rs
  type ColumnWidthBounds (line 9) | pub enum ColumnWidthBounds {
  type ColumnHeader (line 30) | pub trait ColumnHeader {
    method text (line 32) | fn text(&self) -> Cow<'static, str>;
    method header (line 37) | fn header(&self) -> Cow<'static, str> {
    method text (line 43) | fn text(&self) -> Cow<'static, str> {
    method text (line 49) | fn text(&self) -> Cow<'static, str> {
  type DataTableColumn (line 54) | pub trait DataTableColumn<H: ColumnHeader> {
    method inner (line 55) | fn inner(&self) -> &H;
    method inner_mut (line 57) | fn inner_mut(&mut self) -> &mut H;
    method bounds (line 59) | fn bounds(&self) -> ColumnWidthBounds;
    method bounds_mut (line 61) | fn bounds_mut(&mut self) -> &mut ColumnWidthBounds;
    method is_hidden (line 63) | fn is_hidden(&self) -> bool;
    method header (line 66) | fn header(&self) -> Cow<'static, str>;
    method header_len (line 71) | fn header_len(&self) -> usize {
  type Column (line 77) | pub struct Column<H> {
  function inner (line 91) | fn inner(&self) -> &H {
  function inner_mut (line 96) | fn inner_mut(&mut self) -> &mut H {
  function bounds (line 101) | fn bounds(&self) -> ColumnWidthBounds {
  function bounds_mut (line 106) | fn bounds_mut(&mut self) -> &mut ColumnWidthBounds {
  function is_hidden (line 111) | fn is_hidden(&self) -> bool {
  function header (line 115) | fn header(&self) -> Cow<'static, str> {
  function hard (line 121) | pub const fn hard(inner: H, width: u16) -> Self {
  function soft (line 129) | pub const fn soft(inner: H, max_percentage: Option<f32>) -> Self {
  type CalculateColumnWidths (line 141) | pub trait CalculateColumnWidths<H> {
    method calculate_column_widths (line 149) | fn calculate_column_widths(&self, total_width: u16, left_to_right: boo...
  function calculate_column_widths (line 157) | fn calculate_column_widths(&self, total_width: u16, left_to_right: bool)...

FILE: src/canvas/components/data_table/data_type.rs
  type DataToCell (line 8) | pub trait DataToCell<H>
    method to_cell_text (line 14) | fn to_cell_text(&self, column: &H, calculated_width: NonZeroU16) -> Op...
    method style_cell (line 23) | fn style_cell(&self, column: &H, painter: &Painter) -> Option<tui::sty...
    method style_row (line 35) | fn style_row<'a>(&self, row: Row<'a>, painter: &Painter) -> Row<'a> {
    method column_widths (line 40) | fn column_widths<C: DataTableColumn<H>>(data: &[Self], columns: &[C]) ...

FILE: src/canvas/components/data_table/draw.rs
  type SelectionState (line 25) | pub enum SelectionState {
    method new (line 32) | pub fn new(is_expanded: bool, is_on_widget: bool) -> Self {
  type DrawInfo (line 44) | pub struct DrawInfo {
    method is_on_widget (line 52) | pub fn is_on_widget(&self) -> bool {
    method is_expanded (line 57) | pub fn is_expanded(&self) -> bool {
  function block (line 69) | fn block<'a>(&self, draw_info: &'a DrawInfo, data_len: usize) -> Block<'...
  function generate_title (line 98) | fn generate_title(
  function draw (line 132) | pub fn draw(

FILE: src/canvas/components/data_table/props.rs
  type DataTableProps (line 3) | pub struct DataTableProps {

FILE: src/canvas/components/data_table/sortable.rs
  type SortOrder (line 15) | pub enum SortOrder {
    method rev (line 22) | pub fn rev(&self) -> SortOrder {
    method const_default (line 30) | pub const fn const_default() -> Self {
  method default (line 36) | fn default() -> Self {
  type Unsortable (line 42) | pub struct Unsortable;
  type Sortable (line 45) | pub struct Sortable {
  type SortType (line 59) | pub trait SortType: private::Sealed {
    method build_header (line 61) | fn build_header<H, C>(&self, columns: &[C], widths: &[NonZeroU16]) -> ...
    method build_header (line 87) | fn build_header<H, C>(&self, columns: &[C], widths: &[NonZeroU16]) -> ...
  type Sealed (line 78) | pub trait Sealed {}
  type SortsRow (line 119) | pub trait SortsRow {
    method sort_data (line 123) | fn sort_data(&self, data: &mut [Self::DataType], descending: bool);
    type DataType (line 387) | type DataType = TestType;
    method sort_data (line 389) | fn sort_data(&self, data: &mut [TestType], descending: bool) {
  type SortColumn (line 127) | pub struct SortColumn<T> {
  function inner (line 147) | fn inner(&self) -> &T {
  function inner_mut (line 152) | fn inner_mut(&mut self) -> &mut T {
  function bounds (line 157) | fn bounds(&self) -> ColumnWidthBounds {
  function bounds_mut (line 162) | fn bounds_mut(&mut self) -> &mut ColumnWidthBounds {
  function is_hidden (line 167) | fn is_hidden(&self) -> bool {
  function header (line 171) | fn header(&self) -> Cow<'static, str> {
  function header_len (line 175) | fn header_len(&self) -> usize {
  function new (line 187) | pub fn new(inner: T) -> Self {
  function hard (line 198) | pub const fn hard(inner: T, width: u16) -> Self {
  function soft (line 209) | pub const fn soft(inner: T, max_percentage: Option<f32>) -> Self {
  function default_descending (line 222) | pub const fn default_descending(mut self) -> Self {
  function sort_by (line 229) | pub fn sort_by(&self, data: &mut [D], order: SortOrder) {
  type SortDataTableProps (line 235) | pub struct SortDataTableProps {
  type SortDataTable (line 242) | pub type SortDataTable<DataType, H> = DataTable<DataType, H, Sortable, S...
  function new_sortable (line 249) | pub fn new_sortable<C: Into<Vec<SortColumn<H>>>>(
  function set_order (line 269) | pub fn set_order(&mut self, order: SortOrder) {
  function order (line 274) | pub fn order(&self) -> SortOrder {
  function toggle_order (line 279) | pub fn toggle_order(&mut self) {
  function try_select_location (line 291) | pub fn try_select_location(&mut self, x: u16, y: u16) -> Option<usize> {
  function set_sort_index (line 311) | pub fn set_sort_index(&mut self, index: usize) {
  function sort_index (line 321) | pub fn sort_index(&self) -> usize {
  function get_range (line 326) | fn get_range(&self, needle: u16) -> Option<usize> {
  type TestType (line 352) | struct TestType {
    method to_cell_text (line 363) | fn to_cell_text(
    method column_widths (line 369) | fn column_widths<C: DataTableColumn<ColumnType>>(_data: &[Self], _colu...
  type ColumnType (line 357) | enum ColumnType {
  method text (line 378) | fn text(&self) -> Cow<'static, str> {
  function test_sorting (line 402) | fn test_sorting() {

FILE: src/canvas/components/data_table/state.rs
  type ScrollDirection (line 6) | pub enum ScrollDirection {
  type DataTableState (line 16) | pub struct DataTableState {
    method get_start_position (line 51) | pub fn get_start_position(&mut self, num_rows: usize, is_force_redraw:...
  method default (line 37) | fn default() -> Self {

FILE: src/canvas/components/data_table/styling.rs
  type DataTableStyling (line 6) | pub struct DataTableStyling {
    method from_palette (line 17) | pub fn from_palette(styles: &Styles) -> Self {

FILE: src/canvas/components/pipe_gauge.rs
  type LabelLimit (line 10) | pub enum LabelLimit {
  type PipeGauge (line 21) | pub struct PipeGauge<'a> {
  method default (line 32) | fn default() -> Self {
  function ratio (line 50) | pub fn ratio(mut self, ratio: f64) -> Self {
  function start_label (line 57) | pub fn start_label<T>(mut self, start_label: T) -> Self
  function inner_label (line 66) | pub fn inner_label<T>(mut self, inner_label: T) -> Self
  function label_style (line 75) | pub fn label_style(mut self, label_style: Style) -> Self {
  function gauge_style (line 81) | pub fn gauge_style(mut self, style: Style) -> Self {
  function hide_parts (line 88) | pub fn hide_parts(mut self, hide_parts: LabelLimit) -> Self {
  method render (line 95) | fn render(mut self, area: Rect, buf: &mut Buffer) {

FILE: src/canvas/components/time_graph/base.rs
  type GraphData (line 22) | pub(crate) struct GraphData<'a> {
  function time (line 30) | pub fn time(mut self, time: &'a [Instant]) -> Self {
  function values (line 35) | pub fn values(mut self, values: &'a Values) -> Self {
  function style (line 40) | pub fn style(mut self, style: Style) -> Self {
  function name (line 45) | pub fn name(mut self, name: Cow<'a, str>) -> Self {
  type TimeGraph (line 51) | pub struct TimeGraph<'a> {
  function generate_x_axis (line 101) | fn generate_x_axis(&self) -> Axis<'_> {
  function generate_y_axis (line 124) | fn generate_y_axis(&self) -> Axis<'_> {
  function draw (line 145) | pub fn draw(&self, f: &mut Frame<'_>, draw_loc: Rect, graph_data: Vec<Gr...
  function create_dataset (line 183) | fn create_dataset(data: GraphData<'_>) -> Dataset<'_> {
  constant Y_LABELS (line 221) | const Y_LABELS: [Cow<'static, str>; 3] = [
  function create_time_graph (line 227) | fn create_time_graph() -> TimeGraph<'static> {
  function time_graph_gen_x_axis (line 248) | fn time_graph_gen_x_axis() {
  function time_graph_gen_y_axis (line 263) | fn time_graph_gen_y_axis() {

FILE: src/canvas/components/time_graph/variants.rs
  function get_border_style (line 8) | fn get_border_style(styles: &Styles, widget_id: u64, selected_widget_id:...

FILE: src/canvas/components/time_graph/variants/percent.rs
  type PercentTimeGraph (line 16) | pub(crate) struct PercentTimeGraph<'a> {
  function build (line 61) | pub fn build(self) -> TimeGraph<'a> {

FILE: src/canvas/components/time_graph/vendored.rs
  constant DEFAULT_LEGEND_CONSTRAINTS (line 29) | pub const DEFAULT_LEGEND_CONSTRAINTS: (Constraint, Constraint) =
  type Point (line 33) | pub type Point = (f64, f64);
  type AxisBound (line 38) | pub enum AxisBound {
    method get_bounds (line 49) | fn get_bounds(&self) -> [f64; 2] {
  type Axis (line 60) | pub struct Axis<'a> {
  function title (line 81) | pub fn title<T>(mut self, title: T) -> Axis<'a>
  function bounds (line 91) | pub fn bounds(mut self, bounds: AxisBound) -> Axis<'a> {
  function labels (line 101) | pub fn labels(mut self, labels: Vec<Span<'a>>) -> Axis<'a> {
  function style (line 108) | pub fn style<S: Into<Style>>(mut self, style: S) -> Axis<'a> {
  function labels_alignment (line 122) | pub fn labels_alignment(mut self, alignment: Alignment) -> Axis<'a> {
  type LegendPosition (line 132) | pub enum LegendPosition {
    method layout (line 153) | fn layout(
  type ParseLegendPositionError (line 243) | pub struct ParseLegendPositionError;
  type Err (line 246) | type Err = ParseLegendPositionError;
  method from_str (line 248) | fn from_str(s: &str) -> Result<Self, Self::Err> {
  type Data (line 264) | enum Data<'a> {
  type Dataset (line 280) | pub struct Dataset<'a> {
  function name (line 296) | pub fn name<S>(mut self, name: S) -> Dataset<'a>
  function data (line 313) | pub fn data(mut self, times: &'a [Instant], values: &'a Values) -> Datas...
  function marker (line 328) | pub fn marker(mut self, marker: symbols::Marker) -> Dataset<'a> {
  function graph_type (line 340) | pub fn graph_type(mut self, graph_type: GraphType) -> Dataset<'a> {
  function style (line 355) | pub fn style<S: Into<Style>>(mut self, style: S) -> Dataset<'a> {
  type ChartLayout (line 364) | struct ChartLayout {
  type ChartScaling (line 385) | pub(crate) enum ChartScaling {
    method scale (line 394) | pub(super) fn scale(&self, value: f64) -> f64 {
  type TimeChart (line 414) | pub(super) struct TimeChart<'a> {
  function new (line 440) | pub fn new(datasets: Vec<Dataset<'a>>) -> TimeChart<'a> {
  function block (line 457) | pub fn block(mut self, block: Block<'a>) -> TimeChart<'a> {
  function style (line 470) | pub fn style<S: Into<Style>>(mut self, style: S) -> TimeChart<'a> {
  function legend_style (line 477) | pub fn legend_style(mut self, legend_style: Style) -> TimeChart<'a> {
  function x_axis (line 486) | pub fn x_axis(mut self, axis: Axis<'a>) -> TimeChart<'a> {
  function y_axis (line 495) | pub fn y_axis(mut self, axis: Axis<'a>) -> TimeChart<'a> {
  function marker (line 502) | pub fn marker(mut self, marker: Marker) -> TimeChart<'a> {
  function hidden_legend_constraints (line 518) | pub fn hidden_legend_constraints(
  function legend_position (line 538) | pub fn legend_position(mut self, position: Option<LegendPosition>) -> Ti...
  function scaling (line 545) | pub fn scaling(mut self, scaling: ChartScaling) -> TimeChart<'a> {
  function layout (line 552) | fn layout(&self, area: Rect) -> ChartLayout {
  function max_width_of_labels_left_of_y_axis (line 639) | fn max_width_of_labels_left_of_y_axis(&self, area: Rect, has_y_axis: boo...
  function render_x_labels (line 671) | fn render_x_labels(
  function first_x_label_area (line 719) | fn first_x_label_area(
  function render_label (line 738) | fn render_label(buf: &mut Buffer, label: &Span<'_>, label_area: Rect, al...
  function render_y_labels (line 751) | fn render_y_labels(
  method render (line 778) | fn render(self, area: Rect, buf: &mut Buffer) {
  type Item (line 916) | type Item = Axis<'a>;
  method style (line 918) | fn style(&self) -> Style {
  method set_style (line 922) | fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
  type Item (line 928) | type Item = Dataset<'a>;
  method style (line 930) | fn style(&self) -> Style {
  method set_style (line 934) | fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
  type Item (line 940) | type Item = TimeChart<'a>;
  method style (line 942) | fn style(&self) -> Style {
  method set_style (line 946) | fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
  type LegendTestCase (line 1010) | struct LegendTestCase {
  function it_should_hide_the_legend (line 1017) | fn it_should_hide_the_legend() {
  function axis_can_be_stylized (line 1058) | fn axis_can_be_stylized() {
  function dataset_can_be_stylized (line 1070) | fn dataset_can_be_stylized() {
  function chart_can_be_stylized (line 1082) | fn chart_can_be_stylized() {
  function graph_type_to_string (line 1099) | fn graph_type_to_string() {
  function graph_type_from_str (line 1105) | fn graph_type_from_str() {
  function it_does_not_panic_if_title_is_wider_than_buffer (line 1112) | fn it_does_not_panic_if_title_is_wider_than_buffer() {
  function datasets_without_name_do_not_contribute_to_legend_height (line 1123) | fn datasets_without_name_do_not_contribute_to_legend_height() {
  function no_legend_if_no_named_datasets (line 1137) | fn no_legend_if_no_named_datasets() {
  function dataset_legend_style_is_patched (line 1147) | fn dataset_legend_style_is_patched() {
  function test_chart_have_a_topleft_legend (line 1168) | fn test_chart_have_a_topleft_legend() {
  function test_chart_have_a_long_y_axis_title_overlapping_legend (line 1204) | fn test_chart_have_a_long_y_axis_title_overlapping_legend() {
  function test_chart_have_overflowed_y_axis (line 1240) | fn test_chart_have_overflowed_y_axis() {
  function test_legend_area_can_fit_same_chart_area (line 1266) | fn test_legend_area_can_fit_same_chart_area() {
  function test_legend_of_chart_have_odd_margin_size (line 1296) | fn test_legend_of_chart_have_odd_margin_size() {

FILE: src/canvas/components/time_graph/vendored/canvas.rs
  type Shape (line 35) | pub trait Shape {
    method draw (line 36) | fn draw(&self, painter: &mut Painter<'_, '_>);
    method draw (line 40) | fn draw(&self, painter: &mut Painter<'_, '_>) {
    method draw (line 125) | fn draw(&self, painter: &mut Painter<'_, '_>) {
  function draw_line_low (line 82) | fn draw_line_low(
  function draw_line_high (line 103) | fn draw_line_high(
  type Label (line 136) | pub struct Label<'a> {
  type Painter (line 143) | pub struct Painter<'a, 'b> {
  function get_point (line 150) | pub fn get_point(&self, x: f64, y: f64) -> Option<(usize, usize)> {
  function paint (line 167) | pub fn paint(&mut self, x: usize, y: usize, color: Color) {
  function from (line 173) | fn from(context: &'a mut Context<'b>) -> Painter<'a, 'b> {
  type Context (line 184) | pub struct Context<'a> {
  function new (line 193) | pub fn new(
  function marker_to_grid (line 207) | fn marker_to_grid(width: u16, height: u16, marker: Marker) -> Box<dyn Gr...
  function draw (line 222) | pub fn draw<S>(&mut self, shape: &S)
  type Canvas (line 234) | pub struct Canvas<'a, F>
  method default (line 250) | fn default() -> Canvas<'a, F> {
  function x_bounds (line 266) | pub fn x_bounds(mut self, bounds: [f64; 2]) -> Canvas<'a, F> {
  function y_bounds (line 271) | pub fn y_bounds(mut self, bounds: [f64; 2]) -> Canvas<'a, F> {
  function paint (line 277) | pub fn paint(mut self, f: F) -> Canvas<'a, F> {
  function background_color (line 282) | pub fn background_color(mut self, color: Color) -> Canvas<'a, F> {
  function marker (line 291) | pub fn marker(mut self, marker: Marker) -> Canvas<'a, F> {
  method render (line 301) | fn render(self, area: Rect, buf: &mut Buffer) {
  method render (line 310) | fn render(self, area: Rect, buf: &mut Buffer) {

FILE: src/canvas/components/time_graph/vendored/grid.rs
  type Layer (line 15) | pub(super) struct Layer {
  type LayerCell (line 26) | pub(super) struct LayerCell {
  type Grid (line 38) | pub(super) trait Grid: Debug {
    method resolution (line 44) | fn resolution(&self) -> (f64, f64);
    method paint (line 49) | fn paint(&mut self, x: usize, y: usize, color: Color);
    method save (line 51) | fn save(&self) -> Layer;
    method reset (line 53) | fn reset(&mut self);
    method resolution (line 116) | fn resolution(&self) -> (f64, f64) {
    method paint (line 123) | fn paint(&mut self, x: usize, y: usize, color: Color) {
    method save (line 158) | fn save(&self) -> Layer {
    method reset (line 182) | fn reset(&mut self) {
    method resolution (line 291) | fn resolution(&self) -> (f64, f64) {
    method paint (line 295) | fn paint(&mut self, x: usize, y: usize, color: Color) {
    method save (line 304) | fn save(&self) -> Layer {
    method reset (line 318) | fn reset(&mut self) {
    method resolution (line 360) | fn resolution(&self) -> (f64, f64) {
    method paint (line 364) | fn paint(&mut self, x: usize, y: usize, color: Color) {
    method save (line 368) | fn save(&self) -> Layer {
    method reset (line 418) | fn reset(&mut self) {
  type PatternCell (line 58) | struct PatternCell {
  type PatternGrid (line 84) | pub(super) struct PatternGrid<const W: usize, const H: usize> {
  constant _PATTERN_DIMENSION_CHECK (line 97) | const _PATTERN_DIMENSION_CHECK: usize = u8::BITS as usize - W * H;
  function new (line 101) | pub(super) fn new(width: u16, height: u16, char_table: &'static [char]) ...
  type CharGrid (line 251) | pub(super) struct CharGrid {
    method new (line 271) | pub(super) fn new(width: u16, height: u16, cell_char: char) -> Self {
    method apply_color_to_bg (line 282) | pub(super) fn apply_color_to_bg(self) -> Self {
  type HalfBlockGrid (line 338) | pub(super) struct HalfBlockGrid {
    method new (line 350) | pub(super) fn new(width: u16, height: u16) -> Self {

FILE: src/canvas/components/time_graph/vendored/points.rs
  function draw_points (line 13) | pub(crate) fn draw_points(&self, ctx: &mut Context<'_>) {
  function interpolate_point (line 102) | fn interpolate_point(older_point: &Point, newer_point: &Point, x: f64) -...
  function time_graph_test_interpolation (line 115) | fn time_graph_test_interpolation() {

FILE: src/canvas/components/widget_carousel.rs
  method draw_basic_table_arrows (line 14) | pub fn draw_basic_table_arrows(

FILE: src/canvas/dialogs/help_dialog.rs
  method help_text_lines (line 19) | fn help_text_lines(&self) -> Vec<Line<'_>> {
  method draw_help_dialog (line 41) | pub fn draw_help_dialog(&self, f: &mut Frame<'_>, app_state: &mut App, d...

FILE: src/canvas/dialogs/process_kill_dialog.rs
  type ButtonState (line 172) | pub(crate) enum ButtonState {
  type ProcessKillSelectingInner (line 186) | struct ProcessKillSelectingInner {
  type ProcessKillDialogState (line 194) | enum ProcessKillDialogState {
  type ProcessKillDialog (line 207) | pub(crate) struct ProcessKillDialog {
    method reset (line 213) | pub fn reset(&mut self) {
    method is_open (line 218) | pub fn is_open(&self) -> bool {
    method on_esc (line 222) | pub fn on_esc(&mut self) {
    method on_enter (line 226) | pub fn on_enter(&mut self) {
    method on_char (line 303) | pub fn on_char(&mut self, c: char) {
    method on_click (line 389) | pub fn on_click(&mut self, x: u16, y: u16) -> bool {
    method on_scroll_up (line 423) | pub fn on_scroll_up(&mut self) {
    method on_scroll_down (line 428) | pub fn on_scroll_down(&mut self) {
    method on_left_key (line 433) | pub fn on_left_key(&mut self) {
    method on_right_key (line 446) | pub fn on_right_key(&mut self) {
    method scroll_up_by (line 459) | fn scroll_up_by(state: &mut ListState, amount: usize) {
    method scroll_down_by (line 470) | fn scroll_down_by(state: &mut ListState, amount: usize) {
    method on_up_key (line 482) | pub fn on_up_key(&mut self) {
    method on_down_key (line 496) | pub fn on_down_key(&mut self) {
    method on_page_up (line 510) | pub fn on_page_up(&mut self) {
    method on_page_down (line 529) | pub fn on_page_down(&mut self) {
    method go_to_first (line 547) | pub fn go_to_first(&mut self) {
    method go_to_last (line 560) | pub fn go_to_last(&mut self) {
    method start_process_kill (line 574) | pub fn start_process_kill(
    method handle_redraw (line 609) | pub fn handle_redraw(&mut self) {
    method draw_selecting (line 626) | fn draw_selecting(
    method draw_no_button_dialog (line 806) | fn draw_no_button_dialog(
    method draw (line 839) | pub fn draw(&mut self, f: &mut Frame<'_>, draw_area: Rect, styles: &St...

FILE: src/canvas/drawing_utils.rs
  constant SIDE_BORDERS (line 8) | pub const SIDE_BORDERS: Borders = Borders::LEFT.union(Borders::RIGHT);
  constant AUTOHIDE_TIMEOUT_MILLISECONDS (line 9) | pub const AUTOHIDE_TIMEOUT_MILLISECONDS: u64 = 5000;
  function should_hide_x_label (line 12) | pub fn should_hide_x_label(
  function widget_block (line 32) | pub fn widget_block(is_basic: bool, is_selected: bool, border_type: Bord...
  function dialog_block (line 49) | pub fn dialog_block(border_type: BorderType) -> Block<'static> {
  function test_should_hide_x_label (line 61) | fn test_should_hide_x_label() {
  function assert_side_border_bits_match (line 97) | fn assert_side_border_bits_match() {

FILE: src/canvas/widgets/battery_display.rs
  function calculate_basic_use_bars (line 19) | fn calculate_basic_use_bars(use_percentage: f64, num_bars_available: usi...
  method draw_battery (line 27) | pub fn draw_battery(
  function get_hms (line 253) | fn get_hms(secs: u32) -> (u32, u32, u32) {
  function long_time (line 261) | fn long_time(secs: u32) -> String {
  function short_time (line 278) | fn short_time(secs: u32) -> String {
  function test_get_hms (line 293) | fn test_get_hms() {
  function test_long_time (line 303) | fn test_long_time() {
  function test_short_time (line 314) | fn test_short_time() {
  function test_calculate_basic_use_bars (line 325) | fn test_calculate_basic_use_bars() {

FILE: src/canvas/widgets/cpu_basic.rs
  method draw_basic_cpu (line 21) | pub fn draw_basic_cpu(
  method cpu_info (line 156) | fn cpu_info(&self, data: &CpuData) -> (String, String, f32, tui::style::...

FILE: src/canvas/widgets/cpu_graph.rs
  constant AVG_POSITION (line 20) | const AVG_POSITION: usize = 1;
  constant ALL_POSITION (line 21) | const ALL_POSITION: usize = 0;
  method draw_cpu (line 24) | pub fn draw_cpu(&self, f: &mut Frame<'_>, app_state: &mut App, draw_loc:...
  method generate_points (line 119) | fn generate_points<'a>(
  method draw_cpu_graph (line 169) | fn draw_cpu_graph(
  method draw_cpu_legend (line 224) | fn draw_cpu_legend(

FILE: src/canvas/widgets/disk_table.rs
  method draw_disk_table (line 12) | pub fn draw_disk_table(

FILE: src/canvas/widgets/mem_basic.rs
  function memory_fraction_label (line 17) | fn memory_fraction_label(data: &MemData) -> Cow<'static, str> {
  function memory_percentage_label (line 28) | fn memory_percentage_label(data: &MemData) -> Cow<'static, str> {
  function memory_label (line 35) | fn memory_label(data: &MemData, is_percentage: bool) -> Cow<'static, str> {
  method draw_basic_memory (line 44) | pub fn draw_basic_memory(

FILE: src/canvas/widgets/mem_graph.rs
  function memory_legend_label (line 22) | fn memory_legend_label(name: &str, data: Option<&MemData>) -> String {
  function graph_data (line 38) | fn graph_data<'a>(
  method draw_memory_graph (line 56) | pub fn draw_memory_graph(

FILE: src/canvas/widgets/mod.rs
  type PacketInfo (line 17) | pub(super) struct PacketInfo {
  function calculate_packet_info (line 32) | pub(super) fn calculate_packet_info(

FILE: src/canvas/widgets/network_basic.rs
  method draw_basic_network (line 19) | pub fn draw_basic_network(

FILE: src/canvas/widgets/network_graph.rs
  method draw_network (line 27) | pub fn draw_network(
  method draw_network_graph (line 59) | pub fn draw_network_graph(
  method draw_old_network_labels (line 285) | fn draw_old_network_labels(
  function check_network_height_cache (line 374) | fn check_network_height_cache(
  function adjust_network_data_point (line 399) | fn adjust_network_data_point(max_entry: f64, config: &AppConfigFields) -...

FILE: src/canvas/widgets/process_table.rs
  constant SORT_MENU_WIDTH (line 19) | const SORT_MENU_WIDTH: u16 = 7;
  method draw_process (line 25) | pub fn draw_process(
  method draw_processes_table (line 72) | fn draw_processes_table(
  method draw_search_field (line 106) | fn draw_search_field(
  method draw_sort_table (line 299) | fn draw_sort_table(

FILE: src/canvas/widgets/temperature_table.rs
  method draw_temp_table (line 12) | pub fn draw_temp_table(

FILE: src/collection.rs
  type Data (line 40) | pub struct Data {
    method cleanup (line 87) | pub fn cleanup(&mut self) {
  method default (line 62) | fn default() -> Self {
  type SysinfoSource (line 120) | pub struct SysinfoSource {
  method default (line 133) | fn default() -> Self {
  type DataCollector (line 150) | pub struct DataCollector {
    method new (line 196) | pub fn new(filters: DataFilters) -> Self {
    method run_less_routine_tasks (line 243) | fn run_less_routine_tasks(&mut self) {
    method set_collection (line 258) | pub fn set_collection(&mut self, used_widgets: UsedWidgets) {
    method set_use_current_cpu_total (line 262) | pub fn set_use_current_cpu_total(&mut self, use_current_cpu_total: boo...
    method set_unnormalized_cpu (line 266) | pub fn set_unnormalized_cpu(&mut self, unnormalized_cpu: bool) {
    method set_show_average_cpu (line 270) | pub fn set_show_average_cpu(&mut self, show_average_cpu: bool) {
    method set_get_process_threads (line 274) | pub fn set_get_process_threads(&mut self, get_process_threads: bool) {
    method set_free_arc_mem (line 279) | pub fn set_free_arc_mem(&mut self, free_mem: bool) {
    method refresh_sysinfo_data (line 290) | fn refresh_sysinfo_data(&mut self) {
    method update_data (line 355) | pub fn update_data(&mut self) {
    method update_gpus (line 387) | fn update_gpus(&mut self) {
    method update_cpu_usage (line 433) | fn update_cpu_usage(&mut self) {
    method update_processes (line 445) | fn update_processes(&mut self) {
    method update_temps (line 458) | fn update_temps(&mut self) {
    method update_memory_usage (line 475) | fn update_memory_usage(&mut self) {
    method update_network_usage (line 522) | fn update_network_usage(&mut self) {
    method update_batteries (line 550) | fn update_batteries(&mut self) {
    method update_disks (line 599) | fn update_disks(&mut self) {
    method total_memory (line 608) | fn total_memory(&self) -> u64 {
  constant LESS_ROUTINE_TASK_TIME (line 193) | const LESS_ROUTINE_TASK_TIME: Duration = Duration::from_secs(60);
  function deserialize_xo (line 619) | fn deserialize_xo<T>(key: &str, data: &[u8]) -> Result<T, std::io::Error>
  function test_data_collection (line 636) | fn test_data_collection() {

FILE: src/collection/amd.rs
  type AmdGpuData (line 21) | pub struct AmdGpuData {
  type AmdGpuMemory (line 26) | pub struct AmdGpuMemory {
  type AmdGpuProc (line 32) | pub struct AmdGpuProc {
  function get_amd_devs (line 48) | fn get_amd_devs() -> Option<Vec<PathBuf>> {
  function get_amd_name (line 85) | pub fn get_amd_name(device_path: &Path) -> Option<String> {
  function get_amd_vram (line 123) | fn get_amd_vram(device_path: &Path) -> Option<AmdGpuMemory> {
  function diff_usage (line 153) | fn diff_usage(pre: u64, cur: u64, interval: &Duration) -> u64 {
  function get_amdgpu_pid_fds (line 169) | fn get_amdgpu_pid_fds(pid: Pid, device_path: Vec<PathBuf>) -> Option<Vec...
  function get_amdgpu_drm (line 195) | fn get_amdgpu_drm(device_path: &Path) -> Option<Vec<PathBuf>> {
  function get_amd_fdinfo (line 229) | fn get_amd_fdinfo(device_path: &Path) -> Option<IntMap<Pid, AmdGpuProc>> {
  function get_amd_vecs (line 330) | pub fn get_amd_vecs(widgets_to_harvest: &UsedWidgets, prev_time: Instant...

FILE: src/collection/amd/amd_gpu_marketing.rs
  constant AMDGPU_DEFAULT_NAME (line 3) | pub const AMDGPU_DEFAULT_NAME: &str = "AMD Radeon Graphics";
  constant AMD_GPU_MARKETING_NAME (line 5) | pub const AMD_GPU_MARKETING_NAME: &[(u32, u32, &str)] = &[

FILE: src/collection/batteries.rs
  type BatteryState (line 20) | pub enum BatteryState {
    method as_str (line 36) | pub fn as_str(&self) -> &'static str {
  type BatteryData (line 48) | pub struct BatteryData {
    method watt_consumption (line 60) | pub fn watt_consumption(&self) -> String {
    method health (line 64) | pub fn health(&self) -> String {
  function refresh_batteries (line 69) | pub fn refresh_batteries(manager: &Manager, batteries: &mut [Battery]) -...

FILE: src/collection/cpu.rs
  type LoadAvgHarvest (line 6) | pub type LoadAvgHarvest = [f32; 3];
  type CpuDataType (line 9) | pub enum CpuDataType {
  type CpuData (line 15) | pub struct CpuData {
  type CpuHarvest (line 20) | pub type CpuHarvest = Vec<CpuData>;

FILE: src/collection/cpu/sysinfo.rs
  function get_cpu_data_list (line 9) | pub fn get_cpu_data_list(sys: &System, show_average_cpu: bool) -> Collec...
  function get_load_avg (line 34) | pub(crate) fn get_load_avg() -> crate::collection::cpu::LoadAvgHarvest {

FILE: src/collection/disks.rs
  type DiskHarvest (line 36) | pub struct DiskHarvest {
  type IoData (line 51) | pub struct IoData {
  type IoHarvest (line 56) | pub type IoHarvest = HashMap<String, Option<IoData>>;
  function keep_disk_entry (line 102) | pub fn keep_disk_entry(
  function run_filter (line 137) | fn run_filter(disk_filter: &Option<Filter>, mount_filter: &Option<Filter...
  function test_keeping_disk_entry (line 160) | fn test_keeping_disk_entry() {

FILE: src/collection/disks/freebsd.rs
  type StorageSystemInformation (line 13) | struct StorageSystemInformation {
  type FileSystem (line 19) | struct FileSystem {
  function get_io_usage (line 27) | pub fn get_io_usage() -> CollectionResult<IoHarvest> {
  function get_disk_usage (line 59) | pub fn get_disk_usage(collector: &DataCollector) -> CollectionResult<Vec...
  function get_disk_info (line 85) | fn get_disk_info() -> io::Result<StorageSystemInformation> {

FILE: src/collection/disks/io_counters.rs
  type IoCounters (line 4) | pub struct IoCounters {
    method new (line 11) | pub fn new(name: String, read_bytes: u64, write_bytes: u64) -> Self {
    method device_name (line 19) | pub(crate) fn device_name(&self) -> &OsStr {
    method read_bytes (line 23) | pub(crate) fn read_bytes(&self) -> u64 {
    method write_bytes (line 27) | pub(crate) fn write_bytes(&self) -> u64 {

FILE: src/collection/disks/other.rs
  function get_disk_usage (line 6) | pub(crate) fn get_disk_usage(collector: &DataCollector) -> anyhow::Resul...

FILE: src/collection/disks/unix.rs
  function get_disk_usage (line 31) | pub fn get_disk_usage(collector: &DataCollector) -> anyhow::Result<Vec<D...

FILE: src/collection/disks/unix/file_systems.rs
  type FileSystem (line 12) | pub enum FileSystem {
    method is_physical (line 80) | pub fn is_physical(&self) -> bool {
    method is_virtual (line 87) | pub fn is_virtual(&self) -> bool {
    method as_str (line 94) | pub fn as_str(&self) -> &str {
  type Err (line 122) | type Err = anyhow::Error;
  method from_str (line 125) | fn from_str(s: &str) -> anyhow::Result<Self> {
  function file_system_from_str (line 180) | fn file_system_from_str() {

FILE: src/collection/disks/unix/linux/counters.rs
  constant DISK_SECTOR_SIZE (line 24) | const DISK_SECTOR_SIZE: u64 = 512;
  type Err (line 27) | type Err = anyhow::Error;
  method from_str (line 38) | fn from_str(s: &str) -> anyhow::Result<IoCounters> {
  function io_stats (line 68) | pub fn io_stats() -> anyhow::Result<Vec<IoCounters>> {

FILE: src/collection/disks/unix/linux/partition.rs
  type Partition (line 18) | pub(crate) struct Partition {
    method device (line 27) | pub fn device(&self) -> Option<&str> {
    method mount_point (line 33) | pub fn mount_point(&self) -> &Path {
    method fs_type (line 39) | pub fn fs_type(&self) -> &FileSystem {
    method get_device_name (line 44) | pub fn get_device_name(&self) -> String {
    method usage (line 78) | pub fn usage(&self) -> anyhow::Result<Usage> {
  function fix_mount_point (line 107) | fn fix_mount_point(s: &str) -> String {
  type Err (line 120) | type Err = anyhow::Error;
  method from_str (line 122) | fn from_str(line: &str) -> anyhow::Result<Partition> {
  function partitions (line 157) | pub(crate) fn partitions() -> anyhow::Result<Vec<Partition>> {
  function physical_partitions (line 183) | pub(crate) fn physical_partitions() -> anyhow::Result<Vec<Partition>> {
  function test_fix_mount_point (line 214) | fn test_fix_mount_point() {

FILE: src/collection/disks/unix/macos/counters.rs
  function get_device_io (line 6) | fn get_device_io(device: io_kit::IoObject) -> anyhow::Result<IoCounters> {
  function io_stats (line 48) | pub fn io_stats() -> anyhow::Result<Vec<IoCounters>> {

FILE: src/collection/disks/unix/macos/io_kit/bindings.rs
  type io_object_t (line 16) | pub type io_object_t = mach_port_t;
  type io_iterator_t (line 19) | pub type io_iterator_t = io_object_t;
  type io_registry_entry_t (line 21) | pub type io_registry_entry_t = io_object_t;
  type IOOptionBits (line 23) | pub type IOOptionBits = u32;
  constant kIOMasterPortDefault (line 27) | pub const kIOMasterPortDefault: mach_port_t = MACH_PORT_NULL;
  constant kIOServicePlane (line 30) | pub const kIOServicePlane: &str = "IOService\0";
  constant kIOMediaClass (line 33) | pub const kIOMediaClass: &str = "IOMedia\0";
  function IOServiceGetMatchingServices (line 39) | pub fn IOServiceGetMatchingServices(
  function IOServiceMatching (line 43) | pub fn IOServiceMatching(name: *const c_char) -> CFMutableDictionaryRef;
  function IOIteratorNext (line 45) | pub fn IOIteratorNext(iterator: io_iterator_t) -> io_object_t;
  function IOObjectRelease (line 47) | pub fn IOObjectRelease(obj: io_object_t) -> kern_return_t;
  function IORegistryEntryGetParentEntry (line 49) | pub fn IORegistryEntryGetParentEntry(
  function IORegistryEntryCreateCFProperties (line 56) | pub fn IORegistryEntryCreateCFProperties(

FILE: src/collection/disks/unix/macos/io_kit/io_disks.rs
  function get_disks (line 6) | pub fn get_disks() -> anyhow::Result<IoIterator> {

FILE: src/collection/disks/unix/macos/io_kit/io_iterator.rs
  type IoIterator (line 12) | pub struct IoIterator(io_iterator_t);
    method from (line 15) | fn from(iter: io_iterator_t) -> IoIterator {
  type Target (line 21) | type Target = io_iterator_t;
  method deref (line 23) | fn deref(&self) -> &Self::Target {
  method deref_mut (line 29) | fn deref_mut(&mut self) -> &mut Self::Target {
  type Item (line 35) | type Item = IoObject;
  method next (line 37) | fn next(&mut self) -> Option<Self::Item> {
  method drop (line 50) | fn drop(&mut self) {

FILE: src/collection/disks/unix/macos/io_kit/io_object.rs
  type IoObject (line 22) | pub struct IoObject(io_object_t);
    method properties (line 26) | pub fn properties(&self) -> anyhow::Result<CFDictionary<CFString, CFTy...
    method service_parent (line 51) | pub fn service_parent(&self) -> anyhow::Result<IoObject> {
    method from (line 77) | fn from(obj: io_object_t) -> IoObject {
  method drop (line 83) | fn drop(&mut self) {
  function get_dict (line 91) | pub fn get_dict(
  function get_i64 (line 112) | pub fn get_i64(
  function get_string (line 129) | pub fn get_string(

FILE: src/collection/disks/unix/other/bindings.rs
  constant MNT_NOWAIT (line 6) | const MNT_NOWAIT: libc::c_int = 2;
  function getfsstat64 (line 10) | fn getfsstat64(buf: *mut libc::statfs, bufsize: libc::c_int, flags: libc...
  function mounts (line 15) | pub(crate) fn mounts() -> anyhow::Result<Vec<libc::statfs>> {

FILE: src/collection/disks/unix/other/partition.rs
  type Partition (line 13) | pub(crate) struct Partition {
    method mount_point (line 22) | pub fn mount_point(&self) -> &Path {
    method fs_type (line 28) | pub fn fs_type(&self) -> &FileSystem {
    method usage (line 33) | pub fn usage(&self) -> anyhow::Result<Usage> {
    method get_device_name (line 51) | pub fn get_device_name(&self) -> String {
  function partitions_iter (line 56) | fn partitions_iter() -> anyhow::Result<impl Iterator<Item = Partition>> {
  function partitions (line 89) | pub(crate) fn partitions() -> anyhow::Result<Vec<Partition>> {
  function physical_partitions (line 95) | pub(crate) fn physical_partitions() -> anyhow::Result<Vec<Partition>> {

FILE: src/collection/disks/unix/usage.rs
  type Usage (line 1) | pub struct Usage(libc::statvfs);
    method new (line 7) | pub(crate) fn new(vfs: libc::statvfs) -> Self {
    method total (line 12) | pub fn total(&self) -> u64 {
    method available (line 18) | pub fn available(&self) -> u64 {
    method used (line 25) | pub fn used(&self) -> u64 {
    method free (line 32) | pub fn free(&self) -> u64 {

FILE: src/collection/disks/windows.rs
  function io_stats (line 12) | pub(crate) fn io_stats() -> anyhow::Result<Vec<IoCounters>> {
  function get_disk_usage (line 28) | pub(crate) fn get_disk_usage(collector: &DataCollector) -> anyhow::Resul...

FILE: src/collection/disks/windows/bindings.rs
  function volume_io (line 28) | fn volume_io(volume: &Path) -> anyhow::Result<DISK_PERFORMANCE> {
  function current_volume (line 93) | fn current_volume(buffer: &[u16]) -> PathBuf {
  function close_find_handle (line 100) | fn close_find_handle(handle: HANDLE) -> anyhow::Result<()> {
  function all_volume_io (line 111) | pub(crate) fn all_volume_io() -> anyhow::Result<Vec<anyhow::Result<(DISK...
  function volume_name_from_mount (line 153) | pub(crate) fn volume_name_from_mount(mount: &str) -> anyhow::Result<Stri...

FILE: src/collection/disks/zfs_io_counters.rs
  function zfs_io_stats (line 6) | pub fn zfs_io_stats() -> anyhow::Result<Vec<IoCounters>> {
  function zfs_io_stats (line 62) | pub fn zfs_io_stats() -> anyhow::Result<Vec<IoCounters>> {

FILE: src/collection/error.rs
  type CollectionError (line 5) | pub enum CollectionError {
    method fmt (line 18) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    method from (line 37) | fn from(err: std::io::Error) -> Self {
    method from (line 43) | fn from(msg: &'static str) -> Self {
  type CollectionResult (line 34) | pub(crate) type CollectionResult<T> = Result<T, CollectionError>;

FILE: src/collection/linux/utils.rs
  function is_device_awake (line 9) | pub fn is_device_awake(device: &Path) -> bool {

FILE: src/collection/memory.rs
  type MemData (line 22) | pub struct MemData {
    method percentage (line 30) | pub fn percentage(&self) -> f64 {

FILE: src/collection/memory/arc.rs
  function get_arc_usage (line 5) | pub(crate) fn get_arc_usage() -> Option<(MemData, u64)> {

FILE: src/collection/memory/sysinfo.rs
  function get_usage (line 10) | fn get_usage(used: u64, total: u64) -> Option<MemData> {
  function get_ram_usage (line 18) | pub(crate) fn get_ram_usage(sys: &System) -> Option<MemData> {
  function get_swap_usage (line 24) | pub(crate) fn get_swap_usage(sys: &System) -> Option<MemData> {
  function get_cache_usage (line 36) | pub(crate) fn get_cache_usage(sys: &System) -> Option<MemData> {

FILE: src/collection/memory/windows.rs
  function get_swap_usage (line 28) | pub(crate) fn get_swap_usage(sys: &System) -> Option<MemData> {
  function test_windows_get_swap_usage (line 83) | fn test_windows_get_swap_usage() {

FILE: src/collection/network.rs
  type NetworkHarvest (line 8) | pub struct NetworkHarvest {
    method first_run_cleanup (line 20) | pub fn first_run_cleanup(&mut self) {

FILE: src/collection/network/sysinfo.rs
  function get_network_data (line 12) | pub fn get_network_data(

FILE: src/collection/nvidia.rs
  type GpusData (line 15) | pub struct GpusData {
  function init_nvml (line 28) | fn init_nvml() -> Result<Nvml, NvmlError> {
  function get_nvidia_vecs (line 46) | pub fn get_nvidia_vecs(

FILE: src/collection/processes.rs
  type Bytes (line 49) | pub type Bytes = u64;
  type ProcessType (line 54) | pub enum ProcessType {
    method is_thread (line 69) | pub fn is_thread(&self) -> bool {
    method is_kernel (line 74) | pub fn is_kernel(&self) -> bool {
  type ProcessHarvest (line 80) | pub struct ProcessHarvest {
  method get_processes (line 163) | pub(crate) fn get_processes(&mut self) -> CollectionResult<Vec<ProcessHa...
  function process_status_str (line 184) | pub(super) fn process_status_str(status: ProcessStatus) -> &'static str {

FILE: src/collection/processes/freebsd.rs
  type ProcessInformation (line 12) | struct ProcessInformation {
  type ProcessRow (line 18) | struct ProcessRow {
  type FreeBSDProcessExt (line 25) | pub(crate) struct FreeBSDProcessExt;
  method has_backup_proc_cpu_fn (line 29) | fn has_backup_proc_cpu_fn() -> bool {
  method backup_proc_cpu (line 33) | fn backup_proc_cpu(pids: &[Pid]) -> io::Result<IntMap<Pid, f32>> {
  function pid (line 55) | fn pid<'de, D>(deserializer: D) -> Result<i32, D::Error>
  function percent_cpu (line 63) | fn percent_cpu<'de, D>(deserializer: D) -> Result<f32, D::Error>

FILE: src/collection/processes/linux/mod.rs
  constant MAX_STAT_NAME_LEN (line 24) | const MAX_STAT_NAME_LEN: usize = 15;
  type PrevProcDetails (line 27) | pub struct PrevProcDetails {
  function fetch_cpu_usage (line 35) | fn fetch_cpu_usage(line: &str) -> (f64, f64) {
  type CpuUsage (line 60) | struct CpuUsage {
  function cpu_usage_calculation (line 68) | fn cpu_usage_calculation(
  function get_linux_cpu_usage (line 116) | fn get_linux_cpu_usage(
  function read_proc (line 136) | fn read_proc(
  function binary_name_from_cmdline (line 302) | fn binary_name_from_cmdline(cmdline: &str) -> String {
  type PrevProc (line 323) | pub(crate) struct PrevProc<'a> {
  type ProcHarvestOptions (line 328) | pub(crate) struct ProcHarvestOptions {
  function is_str_numeric (line 334) | fn is_str_numeric(s: &str) -> bool {
  type ReadProcArgs (line 340) | pub(crate) struct ReadProcArgs {
  function linux_process_data (line 350) | pub(crate) fn linux_process_data(
  function test_proc_cpu_parse (line 504) | fn test_proc_cpu_parse() {
  function test_name_from_cmdline (line 543) | fn test_name_from_cmdline() {

FILE: src/collection/processes/linux/process.rs
  function next_part (line 24) | fn next_part<'a>(iter: &mut impl Iterator<Item = &'a str>) -> Result<&'a...
  type Stat (line 35) | pub(crate) struct Stat {
    method from_file (line 78) | fn from_file(mut f: File, buffer: &mut String) -> anyhow::Result<Stat> {
    method rss_bytes (line 151) | pub fn rss_bytes(&self) -> u64 {
  type Io (line 160) | pub(crate) struct Io {
    method from_file (line 167) | fn from_file(f: File, buffer: &mut String) -> anyhow::Result<Io> {
  type Process (line 237) | pub(crate) struct Process {
    method from_path (line 263) | pub(crate) fn from_path(
  function reset (line 246) | fn reset(root: &mut PathBuf, buffer: &mut String) {
  function cmdline (line 335) | fn cmdline(root: &mut PathBuf, fd: &OwnedFd, buffer: &mut String) -> any...
  function open_at (line 345) | fn open_at(root: &mut PathBuf, child: &str, fd: &OwnedFd) -> anyhow::Res...
  function threads (line 353) | fn threads(root: &mut PathBuf, pid: Pid, get_threads: bool) -> Vec<PathB...

FILE: src/collection/processes/macos.rs
  type MacOSProcessExt (line 13) | pub(crate) struct MacOSProcessExt;
  method has_backup_proc_cpu_fn (line 17) | fn has_backup_proc_cpu_fn() -> bool {
  method backup_proc_cpu (line 21) | fn backup_proc_cpu(pids: &[Pid]) -> io::Result<IntMap<Pid, f32>> {
  method parent_pid (line 50) | fn parent_pid(process_val: &sysinfo::Process) -> Option<Pid> {
  function fallback_macos_ppid (line 58) | fn fallback_macos_ppid(pid: Pid) -> Option<Pid> {

FILE: src/collection/processes/macos/sysctl_bindings.rs
  type kinfo_proc (line 16) | pub(crate) struct kinfo_proc {
  type p_st1 (line 23) | pub struct p_st1 {
  type extern_proc (line 40) | pub(crate) struct extern_proc {
  constant WMESGLEN (line 165) | const WMESGLEN: usize = 7;
  constant COMAPT_MAXLOGNAME (line 166) | const COMAPT_MAXLOGNAME: usize = 12;
  type caddr_t (line 170) | type caddr_t = *const libc::c_char;
  type segsz_t (line 174) | type segsz_t = i32;
  type fixpt_t (line 178) | type fixpt_t = u32;
  type pcred (line 182) | pub(crate) struct pcred {
  type vmspace (line 194) | pub(crate) struct vmspace {
  type eproc (line 203) | pub(crate) struct eproc {
  function kinfo_process (line 265) | pub(crate) fn kinfo_process(pid: Pid) -> Result<kinfo_proc> {
  function test_struct_sizes (line 306) | fn test_struct_sizes() {

FILE: src/collection/processes/unix/process_ext.rs
  function get_nice (line 15) | fn get_nice(pid: Pid) -> i32 {
  function get_priority (line 29) | fn get_priority(pid: Pid) -> i32 {
  type UnixProcessExt (line 67) | pub(crate) trait UnixProcessExt {
    method sysinfo_process_data (line 68) | fn sysinfo_process_data(
    method has_backup_proc_cpu_fn (line 190) | fn has_backup_proc_cpu_fn() -> bool {
    method backup_proc_cpu (line 194) | fn backup_proc_cpu(_pids: &[Pid]) -> io::Result<IntMap<Pid, f32>> {
    method parent_pid (line 198) | fn parent_pid(process_val: &sysinfo::Process) -> Option<Pid> {
  function convert_process_status_to_char (line 203) | fn convert_process_status_to_char(status: ProcessStatus) -> char {

FILE: src/collection/processes/unix/user_table.rs
  type UserTable (line 8) | pub struct UserTable {
    method uid_to_username (line 15) | pub fn uid_to_username(&mut self, uid: libc::uid_t) -> CollectionResul...

FILE: src/collection/processes/windows.rs
  function get_priority (line 18) | fn get_priority(pid: u32) -> anyhow::Result<i32> {
  function sysinfo_process_data (line 42) | pub fn sysinfo_process_data(

FILE: src/collection/temperature.rs
  type TempSensorData (line 17) | pub struct TempSensorData {

FILE: src/collection/temperature/linux.rs
  constant EMPTY_NAME (line 16) | const EMPTY_NAME: &str = "Unknown";
  type HwmonResults (line 20) | struct HwmonResults {
  function parse_temp (line 27) | fn parse_temp(path: &Path) -> Result<f32> {
  function get_hwmon_candidates (line 33) | fn get_hwmon_candidates() -> (HashSet<PathBuf>, usize) {
  function read_to_string_lossy (line 95) | fn read_to_string_lossy<P: AsRef<Path>>(path: P) -> Option<String> {
  function humanize_name (line 102) | fn humanize_name(name: String, sensor_name: Option<&String>) -> String {
  function counted_name (line 110) | fn counted_name(seen_names: &mut HashMap<String, u32>, name: String) -> ...
  function uppercase_first_letter (line 120) | fn uppercase_first_letter(s: &mut str) {
  function finalize_name (line 126) | fn finalize_name(
  function hwmon_temperatures (line 203) | fn hwmon_temperatures(filter: &Option<Filter>) -> HwmonResults {
  function add_thermal_zone_temperatures (line 353) | fn add_thermal_zone_temperatures(temperatures: &mut Vec<TempSensorData>,...
  function get_temperature_data (line 394) | pub fn get_temperature_data(filter: &Option<Filter>) -> Result<Option<Ve...
  function test_finalize_name (line 411) | fn test_finalize_name() {

FILE: src/collection/temperature/sysinfo.rs
  function get_temperature_data (line 8) | pub fn get_temperature_data(

FILE: src/constants.rs
  constant DEFAULT_WIDGET_ID (line 6) | pub const DEFAULT_WIDGET_ID: u64 = 56709;
  constant TABLE_GAP_HEIGHT_LIMIT (line 10) | pub const TABLE_GAP_HEIGHT_LIMIT: u16 = 7;
  constant HELP_CONTENTS_TEXT (line 13) | const HELP_CONTENTS_TEXT: [&str; 10] = [
  constant GENERAL_HELP_TEXT (line 28) | pub(crate) const GENERAL_HELP_TEXT: [&str; 28] = [
  constant CPU_HELP_TEXT (line 59) | const CPU_HELP_TEXT: [&str; 2] = [
  constant PROCESS_HELP_TEXT (line 64) | const PROCESS_HELP_TEXT: [&str; 20] = [
  constant SEARCH_HELP_TEXT (line 87) | const SEARCH_HELP_TEXT: [&str; 51] = [
  constant SORT_HELP_TEXT (line 141) | const SORT_HELP_TEXT: [&str; 6] = [
  constant TEMP_HELP_WIDGET (line 150) | const TEMP_HELP_WIDGET: [&str; 3] = [
  constant DISK_HELP_WIDGET (line 156) | const DISK_HELP_WIDGET: [&str; 9] = [
  constant BATTERY_HELP_TEXT (line 168) | const BATTERY_HELP_TEXT: [&str; 3] = [
  constant BASIC_MEM_HELP_TEXT (line 174) | const BASIC_MEM_HELP_TEXT: [&str; 2] = [
  constant HELP_TEXT (line 179) | pub(crate) const HELP_TEXT: [&[&str]; HELP_CONTENTS_TEXT.len()] = [
  constant DEFAULT_LAYOUT (line 192) | pub(crate) const DEFAULT_LAYOUT: &str = r#"
  constant DEFAULT_BATTERY_LAYOUT (line 217) | pub(crate) const DEFAULT_BATTERY_LAYOUT: &str = r#"
  constant CONFIG_TEXT (line 247) | pub(crate) const CONFIG_TEXT: &str = r#"# This is a default config file ...
  function help_menu_matches_entry_len (line 571) | fn help_menu_matches_entry_len() {
  function help_menu_text_has_sections (line 581) | fn help_menu_text_has_sections() {
  function check_default_config (line 593) | fn check_default_config() {

FILE: src/event.rs
  type BottomEvent (line 14) | pub enum BottomEvent {
  type CollectionThreadEvent (line 26) | pub enum CollectionThreadEvent {
  function handle_mouse_event (line 31) | pub fn handle_mouse_event(event: MouseEvent, app: &mut App) {
  function handle_key_event_or_break (line 53) | pub fn handle_key_event_or_break(

FILE: src/lib.rs
  function try_drawing (line 63) | fn try_drawing(
  function cleanup_terminal (line 76) | fn cleanup_terminal(
  function check_if_terminal (line 94) | fn check_if_terminal() {
  function reset_stdout (line 108) | pub fn reset_stdout() {
  function panic_hook (line 122) | fn panic_hook(panic_info: &PanicHookInfo<'_>) {
  function create_input_thread (line 146) | fn create_input_thread(
  function create_collection_thread (line 221) | fn create_collection_thread(
  function start_bottom (line 294) | pub fn start_bottom(enable_error_hook: &mut bool) -> anyhow::Result<()> {

FILE: src/options.rs
  constant DEFAULT_CONFIG_FILE_LOCATION (line 78) | const DEFAULT_CONFIG_FILE_LOCATION: &str = "bottom/bottom.toml";
  function get_config_path (line 92) | fn get_config_path(override_config_path: Option<&Path>) -> Option<PathBu...
  function create_config_at_path (line 140) | fn create_config_at_path(path: &Path) -> anyhow::Result<Config> {
  function get_or_create_config (line 161) | pub(crate) fn get_or_create_config(config_path: Option<&Path>) -> anyhow...
  function init_app (line 213) | pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App,...
  function get_widget_layout (line 558) | fn get_widget_layout(
  function try_parse_ms (line 623) | fn try_parse_ms(s: &str) -> Result<u64, ()> {
  function get_update_rate (line 708) | fn get_update_rate(args: &BottomArgs, config: &Config) -> OptionResult<u...
  function get_temperature (line 721) | fn get_temperature(args: &BottomArgs, config: &Config) -> OptionResult<T...
  function get_show_average_cpu (line 737) | fn get_show_average_cpu(args: &BottomArgs, config: &Config) -> bool {
  function get_default_cpu_selection (line 750) | fn get_default_cpu_selection(args: &BottomArgs, config: &Config) -> conf...
  function get_dedicated_avg_row (line 760) | fn get_dedicated_avg_row(config: &Config) -> bool {
  function get_default_time_value (line 769) | fn get_default_time_value(
  function get_time_interval (line 788) | fn get_time_interval(args: &BottomArgs, config: &Config, retention_ms: u...
  function get_default_widget_and_count (line 804) | fn get_default_widget_and_count(
  function get_use_battery (line 855) | fn get_use_battery(args: &BottomArgs, config: &Config) -> bool {
  function get_use_battery (line 878) | fn get_use_battery(_args: &BottomArgs, _config: &Config) -> bool {
  function get_enable_gpu (line 883) | fn get_enable_gpu(args: &BottomArgs, config: &Config) -> bool {
  function get_enable_gpu (line 896) | fn get_enable_gpu(_: &BottomArgs, _: &Config) -> bool {
  function get_enable_cache_memory (line 901) | fn get_enable_cache_memory(args: &BottomArgs, config: &Config) -> bool {
  function get_enable_cache_memory (line 914) | fn get_enable_cache_memory(_args: &BottomArgs, _config: &Config) -> bool {
  function get_ignore_list (line 918) | fn get_ignore_list(ignore_list: &Option<IgnoreList>) -> OptionResult<Opt...
  function get_network_unit_type (line 954) | fn get_network_unit_type(args: &BottomArgs, config: &Config) -> DataUnit {
  function get_network_scale_type (line 968) | fn get_network_scale_type(args: &BottomArgs, config: &Config) -> AxisSca...
  function get_network_show_packets (line 982) | fn get_network_show_packets(args: &BottomArgs, config: &Config) -> bool {
  function get_retention (line 994) | fn get_retention(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
  function get_network_legend_position (line 1010) | fn get_network_legend_position(
  function get_memory_legend_position (line 1034) | fn get_memory_legend_position(
  function verify_try_parse_ms (line 1073) | fn verify_try_parse_ms() {
  function matches_human_times (line 1092) | fn matches_human_times() {
  function matches_number_times (line 1117) | fn matches_number_times() {
  function config_human_times (line 1142) | fn config_human_times() {
  function config_number_times_as_string (line 1172) | fn config_number_times_as_string() {
  function config_number_times_as_num (line 1202) | fn config_number_times_as_num() {
  function create_app (line 1231) | fn create_app(args: BottomArgs) -> App {
  function verify_cli_options_build (line 1240) | fn verify_cli_options_build() {
  function test_get_config_path_macos (line 1284) | fn test_get_config_path_macos() {

FILE: src/options/args.rs
  constant TEMPLATE (line 13) | const TEMPLATE: &str = indoc! {
  constant USAGE (line 24) | const USAGE: &str = "btm [OPTIONS]";
  constant VERSION (line 26) | const VERSION: &str = match option_env!("NIGHTLY_VERSION") {
  constant CHART_WIDGET_POSITIONS (line 31) | const CHART_WIDGET_POSITIONS: [&str; 9] = [
  type BottomArgs (line 56) | pub struct BottomArgs {
  type GeneralArgs (line 93) | pub struct GeneralArgs {
  type ProcessArgs (line 295) | pub struct ProcessArgs {
  type TemperatureArgs (line 424) | pub struct TemperatureArgs {
  type CpuDefault (line 457) | pub enum CpuDefault {
  method value_variants (line 464) | fn value_variants<'a>() -> &'a [Self] {
  method to_possible_value (line 468) | fn to_possible_value(&self) -> Option<PossibleValue> {
  type CpuArgs (line 479) | pub struct CpuArgs {
  type MemoryArgs (line 512) | pub struct MemoryArgs {
  type NetworkArgs (line 545) | pub struct NetworkArgs {
  type BatteryArgs (line 608) | pub struct BatteryArgs {
  type GpuArgs (line 624) | pub struct GpuArgs {
  type StyleArgs (line 632) | pub struct StyleArgs {
  type OtherArgs (line 665) | pub struct OtherArgs {
  function get_args (line 674) | pub fn get_args() -> BottomArgs {
  function build_cmd (line 680) | pub(crate) fn build_cmd() -> Command {
  function verify_cli (line 691) | fn verify_cli() {
  function no_default_help_heading (line 696) | fn no_default_help_heading() {
  function catch_incorrect_long_args (line 715) | fn catch_incorrect_long_args() {
  function catch_missing_hyphen_alias (line 733) | fn catch_missing_hyphen_alias() {

FILE: src/options/config.rs
  type Config (line 25) | pub struct Config {
  type StringOrNum (line 40) | pub(crate) enum StringOrNum {
    method from (line 46) | fn from(value: String) -> Self {
    method from (line 52) | fn from(value: u64) -> Self {
  function test_integration_valid_configs (line 64) | fn test_integration_valid_configs() {

FILE: src/options/config/cpu.rs
  type CpuDefault (line 8) | pub(crate) enum CpuDefault {
  type CpuConfig (line 19) | pub(crate) struct CpuConfig {
  function default_cpu_default (line 30) | fn default_cpu_default() {
  function all_cpu_default (line 42) | fn all_cpu_default() {
  function avg_cpu_default (line 56) | fn avg_cpu_default() {
  function average_cpu_default (line 71) | fn average_cpu_default() {

FILE: src/options/config/disk.rs
  type DiskConfig (line 10) | pub(crate) struct DiskConfig {
  function none_column_setting (line 27) | fn none_column_setting() {
  function empty_column_setting (line 34) | fn empty_column_setting() {
  function valid_disk_column_settings (line 41) | fn valid_disk_column_settings() {
  function bad_disk_column_settings (line 47) | fn bad_disk_column_settings() {

FILE: src/options/config/flags.rs
  type GeneralConfig (line 9) | pub(crate) struct GeneralConfig {

FILE: src/options/config/ignore_list.rs
  function default_as_true (line 4) | fn default_as_true() -> bool {
  type IgnoreList (line 11) | pub struct IgnoreList {

FILE: src/options/config/layout.rs
  type Row (line 11) | pub struct Row {
    method convert_row_to_bottom_row (line 57) | pub fn convert_row_to_bottom_row(
  function new_cpu (line 16) | fn new_cpu(cpu_left_legend: bool, iter_id: &mut u64) -> BottomColRow {
  function new_proc_sort (line 41) | fn new_proc_sort(sort_id: u64) -> BottomWidget {
  function new_proc (line 47) | fn new_proc(proc_id: u64) -> BottomWidget {
  function new_proc_search (line 51) | fn new_proc_search(search_id: u64) -> BottomWidget {
  type RowChildren (line 224) | pub enum RowChildren {
  type FinalWidget (line 236) | pub struct FinalWidget {
  constant PROC_LAYOUT (line 253) | const PROC_LAYOUT: &str = r#"
  function test_create_layout (line 269) | fn test_create_layout(
  function test_default_movement (line 302) | fn test_default_movement() {
  function test_default_battery_movement (line 374) | fn test_default_battery_movement() {
  function test_cpu_left_legend (line 422) | fn test_cpu_left_legend() {
  function test_default_widget_in_layout (line 465) | fn test_default_widget_in_layout() {
  function test_default_widget_by_option (line 515) | fn test_default_widget_by_option() {
  function test_proc_custom_layout (line 547) | fn test_proc_custom_layout() {

FILE: src/options/config/network.rs
  type NetworkConfig (line 9) | pub(crate) struct NetworkConfig {

FILE: src/options/config/process.rs
  type ProcessesConfig (line 9) | pub(crate) struct ProcessesConfig {
  function empty_column_setting (line 24) | fn empty_column_setting() {
  function to_columns (line 30) | fn to_columns(columns: Vec<ProcColumn>) -> Vec<ProcWidgetColumn> {
  function valid_process_column_config (line 38) | fn valid_process_column_config() {
  function bad_process_column_config (line 73) | fn bad_process_column_config() {
  function valid_process_column_config_2 (line 79) | fn valid_process_column_config_2() {

FILE: src/options/config/style.rs
  type ColorStr (line 33) | pub(crate) struct ColorStr(Cow<'static, str>);
  type TextStyleConfig (line 40) | pub(crate) enum TextStyleConfig {
  type StyleConfig (line 65) | pub(crate) struct StyleConfig {
  type Styles (line 98) | pub struct Styles {
    method new (line 139) | pub fn new(args: &BottomArgs, config: &Config) -> anyhow::Result<Self> {
    method from_theme (line 156) | fn from_theme(theme: &str) -> anyhow::Result<Self> {
    method set_styles_from_config (line 172) | fn set_styles_from_config(&mut self, config: &StyleConfig) -> OptionRe...
  method default (line 133) | fn default() -> Self {
  function default_selected_colour_works (line 247) | fn default_selected_colour_works() {
  function built_in_colour_schemes_work (line 272) | fn built_in_colour_schemes_work() {

FILE: src/options/config/style/battery.rs
  type BatteryStyle (line 9) | pub(crate) struct BatteryStyle {

FILE: src/options/config/style/borders.rs
  type WidgetBorderType (line 7) | pub(crate) enum WidgetBorderType {
    method deserialize (line 16) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  method from (line 34) | fn from(value: WidgetBorderType) -> Self {

FILE: src/options/config/style/cpu.rs
  type CpuStyle (line 9) | pub(crate) struct CpuStyle {

FILE: src/options/config/style/graphs.rs
  type GraphStyle (line 9) | pub(crate) struct GraphStyle {

FILE: src/options/config/style/memory.rs
  type MemoryStyle (line 10) | pub(crate) struct MemoryStyle {

FILE: src/options/config/style/network.rs
  type NetworkStyle (line 9) | pub(crate) struct NetworkStyle {

FILE: src/options/config/style/tables.rs
  type TableStyle (line 9) | pub(crate) struct TableStyle {

FILE: src/options/config/style/themes/default.rs
  method default_palette (line 10) | pub(crate) fn default_palette() -> Self {
  method default_light_palette (line 75) | pub fn default_light_palette() -> Self {
  function default_palettes_valid (line 121) | fn default_palettes_valid() {

FILE: src/options/config/style/themes/gruvbox.rs
  method gruvbox_palette (line 10) | pub(crate) fn gruvbox_palette() -> Self {
  method gruvbox_light_palette (line 75) | pub(crate) fn gruvbox_light_palette() -> Self {
  function gruvbox_palettes_valid (line 144) | fn gruvbox_palettes_valid() {

FILE: src/options/config/style/themes/nord.rs
  method nord_palette (line 10) | pub(crate) fn nord_palette() -> Self {
  method nord_light_palette (line 63) | pub(crate) fn nord_light_palette() -> Self {
  function nord_palettes_valid (line 120) | fn nord_palettes_valid() {

FILE: src/options/config/style/utils.rs
  function try_hex_to_colour (line 6) | pub(super) fn try_hex_to_colour(hex: &str) -> Result<Color, String> {
  function str_to_colour (line 42) | pub fn str_to_colour(input_val: &str) -> Result<Color, String> {
  function convert_rgb_to_color (line 56) | fn convert_rgb_to_color(rgb_str: &str) -> Result<Color, String> {
  function convert_name_to_colour (line 78) | fn convert_name_to_colour(color_name: &str) -> Result<Color, String> {
  function general_str_to_colour (line 275) | fn general_str_to_colour() {
  function invalid_colour_names (line 290) | fn invalid_colour_names() {
  function valid_colour_names (line 302) | fn valid_colour_names() {
  function valid_hex_colours (line 337) | fn valid_hex_colours() {
  function invalid_hex_colours (line 367) | fn invalid_hex_colours() {
  function test_rgb_colours (line 403) | fn test_rgb_colours() {
  type DummyConfig (line 419) | struct DummyConfig {
  type InnerDummyConfig (line 423) | struct InnerDummyConfig {
  method default (line 441) | fn default() -> Self {
  function test_set_colour (line 491) | fn test_set_colour() -> anyhow::Result<()> {
  function test_bad_set_colour (line 517) | fn test_bad_set_colour() {
  function test_set_multi_colours (line 532) | fn test_set_multi_colours() -> anyhow::Result<()> {
  function test_bad_set_list (line 547) | fn test_bad_set_list() {
  function test_set_style (line 562) | fn test_set_style() -> anyhow::Result<()> {
  function test_bad_text_1 (line 597) | fn test_bad_text_1() {
  function test_bad_text_2 (line 612) | fn test_bad_text_2() {

FILE: src/options/config/style/widgets.rs
  type WidgetStyle (line 9) | pub(crate) struct WidgetStyle {

FILE: src/options/config/temperature.rs
  type TempConfig (line 9) | pub(crate) struct TempConfig {

FILE: src/options/error.rs
  type OptionError (line 12) | pub enum OptionError {
    method config (line 20) | pub(crate) fn config<R: Into<Cow<'static, str>>>(reason: R) -> Self {
    method invalid_config_value (line 25) | pub(crate) fn invalid_config_value(value: &str) -> Self {
    method arg (line 32) | pub(crate) fn arg<R: Into<Cow<'static, str>>>(reason: R) -> Self {
    method invalid_arg_value (line 37) | pub(crate) fn invalid_arg_value(value: &str) -> Self {
    method other (line 44) | pub(crate) fn other<R: Into<Cow<'static, str>>>(reason: R) -> Self {
    method fmt (line 52) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    method from (line 66) | fn from(err: toml_edit::de::Error) -> Self {
    method from (line 72) | fn from(err: std::io::Error) -> Self {
  type OptionResult (line 49) | pub(crate) type OptionResult<T> = Result<T, OptionError>;

FILE: src/utils/cancellation_token.rs
  type CancellationToken (line 7) | pub(crate) struct CancellationToken {
    method cancel (line 27) | pub fn cancel(&self) {
    method try_check (line 41) | pub fn try_check(&self) -> Option<bool> {
    method sleep_with_cancellation (line 48) | pub fn sleep_with_cancellation(&self, duration: Duration) -> bool {
  method default (line 14) | fn default() -> Self {

FILE: src/utils/conversion.rs
  function get_binary_unit_and_denominator (line 13) | pub(crate) fn get_binary_unit_and_denominator(bytes: u64) -> (&'static s...
  function dec_bytes_per_second_string (line 27) | pub(crate) fn dec_bytes_per_second_string(value: u64) -> String {
  function test_dec_bytes_per_second_string (line 41) | fn test_dec_bytes_per_second_string() {

FILE: src/utils/data_units.rs
  type DataUnit (line 2) | pub enum DataUnit {
  constant KILO_LIMIT (line 8) | pub const KILO_LIMIT: u64 = 1000;
  constant MEGA_LIMIT (line 9) | pub const MEGA_LIMIT: u64 = 1_000_000;
  constant GIGA_LIMIT (line 10) | pub const GIGA_LIMIT: u64 = 1_000_000_000;
  constant TERA_LIMIT (line 11) | pub const TERA_LIMIT: u64 = 1_000_000_000_000;
  constant KIBI_LIMIT (line 12) | pub const KIBI_LIMIT: u64 = 1024;
  constant MEBI_LIMIT (line 13) | pub const MEBI_LIMIT: u64 = 1024 * 1024;
  constant GIBI_LIMIT (line 14) | pub const GIBI_LIMIT: u64 = 1024 * 1024 * 1024;
  constant TEBI_LIMIT (line 15) | pub const TEBI_LIMIT: u64 = 1024 * 1024 * 1024 * 1024;
  constant KILO_LIMIT_F64 (line 17) | pub const KILO_LIMIT_F64: f64 = 1000.0;
  constant MEGA_LIMIT_F64 (line 18) | pub const MEGA_LIMIT_F64: f64 = 1_000_000.0;
  constant GIGA_LIMIT_F64 (line 19) | pub const GIGA_LIMIT_F64: f64 = 1_000_000_000.0;
  constant TERA_LIMIT_F64 (line 20) | pub const TERA_LIMIT_F64: f64 = 1_000_000_000_000.0;
  constant KIBI_LIMIT_F64 (line 21) | pub const KIBI_LIMIT_F64: f64 = 1024.0;
  constant MEBI_LIMIT_F64 (line 22) | pub const MEBI_LIMIT_F64: f64 = 1024.0 * 1024.0;
  constant GIBI_LIMIT_F64 (line 23) | pub const GIBI_LIMIT_F64: f64 = 1024.0 * 1024.0 * 1024.0;
  constant TEBI_LIMIT_F64 (line 24) | pub const TEBI_LIMIT_F64: f64 = 1024.0 * 1024.0 * 1024.0 * 1024.0;
  constant LOG_MEGA_LIMIT (line 26) | pub const LOG_MEGA_LIMIT: f64 = 6.0;
  constant LOG_GIGA_LIMIT (line 27) | pub const LOG_GIGA_LIMIT: f64 = 9.0;
  constant LOG_TERA_LIMIT (line 28) | pub const LOG_TERA_LIMIT: f64 = 12.0;
  constant LOG_PETA_LIMIT (line 29) | pub const LOG_PETA_LIMIT: f64 = 15.0;
  constant LOG_MEBI_LIMIT (line 31) | pub const LOG_MEBI_LIMIT: f64 = 20.0;
  constant LOG_GIBI_LIMIT (line 32) | pub const LOG_GIBI_LIMIT: f64 = 30.0;
  constant LOG_TEBI_LIMIT (line 33) | pub const LOG_TEBI_LIMIT: f64 = 40.0;
  constant LOG_PEBI_LIMIT (line 34) | pub const LOG_PEBI_LIMIT: f64 = 50.0;
  function get_binary_bytes (line 40) | pub fn get_binary_bytes(bytes: u64) -> (f64, &'static str) {
  function get_decimal_bytes (line 54) | pub fn get_decimal_bytes(bytes: u64) -> (f64, &'static str) {
  function convert_bits (line 66) | pub fn convert_bits(bits: u64, base_two: bool) -> (f64, &'static str) {
  function convert_bytes (line 72) | pub fn convert_bytes(bytes: u64, base_two: bool) -> (f64, &'static str) {
  function get_unit_prefix (line 82) | pub fn get_unit_prefix(value: u64, base_two: bool) -> (f64, &'static str) {

FILE: src/utils/general.rs
  function sort_partial_fn (line 4) | pub(crate) const fn sort_partial_fn<T: PartialOrd>(is_descending: bool) ...
  function partial_ordering (line 14) | pub(crate) fn partial_ordering<T: PartialOrd>(a: T, b: T) -> Ordering {
  function partial_ordering_desc (line 23) | pub(crate) fn partial_ordering_desc<T: PartialOrd>(a: T, b: T) -> Orderi...
  type ClampExt (line 28) | pub(crate) trait ClampExt {
    method clamp_lower (line 32) | fn clamp_lower(&self, lower_bound: Self) -> Self;
    method clamp_upper (line 36) | fn clamp_upper(&self, upper_bound: Self) -> Self;
  function saturating_log2 (line 66) | pub(crate) fn saturating_log2(value: f64) -> f64 {
  function saturating_log10 (line 71) | pub(crate) fn saturating_log10(value: f64) -> f64 {
  function test_clamp_upper (line 80) | fn test_clamp_upper() {
  function test_clamp_lower (line 92) | fn test_clamp_lower() {
  function test_sort_partial_fn (line 104) | fn test_sort_partial_fn() {

FILE: src/utils/logging.rs
  function init_logger (line 8) | pub fn init_logger(
  function init_test_logger (line 148) | fn init_test_logger() {
  function test_logging_macros (line 161) | fn test_logging_macros() {
  function test_log_every_macros (line 173) | fn test_log_every_macros() {

FILE: src/utils/process_killer.rs
  type Process (line 17) | struct Process(HANDLE);
    method open (line 21) | fn open(pid: u32) -> anyhow::Result<Process> {
    method kill (line 29) | fn kill(self) -> anyhow::Result<()> {
  method drop (line 42) | fn drop(&mut self) {
  function kill_process_given_pid (line 52) | pub fn kill_process_given_pid(pid: Pid) -> anyhow::Result<()> {
  function kill_process_given_pid (line 61) | pub fn kill_process_given_pid(pid: Pid, signal: usize) -> anyhow::Result...

FILE: src/utils/strings.rs
  function truncate_to_text (line 8) | pub fn truncate_to_text<'a, U: Into<usize>>(content: &str, width: U) -> ...
  function test_multi_eq_ignore_ascii_case (line 40) | fn test_multi_eq_ignore_ascii_case() {

FILE: src/widgets/battery_info.rs
  type BatteryWidgetState (line 2) | pub struct BatteryWidgetState {

FILE: src/widgets/cpu_graph.rs
  type CpuWidgetColumn (line 19) | pub enum CpuWidgetColumn {
  method text (line 25) | fn text(&self) -> Cow<'static, str> {
  type CpuWidgetTableData (line 33) | pub enum CpuWidgetTableData {
    method from_cpu_data (line 39) | pub fn from_cpu_data(data: &CpuData) -> CpuWidgetTableData {
    method to_cell_text (line 48) | fn to_cell_text(
    method style_row (line 96) | fn style_row<'a>(&self, row: Row<'a>, painter: &Painter) -> Row<'a> {
    method column_widths (line 113) | fn column_widths<C: DataTableColumn<CpuWidgetColumn>>(
  type CpuWidgetState (line 123) | pub struct CpuWidgetState {
    method new (line 132) | pub(crate) fn new(
    method force_data_update (line 171) | pub fn force_data_update(&mut self) {
    method set_legend_data (line 175) | pub fn set_legend_data(&mut self, data: &[CpuData]) {

FILE: src/widgets/disk_table.rs
  type DiskWidgetData (line 19) | pub struct DiskWidgetData {
    method total_space (line 31) | fn total_space(&self) -> Cow<'static, str> {
    method free_space (line 40) | fn free_space(&self) -> Cow<'static, str> {
    method used_space (line 49) | fn used_space(&self) -> Cow<'static, str> {
    method free_percent (line 58) | fn free_percent(&self) -> Option<f64> {
    method used_percent (line 72) | fn used_percent(&self) -> Option<f64> {
    method io_read (line 86) | fn io_read(&self) -> Cow<'static, str> {
    method io_write (line 92) | fn io_write(&self) -> Cow<'static, str> {
    method to_cell_text (line 177) | fn to_cell_text(
    method column_widths (line 202) | fn column_widths<C: DataTableColumn<DiskColumn>>(data: &[Self], _colum...
  type DiskColumn (line 105) | pub enum DiskColumn {
    method deserialize (line 118) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    method get_schema_names (line 143) | pub fn get_schema_names(&self) -> &[&'static str] {
  method text (line 159) | fn text(&self) -> Cow<'static, str> {
  type DiskTableWidget (line 217) | pub struct DiskTableWidget {
    method new (line 298) | pub fn new(config: &AppConfigFields, palette: &Styles, columns: Option...
    method force_data_update (line 331) | pub fn force_data_update(&mut self) {
    method set_table_data (line 336) | pub fn set_table_data(&mut self, data: &StoredData) {
    method set_index (line 346) | pub fn set_index(&mut self, index: usize) {
  type DataType (line 223) | type DataType = DiskWidgetData;
  method sort_data (line 225) | fn sort_data(&self, data: &mut [Self::DataType], descending: bool) {
  function create_column (line 266) | const fn create_column(column_type: &DiskColumn) -> SortColumn<DiskColum...
  function default_disk_columns (line 284) | const fn default_disk_columns() -> [SortColumn<DiskColumn>; 8] {

FILE: src/widgets/mem_graph.rs
  type MemWidgetState (line 3) | pub struct MemWidgetState {
    method init (line 9) | pub fn init(current_display_time: u64, autohide_timer: Option<Instant>...

FILE: src/widgets/network_graph.rs
  type NetWidgetState (line 3) | pub struct NetWidgetState {
    method init (line 16) | pub fn init(current_display_time: u64, autohide_timer: Option<Instant>...
  type NetWidgetHeightCache (line 9) | pub struct NetWidgetHeightCache {

FILE: src/widgets/process_table.rs
  type ProcessSearchState (line 34) | pub struct ProcessSearchState {
    method search_toggle_ignore_case (line 40) | pub fn search_toggle_ignore_case(&mut self) {
    method search_toggle_whole_word (line 44) | pub fn search_toggle_whole_word(&mut self) {
    method search_toggle_regex (line 48) | pub fn search_toggle_regex(&mut self) {
  type TreeCollapsed (line 55) | pub(crate) enum TreeCollapsed {
    method new (line 62) | pub(crate) fn new(default_collapsed: bool) -> Self {
    method is_collapsed (line 75) | pub(crate) fn is_collapsed(&self, pid: Pid) -> bool {
    method collapse (line 83) | pub(crate) fn collapse(&mut self, pid: Pid) {
    method expand (line 95) | pub(crate) fn expand(&mut self, pid: Pid) {
    method toggle (line 107) | pub(crate) fn toggle(&mut self, pid: Pid) {
  type ProcWidgetMode (line 128) | pub(crate) enum ProcWidgetMode {
  type ProcessTable (line 134) | type ProcessTable = SortDataTable<ProcWidgetData, ProcColumn>;
  type SortTable (line 135) | type SortTable = DataTable<Cow<'static, str>, SortTableColumn>;
  type StringPidMap (line 136) | type StringPidMap = HashMap<String, Vec<Pid>>;
  function make_column (line 138) | fn make_column(column: ProcColumn) -> SortColumn<ProcColumn> {
  type ProcTableConfig (line 170) | pub struct ProcTableConfig {
  type ProcWidgetColumn (line 180) | pub enum ProcWidgetColumn {
  type ProcWidgetState (line 204) | pub struct ProcWidgetState {
    method new_sort_table (line 237) | fn new_sort_table(config: &AppConfigFields, palette: &Styles) -> SortT...
    method new_process_table (line 253) | fn new_process_table(
    method new (line 275) | pub(crate) fn new(
    method is_using_command (line 451) | pub fn is_using_command(&self) -> bool {
    method is_mem_percent (line 463) | pub fn is_mem_percent(&self) -> bool {
    method get_query (line 471) | fn get_query(&self) -> &Option<ProcessQuery> {
    method set_table_data (line 484) | pub fn set_table_data(&mut self, stored_data: &StoredData) {
    method get_tree_data (line 495) | fn get_tree_data(
    method get_normal_data (line 771) | fn get_normal_data(
    method get_mut_proc_col (line 864) | fn get_mut_proc_col(&mut self, index: usize) -> Option<&mut ProcColumn> {
    method toggle_mem_percentage (line 868) | pub fn toggle_mem_percentage(&mut self) {
    method force_data_update (line 906) | pub fn force_data_update(&mut self) {
    method force_rerender_and_update (line 912) | pub fn force_rerender_and_update(&mut self) {
    method toggle_k_thread (line 918) | pub fn toggle_k_thread(&mut self) {
    method hide_column (line 925) | fn hide_column(&mut self, column: ProcWidgetColumn) {
    method show_column (line 939) | fn show_column(&mut self, column: ProcWidgetColumn) {
    method select_column (line 949) | pub fn select_column(&mut self, column: ProcWidgetColumn) {
    method collapse_current_tree_branch_entry (line 956) | pub fn collapse_current_tree_branch_entry(&mut self) {
    method expand_current_tree_branch_entry (line 965) | pub fn expand_current_tree_branch_entry(&mut self) {
    method toggle_current_tree_branch_entry (line 974) | pub fn toggle_current_tree_branch_entry(&mut self) {
    method toggle_command (line 983) | pub fn toggle_command(&mut self) {
    method toggle_tab (line 1025) | pub fn toggle_tab(&mut self) {
    method column_text (line 1060) | pub fn column_text(&self) -> Vec<Cow<'static, str>> {
    method cursor_char_index (line 1069) | pub fn cursor_char_index(&self) -> usize {
    method is_search_enabled (line 1073) | pub fn is_search_enabled(&self) -> bool {
    method current_search_query (line 1077) | pub fn current_search_query(&self) -> &str {
    method update_query (line 1084) | pub fn update_query(&mut self) {
    method clear_search (line 1121) | pub fn clear_search(&mut self) {
    method search_walk_forward (line 1126) | pub fn search_walk_forward(&mut self) {
    method search_walk_back (line 1130) | pub fn search_walk_back(&mut self) {
    method use_sort_table_value (line 1136) | pub(crate) fn use_sort_table_value(&mut self) {
    method test_equality (line 1144) | pub(crate) fn test_equality(&self, other: &Self) -> bool {
  function sort_skip_pid_asc (line 1163) | fn sort_skip_pid_asc(column: &ProcColumn, data: &mut [ProcWidgetData], o...
  function test_proc_sort (line 1183) | fn test_proc_sort() {
  function get_columns (line 1275) | fn get_columns(table: &ProcessTable) -> Vec<ProcColumn> {
  function init_state (line 1289) | fn init_state(table_config: ProcTableConfig, columns: &[ProcWidgetColumn...
  function init_default_state (line 1303) | fn init_default_state(columns: &[ProcWidgetColumn]) -> ProcWidgetState {
  function custom_columns (line 1308) | fn custom_columns() {
  function toggle_count_pid (line 1326) | fn toggle_count_pid() {
  function toggle_count_pid_2 (line 1354) | fn toggle_count_pid_2() {
  function toggle_command (line 1384) | fn toggle_command() {
  function toggle_mem_percentage (line 1419) | fn toggle_mem_percentage() {
  function toggle_mem_percentage_2 (line 1450) | fn toggle_mem_percentage_2() {
  function columns_and_is_using_command (line 1485) | fn columns_and_is_using_command() {
  function columns_and_is_memory (line 1515) | fn columns_and_is_memory() {
  function double_memory_sim_toggle (line 1550) | fn double_memory_sim_toggle() {
  function pid_and_count_sim_toggle (line 1587) | fn pid_and_count_sim_toggle() {
  function command_name_sim_toggle (line 1621) | fn command_name_sim_toggle() {
  function test_tree_collapse (line 1658) | fn test_tree_collapse() {
  function test_toggle_k_threads (line 1698) | fn test_toggle_k_threads() {

FILE: src/widgets/process_table/process_columns.rs
  type ProcColumn (line 17) | pub enum ProcColumn {
    method get_schema_names (line 47) | pub fn get_schema_names(&self) -> &[&'static str] {
    method deserialize (line 204) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  method text (line 77) | fn text(&self) -> Cow<'static, str> {
  method header (line 107) | fn header(&self) -> Cow<'static, str> {
  type DataType (line 124) | type DataType = ProcWidgetData;
  method sort_data (line 126) | fn sort_data(&self, data: &mut [ProcWidgetData], descending: bool) {
  method from (line 239) | fn from(value: &ProcColumn) -> Self {

FILE: src/widgets/process_table/process_data.rs
  type IdType (line 25) | enum IdType {
  type Id (line 31) | pub struct Id {
    method from (line 37) | fn from(s: &'static str) -> Self {
    method to_lowercase (line 49) | pub fn to_lowercase(&self) -> String {
    method as_str (line 57) | pub fn as_str(&self) -> &str {
    method to_prefixed_string (line 65) | pub fn to_prefixed_string(&self) -> String {
  method fmt (line 84) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type MemUsage (line 90) | pub enum MemUsage {
  method partial_cmp (line 96) | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  method fmt (line 106) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type DurationExt (line 114) | trait DurationExt {
    method num_days (line 115) | fn num_days(&self) -> u64;
    method num_hours (line 116) | fn num_hours(&self) -> u64;
    method num_minutes (line 117) | fn num_minutes(&self) -> u64;
    method num_days (line 127) | fn num_days(&self) -> u64 {
    method num_hours (line 133) | fn num_hours(&self) -> u64 {
    method num_minutes (line 139) | fn num_minutes(&self) -> u64 {
  constant SECS_PER_DAY (line 120) | const SECS_PER_DAY: u64 = SECS_PER_HOUR * 24;
  constant SECS_PER_HOUR (line 121) | const SECS_PER_HOUR: u64 = SECS_PER_MINUTE * 60;
  constant SECS_PER_MINUTE (line 122) | const SECS_PER_MINUTE: u64 = 60;
  function format_time (line 144) | fn format_time(dur: Duration) -> String {
  function binary_byte_string (line 175) | fn binary_byte_string(value: u64) -> String {
  function dec_bytes_string (line 186) | fn dec_bytes_string(value: u64) -> String {
  type ProcWidgetData (line 196) | pub struct ProcWidgetData {
    method from_data (line 227) | pub fn from_data(process: &ProcessHarvest, is_command: bool, is_mem_pe...
    method disabled (line 276) | pub fn disabled(mut self, disabled: bool) -> Self {
    method prefix (line 281) | pub fn prefix(mut self, prefix: Option<String>) -> Self {
    method add (line 286) | pub fn add(&mut self, other: &Self) {
    method to_string (line 315) | fn to_string(&self, column: &ProcColumn) -> String {
    method to_cell_text (line 346) | fn to_cell_text(
    method style_cell (line 390) | fn style_cell(&self, column: &ProcColumn, painter: &Painter) -> Option...
    method style_row (line 400) | fn style_row<'a>(&self, row: Row<'a>, painter: &Painter) -> Row<'a> {
    method column_widths (line 408) | fn column_widths<C: DataTableColumn<ProcColumn>>(data: &[Self], column...
  function test_format_time (line 432) | fn test_format_time() {
  function test_binary_byte_string (line 463) | fn test_binary_byte_string() {

FILE: src/widgets/process_table/query.rs
  constant DELIMITER_LIST (line 24) | const DELIMITER_LIST: [char; 6] = ['=', '>', '<', '(', ')', '\"'];
  constant COMPARISON_LIST (line 25) | const COMPARISON_LIST: [&str; 3] = [">", "=", "<"];
  type QueryProcessor (line 29) | trait QueryProcessor {
    method process (line 30) | fn process(query: &mut VecDeque<String>, regex_options: &QueryOptions)...
  function new_regex (line 38) | fn new_regex(base: &str, regex_options: &QueryOptions) -> QueryResult<Re...
  type QueryOptions (line 64) | pub struct QueryOptions {
  method default (line 77) | fn default() -> Self {
  function parse_query (line 106) | pub(crate) fn parse_query(search_query: &str, options: &QueryOptions) ->...
  type ProcessQuery (line 141) | pub struct ProcessQuery {
    method check (line 147) | pub(crate) fn check(&self, process: &ProcessHarvest, is_using_command:...
  type PrefixType (line 155) | enum PrefixType {
    type Err (line 180) | type Err = QueryError;
    method from_str (line 182) | fn from_str(s: &str) -> QueryResult<Self> {
  type QueryComparison (line 234) | enum QueryComparison {
  type NumericalQuery (line 243) | struct NumericalQuery {
    method check (line 250) | fn check<I: Into<f64>>(&self, lhs: I) -> bool {
  type TimeQuery (line 265) | struct TimeQuery {
    method check (line 272) | fn check(&self, lhs: Duration) -> bool {
  function simple_process (line 289) | fn simple_process(name: &str) -> ProcessHarvest {
  function parse_query_no_options (line 296) | fn parse_query_no_options(query: &str) -> QueryResult<ProcessQuery> {
  function basic_query (line 308) | fn basic_query() {
  function basic_or_query (line 321) | fn basic_or_query() {
  function basic_and_query (line 334) | fn basic_and_query() {
  function implied_and_query (line 349) | fn implied_and_query() {
  function quoted_query (line 366) | fn quoted_query() {
  function quoted_multi_word_query (line 387) | fn quoted_multi_word_query() {
  function basic_cpu_query (line 406) | fn basic_cpu_query() {
  function basic_mem_query (line 424) | fn basic_mem_query() {
  function nested_query_1 (line 443) | fn nested_query_1() {
  function nested_query_2 (line 459) | fn nested_query_2() {
  function nested_query_3 (line 491) | fn nested_query_3() {
  function ambiguous_precedence_1 (line 523) | fn ambiguous_precedence_1() {
  function ambiguous_precedence_2 (line 536) | fn ambiguous_precedence_2() {
  function parse_complicated_query (line 550) | fn parse_complicated_query() {
  function parse_empty_quotes (line 560) | fn parse_empty_quotes() {
  function search_empty_quotes (line 567) | fn search_empty_quotes() {
  function parse_unfinished_quotes (line 579) | fn parse_unfinished_quotes() {
  function parse_nested_closing_quotes (line 588) | fn parse_nested_closing_quotes() {
  function invalid_uncompleted_queries_1 (line 601) | fn invalid_uncompleted_queries_1() {
  function invalid_lhs_rhs (line 608) | fn invalid_lhs_rhs(op: &str) {
  function invalid_or (line 618) | fn invalid_or() {
  function invalid_and (line 624) | fn invalid_and() {
  function test_command_check (line 642) | fn test_command_check() {
  function test_non_ascii_only_1 (line 656) | fn test_non_ascii_only_1() {
  function test_non_ascii_only_2 (line 667) | fn test_non_ascii_only_2() {
  function test_non_ascii_only_3 (line 678) | fn test_non_ascii_only_3() {
  function test_non_ascii_only_4 (line 691) | fn test_non_ascii_only_4() {
  function test_invalid_non_ascii (line 704) | fn test_invalid_non_ascii() {
  function test_mixed_unicode (line 709) | fn test_mixed_unicode() {
  function test_regex_1 (line 726) | fn test_regex_1() {
  function test_regex_2 (line 745) | fn test_regex_2() {
  function test_whole_word_1 (line 768) | fn test_whole_word_1() {
  function test_case_sensitive_1 (line 789) | fn test_case_sensitive_1() {
  function test_gpu_queries (line 819) | fn test_gpu_queries() {
  function test_invalid_gpu_queries (line 846) | fn test_invalid_gpu_queries() {

FILE: src/widgets/process_table/query/and.rs
  type And (line 13) | pub(super) struct And {
    method check (line 20) | pub(super) fn check(&self, process: &ProcessHarvest, is_using_command:...
  method process (line 30) | fn process(query: &mut VecDeque<String>, options: &QueryOptions) -> Quer...

FILE: src/widgets/process_table/query/attribute.rs
  type ProcessAttribute (line 16) | pub(super) enum ProcessAttribute {
    method check (line 46) | pub(super) fn check(&self, process: &ProcessHarvest, is_using_command:...
  function new_string_attribute (line 83) | pub(super) fn new_string_attribute(
  function new_time_attribute (line 105) | pub(super) fn new_time_attribute(
  function new_numerical_attribute (line 117) | pub(super) fn new_numerical_attribute(

FILE: src/widgets/process_table/query/error.rs
  type QueryError (line 7) | pub(crate) struct QueryError {
    method new (line 13) | pub(crate) fn new<I: Into<Cow<'static, str>>>(reason: I) -> Self {
    method missing_value (line 20) | pub(super) fn missing_value() -> Self {
    method from (line 34) | fn from(err: regex::Error) -> Self {
  method fmt (line 28) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
  type QueryResult (line 39) | pub(super) type QueryResult<T> = Result<T, QueryError>;

FILE: src/widgets/process_table/query/or.rs
  type Or (line 13) | pub(super) struct Or {
    method check (line 20) | pub(super) fn check(&self, process: &ProcessHarvest, is_using_command:...
  method process (line 30) | fn process(query: &mut VecDeque<String>, options: &QueryOptions) -> Quer...

FILE: src/widgets/process_table/query/prefix.rs
  function process_prefix_units (line 17) | fn process_prefix_units(query: &mut VecDeque<String>, value: &mut f64) {
  type Prefix (line 60) | pub(super) enum Prefix {
    method check (line 66) | pub(super) fn check(&self, process: &ProcessHarvest, is_using_command:...
    method process_in_quotes (line 73) | fn process_in_quotes(
  method process (line 113) | fn process(query: &mut VecDeque<String>, options: &QueryOptions) -> Quer...

FILE: src/widgets/process_table/sort_table.rs
  type SortTableColumn (line 5) | pub struct SortTableColumn;
  method text (line 8) | fn text(&self) -> Cow<'static, str> {
  function to_cell_text (line 14) | fn to_cell_text(
  function column_widths (line 20) | fn column_widths<C: DataTableColumn<SortTableColumn>>(data: &[Self], _co...
  function to_cell_text (line 29) | fn to_cell_text(
  function column_widths (line 35) | fn column_widths<C: DataTableColumn<SortTableColumn>>(data: &[Self], _co...

FILE: src/widgets/temperature_table.rs
  type TempWidgetData (line 14) | pub struct TempWidgetData {
    method temperature (line 34) | pub fn temperature(&self) -> Cow<'static, str> {
    method to_cell_text (line 43) | fn to_cell_text(
    method column_widths (line 52) | fn column_widths<C: DataTableColumn<TempWidgetColumn>>(
  type TempWidgetColumn (line 19) | pub enum TempWidgetColumn {
  method text (line 25) | fn text(&self) -> Cow<'static, str> {
  type DataType (line 70) | type DataType = TempWidgetData;
  method sort_data (line 72) | fn sort_data(&self, data: &mut [Self::DataType], descending: bool) {
  type TempWidgetState (line 84) | pub struct TempWidgetState {
    method new (line 90) | pub(crate) fn new(config: &AppConfigFields, palette: &Styles) -> Self {
    method force_data_update (line 119) | pub fn force_data_update(&mut self) {
    method set_table_data (line 124) | pub fn set_table_data(&mut self, data: &[TempWidgetData]) {

FILE: tests/integration/arg_tests.rs
  function test_small_rate (line 10) | fn test_small_rate() {
  function test_large_default_time (line 20) | fn test_large_default_time() {
  function test_small_default_time (line 32) | fn test_small_default_time() {
  function test_large_delta_time (line 44) | fn test_large_delta_time() {
  function test_small_delta_time (line 56) | fn test_small_delta_time() {
  function test_large_rate (line 66) | fn test_large_rate() {
  function test_negative_rate (line 78) | fn test_negative_rate() {
  function test_invalid_rate (line 89) | fn test_invalid_rate() {
  function test_conflicting_temps (line 101) | fn test_conflicting_temps() {
  function test_invalid_default_widget_1 (line 111) | fn test_invalid_default_widget_1() {
  function test_invalid_default_widget_2 (line 121) | fn test_invalid_default_widget_2() {
  function test_missing_default_widget_type (line 133) | fn test_missing_default_widget_type() {
  function test_invalid_default_cpu_entry (line 145) | fn test_invalid_default_cpu_entry() {
  function test_battery_flag (line 156) | fn test_battery_flag() {
  function test_gpu_flag (line 168) | fn test_gpu_flag() {
  function test_version (line 180) | fn test_version() {
  function test_help (line 187) | fn test_help() {

FILE: tests/integration/invalid_config_tests.rs
  function test_toml_mismatch_type (line 9) | fn test_toml_mismatch_type() {
  function test_empty_layout (line 17) | fn test_empty_layout() {
  function test_invalid_layout_widget_type (line 25) | fn test_invalid_layout_widget_type() {
  function test_duplicate_temp_type (line 38) | fn test_duplicate_temp_type() {
  function test_invalid_colour_hex (line 47) | fn test_invalid_colour_hex() {
  function test_invalid_colour_hex_2 (line 56) | fn test_invalid_colour_hex_2() {
  function test_invalid_colour_hex_3 (line 66) | fn test_invalid_colour_hex_3() {
  function test_invalid_colour_name (line 74) | fn test_invalid_colour_name() {
  function test_invalid_colour_rgb (line 82) | fn test_invalid_colour_rgb() {
  function test_invalid_colour_rgb_2 (line 90) | fn test_invalid_colour_rgb_2() {
  function test_invalid_colour_string (line 98) | fn test_invalid_colour_string() {
  function test_lone_default_widget_count (line 106) | fn test_lone_default_widget_count() {
  function test_invalid_default_widget_count (line 117) | fn test_invalid_default_widget_count() {
  function test_invalid_process_column (line 128) | fn test_invalid_process_column() {
  function test_invalid_disk_column (line 136) | fn test_invalid_disk_column() {

FILE: tests/integration/util.rs
  function abs_path (line 7) | pub fn abs_path(path: &str) -> OsString {
  function get_qemu_target (line 19) | fn get_qemu_target(arch: &str) -> &str {
  function cross_runner (line 37) | fn cross_runner() -> Option<String> {
  constant BTM_EXE_PATH (line 71) | const BTM_EXE_PATH: &str = env!("CARGO_BIN_EXE_btm");
  constant RUNNER_ENV_VARS (line 72) | const RUNNER_ENV_VARS: [(&str, &str); 1] = [("NO_COLOR", "1")];
  constant DEFAULT_CFG (line 73) | const DEFAULT_CFG: [&str; 2] = ["-C", "./tests/valid_configs/empty_confi...
  function btm_command (line 77) | pub fn btm_command(args: &[&str]) -> Command {
  function no_cfg_btm_command (line 105) | pub fn no_cfg_btm_command() -> Command {
  function spawn_btm_in_pty (line 111) | pub fn spawn_btm_in_pty(args: &[&str]) -> (Box<dyn MasterPty>, Box<dyn C...

FILE: tests/integration/valid_config_tests.rs
  function reader_to_string (line 9) | fn reader_to_string(mut reader: Box<dyn Read>) -> String {
  function run_and_kill (line 16) | fn run_and_kill(args: &[&str]) {
  function test_basic (line 42) | fn test_basic() {
  function test_bad_basic (line 49) | fn test_bad_basic() {
  function test_empty (line 54) | fn test_empty() {
  function test_uncommented_default_config (line 59) | fn test_uncommented_default_config(original: &Path, test_name: &str) {
  function test_default (line 106) | fn test_default() {
  function test_new_default (line 115) | fn test_new_default() {
  function test_demo (line 144) | fn test_demo() {
  function test_many_proc (line 154) | fn test_many_proc() {
  function test_all_proc (line 159) | fn test_all_proc() {
  function test_cpu_doughnut (line 164) | fn test_cpu_doughnut() {
  function test_theme (line 169) | fn test_theme() {
  function test_styling_sanity_check (line 174) | fn test_styling_sanity_check() {
  function test_styling_sanity_check_2 (line 179) | fn test_styling_sanity_check_2() {
  function test_filtering (line 184) | fn test_filtering() {
  function test_proc_columns (line 189) | fn test_proc_columns() {
  function test_linux_only (line 195) | fn test_linux_only() {
Condensed preview — 285 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,751K chars).
[
  {
    "path": ".all-contributorsrc",
    "chars": 19309,
    "preview": "{\n  \"files\": [\n    \"README.md\"\n  ],\n  \"imageSize\": 100,\n  \"commit\": false,\n  \"contributors\": [\n    {\n      \"login\": \"shi"
  },
  {
    "path": ".cargo/config.toml",
    "chars": 161,
    "preview": "[target.x86_64-pc-windows-msvc]\nrustflags = [\"-C\", \"target-feature=+crt-static\"]\n\n[target.i686-pc-windows-msvc]\nrustflag"
  },
  {
    "path": ".cirrus.yml",
    "chars": 2162,
    "preview": "%YAML 1.1\n---\n# Configuration for CirrusCI. This is primarily used for testing and building FreeBSD and old versions of "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "chars": 5825,
    "preview": "name: Bug report\ndescription: Found something wrong or broken? If it hasn't already been filed/solved, report it!\nlabels"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 319,
    "preview": "blank_issues_enabled: true\ncontact_links:\n  - name: Open a discussion\n    about: |\n      Got a question about using bott"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "chars": 1211,
    "preview": "name: Feature request\ndescription: Got a good idea that hasn't already been suggested?  Mention it here!\nlabels: [\"featu"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/packaging.yml",
    "chars": 2267,
    "preview": "name: Packaging\ndescription: For issues, questions, or requests regarding packaging or distribution.\nlabels: [\"packaging"
  },
  {
    "path": ".github/actions/test-bsd-target/action.yml",
    "chars": 3441,
    "preview": "name: Test BSD Target\ndescription: Run tests for a BSD target using VMs, with retries on failure. Needed as cross doesn'"
  },
  {
    "path": ".github/ci/rust_version.txt",
    "chars": 7,
    "preview": "1.94.0\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 1431,
    "preview": "<!-- Please use this template (unless you have a very good reason not to). PRs that do not use the template may be close"
  },
  {
    "path": ".github/workflows/bsd_vm_check.yml",
    "chars": 2498,
    "preview": "# Run BSD VM jobs with manually-implemented retries.\n\nname: \"BSD VM Check\"\n\non:\n  workflow_call:\n    inputs:\n      os-ta"
  },
  {
    "path": ".github/workflows/build_releases.yml",
    "chars": 23679,
    "preview": "# Builds the following releases:\n# - Binaries\n# - Binaries via VMs\n# - Cirrus binaries (currently just Linux 2.17)\n# - M"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 14962,
    "preview": "# Main CI workflow to validate that files are formatted correctly, pass tests,\n# and pass lints.\n#\n# CI workflow was bas"
  },
  {
    "path": ".github/workflows/clear_workflow_cache.yml",
    "chars": 1635,
    "preview": "# Simple job to clear the cache used by a workflow. This automatically runs when a PR is closed/merged\n# to clean up the"
  },
  {
    "path": ".github/workflows/coverage.yml",
    "chars": 4000,
    "preview": "# Code coverage generation via cargo-llvm-cov, which is then uploaded to Codecov.\n# Codecov will report back via a comme"
  },
  {
    "path": ".github/workflows/deployment.yml",
    "chars": 4375,
    "preview": "# How we deploy a release. Covers binary builds. Also manages packaging for choco.\n#\n# Binaries are primarily built by G"
  },
  {
    "path": ".github/workflows/docs.yml",
    "chars": 1452,
    "preview": "# Workflow to deploy mkdocs documentation.\n\nname: docs\n\non:\n  workflow_dispatch:\n  workflow_call:\n    inputs:\n      nigh"
  },
  {
    "path": ".github/workflows/nightly.yml",
    "chars": 5838,
    "preview": "# Creates nightly deployment builds for main targets. Note this does not cover package distribution channels,\n# such as "
  },
  {
    "path": ".github/workflows/post_release.yml",
    "chars": 3107,
    "preview": "# Actions to run after releasing a version, like:\n# - Generating documentation via mkdocs\n# - Notifying packaging repos\n"
  },
  {
    "path": ".github/workflows/publish_github_pages.yml",
    "chars": 1224,
    "preview": "# Workflow to publish to GitHub Pages. Based on the normal\n# job (e.g. https://github.com/ClementTsang/bottom/actions/ru"
  },
  {
    "path": ".github/workflows/test_docs.yml",
    "chars": 1412,
    "preview": "# Small CI workflow to test if mkdocs documentation can be successfully built.\n\nname: test docs\n\non:\n  workflow_dispatch"
  },
  {
    "path": ".github/workflows/validate_schema.yml",
    "chars": 2179,
    "preview": "# Workflow to validate the latest schema.\n\nname: \"validate schema\"\non:\n  workflow_dispatch:\n  pull_request:\n  push:\n    "
  },
  {
    "path": ".gitignore",
    "chars": 566,
    "preview": "# Generated by Cargo\n# will have compiled files and executables\n/target/\n\n# These are backup files generated by rustfmt\n"
  },
  {
    "path": ".markdownlint.json",
    "chars": 148,
    "preview": "{\n  \"MD013\": false,\n  \"MD041\": false,\n  \"MD033\": false,\n  \"MD040\": false,\n  \"MD024\": false,\n  \"MD025\": false,\n  \"MD046\":"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 50663,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file. The format is based on\n[Keep a Changel"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2402,
    "preview": "# Contribution\n\nContribution in any way is appreciated, whether it is reporting problems, fixing bugs, implementing feat"
  },
  {
    "path": "Cargo.toml",
    "chars": 7123,
    "preview": "[package]\nname = \"bottom\"\nversion = \"0.12.3\"\nrepository = \"https://github.com/ClementTsang/bottom\"\nlicense = \"MIT\"\ndescr"
  },
  {
    "path": "Cross.toml",
    "chars": 618,
    "preview": "[build.env]\npassthrough = [\"RUST_BACKTRACE\", \"BTM_GENERATE\"]\n\n[target.x86_64-unknown-netbsd]\npre-build = [\n    \"apt-get "
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2019 Clement Tsang\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
  },
  {
    "path": "README.md",
    "chars": 46312,
    "preview": "<div align=\"center\">\n  <h1>bottom (btm)</h1>\n\n  <p>\n    A customizable cross-platform graphical process/system monitor f"
  },
  {
    "path": "build.rs",
    "chars": 4052,
    "preview": "//! General build script used by bottom to generate completion files and set binary version.\n\n#![expect(clippy::unwrap_u"
  },
  {
    "path": "clippy.toml",
    "chars": 161,
    "preview": "cognitive-complexity-threshold = 100\ntype-complexity-threshold = 500\ntoo-many-arguments-threshold = 8\nallow-unwrap-in-co"
  },
  {
    "path": "codecov.yml",
    "chars": 107,
    "preview": "coverage:\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 30%\n    patch: off\n"
  },
  {
    "path": "desktop/bottom.desktop",
    "chars": 281,
    "preview": "[Desktop Entry]\nName=bottom\nVersion=1.5\nGenericName=System Monitor\nComment=A customizable cross-platform graphical proce"
  },
  {
    "path": "docs/.gitignore",
    "chars": 38,
    "preview": "site/\nvenv/\n.cache/\nhooks/__pycache__/"
  },
  {
    "path": "docs/README.md",
    "chars": 1338,
    "preview": "# Extended Documentation\n\nThis is where the extended documentation resides, hosted on GitHub Pages. We use [MkDocs](http"
  },
  {
    "path": "docs/content/configuration/command-line-options.md",
    "chars": 7311,
    "preview": "# Command-line Options\n\nThe following options can be provided to bottom in the command line to change the behaviour of t"
  },
  {
    "path": "docs/content/configuration/config-file/cpu.md",
    "chars": 224,
    "preview": "# CPU\n\n## Default CPU Graph Selection\n\nYou can configure which CPU graph is shown by default when starting up bottom by "
  },
  {
    "path": "docs/content/configuration/config-file/disk-table.md",
    "chars": 1795,
    "preview": "# Disk Table\n\n## Columns\n\nYou can configure which columns are shown by the disk table widget by setting the `columns` se"
  },
  {
    "path": "docs/content/configuration/config-file/flags.md",
    "chars": 11705,
    "preview": "# Flags\n\n!!! Warning\n\n    This section is in progress, and is just copied from the old documentation.\n\nYou can configure"
  },
  {
    "path": "docs/content/configuration/config-file/index.md",
    "chars": 1307,
    "preview": "# Config File\n\nFor persistent configuration, and for certain configuration options, bottom supports config files.\n\n## De"
  },
  {
    "path": "docs/content/configuration/config-file/layout.md",
    "chars": 2294,
    "preview": "# Layout\n\n!!! Warning\n\n    This section is in progress, and is just copied from the old documentation.\n\nbottom supports "
  },
  {
    "path": "docs/content/configuration/config-file/network.md",
    "chars": 780,
    "preview": "# Network\n\n## Filtering Entries\n\nYou can filter out what entries to show by configuring `[network.interface_filter]` .\nI"
  },
  {
    "path": "docs/content/configuration/config-file/processes.md",
    "chars": 319,
    "preview": "# Processes\n\n## Columns\n\nYou can configure which columns are shown by the process widget by setting the `columns` settin"
  },
  {
    "path": "docs/content/configuration/config-file/styling.md",
    "chars": 8196,
    "preview": "# Styling\n\nVarious parts of the bottom can be styled, using either built-in themes or custom theming.\n\n## Precedence\n\nAs"
  },
  {
    "path": "docs/content/configuration/config-file/temperature-table.md",
    "chars": 747,
    "preview": "# Temperature Table\n\n## Filtering Entries\n\nYou can filter out what entries to show by configuring `[temperature.sensor_f"
  },
  {
    "path": "docs/content/contribution/development/build_process.md",
    "chars": 2863,
    "preview": "# Build Process\n\n!!! Warning\n\n    This section is currently somewhat WIP.\n\n!!! Warning\n\n    This section is intended for"
  },
  {
    "path": "docs/content/contribution/development/deploy_process.md",
    "chars": 3102,
    "preview": "# Deploy Process\n\n!!! Warning\n\n    This section is currently WIP.\n\n!!! Warning\n\n    This section is intended for people "
  },
  {
    "path": "docs/content/contribution/development/dev_env.md",
    "chars": 193,
    "preview": "# Development Environment\n\n!!! Warning\n\n    This section is currently WIP.\n\n!!! Warning\n\n    This section is intended fo"
  },
  {
    "path": "docs/content/contribution/development/logging.md",
    "chars": 177,
    "preview": "# Logging\n\n!!! Warning\n\n    This section is currently WIP.\n\n!!! Warning\n\n    This section is intended for people who wis"
  },
  {
    "path": "docs/content/contribution/development/testing.md",
    "chars": 177,
    "preview": "# Testing\n\n!!! Warning\n\n    This section is currently WIP.\n\n!!! Warning\n\n    This section is intended for people who wis"
  },
  {
    "path": "docs/content/contribution/documentation.md",
    "chars": 2823,
    "preview": "# Documentation\n\n## When should documentation changes be done?\n\n- Whenever a new feature is added, a bug is fixed, or a "
  },
  {
    "path": "docs/content/contribution/issues-and-pull-requests.md",
    "chars": 2099,
    "preview": "# Issues, Pull Requests, and Discussions\n\n## Discussions\n\nDiscussions are open [in the repo](https://github.com/ClementT"
  },
  {
    "path": "docs/content/contribution/packaging-and-distribution.md",
    "chars": 3088,
    "preview": "# Packaging and Distribution\n\nPackage maintainers are always welcome and appreciated! Here's some info on how one can he"
  },
  {
    "path": "docs/content/index.md",
    "chars": 1856,
    "preview": "---\nhide:\n  - navigation\n  - toc\ntitle: Home\n---\n\n# `bottom`\n\nA customizable cross-platform graphical process/system mo"
  },
  {
    "path": "docs/content/nightly-release.md",
    "chars": 54,
    "preview": "<!-- Intentionally empty file, used for redirects -->\n"
  },
  {
    "path": "docs/content/stylesheets/extra.css",
    "chars": 174,
    "preview": ":root {\n  --md-primary-fg-color: #268bd2;\n  --md-accent-fg-color: #81a1c1;\n}\n\n.md-typeset__table {\n  min-width: 100%;\n}\n"
  },
  {
    "path": "docs/content/support/official.md",
    "chars": 648,
    "preview": "# Official support\n\nbottom _officially_ supports the following operating systems and corresponding architectures:\n\n- mac"
  },
  {
    "path": "docs/content/support/unofficial.md",
    "chars": 1085,
    "preview": "# Unofficial support\n\nSystems and architectures that aren't officially supported may still work, but there are no guaran"
  },
  {
    "path": "docs/content/troubleshooting.md",
    "chars": 8451,
    "preview": "# Troubleshooting/Known Issues\n\n## The graph points look broken/strange\n\nIt's possible that your graphs don't look great"
  },
  {
    "path": "docs/content/usage/autocomplete.md",
    "chars": 834,
    "preview": "# Auto-Complete\n\nThe release binaries in [the releases page](https://github.com/ClementTsang/bottom/releases) are packag"
  },
  {
    "path": "docs/content/usage/basic-mode.md",
    "chars": 1047,
    "preview": "# Basic Mode\n\nBasic mode is a special layout that removes all of the graphs and provides an interface that resembles (a "
  },
  {
    "path": "docs/content/usage/general-usage.md",
    "chars": 4222,
    "preview": "# General Usage\n\nYou can run bottom with:\n\n```bash\nbtm\n```\n\nFor help regarding the command-line options, use:\n\n```bash\n#"
  },
  {
    "path": "docs/content/usage/widgets/battery.md",
    "chars": 1491,
    "preview": "# Battery Widget\n\n!!! Warning\n\n    The battery features are unavailable if the binary is compiled with the `battery` fea"
  },
  {
    "path": "docs/content/usage/widgets/cpu.md",
    "chars": 2250,
    "preview": "# CPU Widget\n\nThe CPU widget displays a visual representation of CPU usage over a time range.\n\n<figure>\n    <img src=\".."
  },
  {
    "path": "docs/content/usage/widgets/disk.md",
    "chars": 2019,
    "preview": "# Disk Widget\n\nThe disk widget provides a table of useful disk and partition information, like I/O per second and total "
  },
  {
    "path": "docs/content/usage/widgets/memory.md",
    "chars": 2279,
    "preview": "# Memory Widget\n\nThe memory widget provides a visual representation of RAM and swap usage over time.\n\n<figure>\n    <img "
  },
  {
    "path": "docs/content/usage/widgets/network.md",
    "chars": 1543,
    "preview": "# Network Widget\n\nThe network widget provides a visual representation of network input and output per second, as well as"
  },
  {
    "path": "docs/content/usage/widgets/process.md",
    "chars": 16472,
    "preview": "# Process Widget\n\nThe process widget displays a table containing information regarding a running process, along with sor"
  },
  {
    "path": "docs/content/usage/widgets/temperature.md",
    "chars": 1373,
    "preview": "# Temperature Widget\n\nThe temperature widget provides a table of temperature sensors and their current temperature.\n\n<fi"
  },
  {
    "path": "docs/hooks/nightly_banner.py",
    "chars": 486,
    "preview": "import os\nimport sys\n\nimport mkdocs.plugins\n\n\n@mkdocs.plugins.event_priority(-100)\ndef on_config(config):\n    print(\"Run"
  },
  {
    "path": "docs/hooks/nightly_redirect.py",
    "chars": 1706,
    "preview": "import os\nimport sys\nimport json\nimport mkdocs.plugins\nimport urllib.request\n\n\n# Based on https://github.com/squidfunk/m"
  },
  {
    "path": "docs/mike.sh",
    "chars": 619,
    "preview": "#!/bin/bash\n\n# Used to serve a versioned version of the docs locally. Note this\n# does NOT reflect local changes.\n\nset -"
  },
  {
    "path": "docs/mkdocs.yml",
    "chars": 5551,
    "preview": "# Site information\nsite_name: bottom\nsite_author: Clement Tsang\nsite_url: https://bottom.pages.dev\nsite_description: >-\n"
  },
  {
    "path": "docs/overrides/main.html",
    "chars": 654,
    "preview": "{% extends \"base.html\" %}\n{% block announce %}\n    {#- It's like helm and you need to add dashes, see https://github.com"
  },
  {
    "path": "docs/requirements.txt",
    "chars": 160,
    "preview": "mkdocs == 1.6.1\nmkdocs-material == 9.7.1\nmdx_truly_sane_lists == 1.3\nmike == 2.1.3\nmkdocs-git-revision-date-localized-pl"
  },
  {
    "path": "docs/serve.sh",
    "chars": 521,
    "preview": "#!/bin/bash\n\nset -e\n\nVENV_PATH=\"./.venv/\"\nPYTHON_CMD=${1:-python}\n\nif [ ! -d $VENV_PATH ]; then\n    echo \"venv not found"
  },
  {
    "path": "rustfmt.toml",
    "chars": 488,
    "preview": "reorder_imports = true\nreorder_modules = true\nmerge_derives = true\nfn_params_layout = \"Compressed\"\nuse_field_init_shorth"
  },
  {
    "path": "sample_configs/default_config.toml",
    "chars": 9069,
    "preview": "# This is a default config file for bottom. All of the settings are commented\n# out by default; if you wish to change th"
  },
  {
    "path": "sample_configs/demo_config.toml",
    "chars": 404,
    "preview": "[flags]\navg_cpu = true\n\n# Temperature is one of:\ntemperature_type = \"c\"\n\nrate = 1000\ncpu_left_legend = false\ncurrent_usa"
  },
  {
    "path": "schema/README.md",
    "chars": 1161,
    "preview": "# Config JSON Schema\n\n## Generation\n\nThese are automatically generated from code using [`schemars`](https://github.com/G"
  },
  {
    "path": "schema/nightly/bottom.json",
    "chars": 25390,
    "preview": "{\n  \"$id\": \"https://github.com/ClementTsang/bottom/blob/main/schema/nightly/bottom.json\",\n  \"$schema\": \"https://json-sch"
  },
  {
    "path": "schema/v0.10/bottom.json",
    "chars": 23316,
    "preview": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://github.com/ClementTsang/bottom/blob/main/sch"
  },
  {
    "path": "schema/v0.11/bottom.json",
    "chars": 25226,
    "preview": "{\n  \"$id\": \"https://github.com/ClementTsang/bottom/blob/main/schema/nightly/bottom.json\",\n  \"$schema\": \"https://json-sch"
  },
  {
    "path": "schema/v0.12.0/bottom.json",
    "chars": 25388,
    "preview": "{\n  \"$id\": \"https://github.com/ClementTsang/bottom/blob/main/schema/0.12.0/bottom.json\",\n  \"$schema\": \"https://json-sche"
  },
  {
    "path": "schema/v0.9/bottom.json",
    "chars": 12267,
    "preview": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://github.com/ClementTsang/bottom/blob/main/sch"
  },
  {
    "path": "scripts/ci/bsd_tests.sh",
    "chars": 1003,
    "preview": "#!/bin/sh\n\n# Script to be run by the `ci.yml` workflow for -BSD jobs based on the target.\n\nset -eu\n\nBSD_TARGET=\"${1:-}\"\n"
  },
  {
    "path": "scripts/ci/ci_bsd.sh",
    "chars": 726,
    "preview": "#!/bin/sh\n\n# Script to be run by the `ci.yml` workflow for -BSD jobs based on the target.\n\nset -eu\n\nBSD_TARGET=\"${1:-}\"\n"
  },
  {
    "path": "scripts/ci/cirrus_release.py",
    "chars": 9486,
    "preview": "#!/bin/python3\n\n# A simple script to trigger Cirrus CI builds and download the release artifacts\n# through Cirrus CI's G"
  },
  {
    "path": "scripts/ci/configure_git.sh",
    "chars": 183,
    "preview": "#!/bin/bash\n\ngit config --global user.name ${GIT_USER}\ngit config --global user.email ${GIT_EMAIL}\necho Name: $(git conf"
  },
  {
    "path": "scripts/clear_cache.py",
    "chars": 3693,
    "preview": "#!/bin/python3\n\n# A simple script to clean caches matching a PR ID.\n#\n# Expects a GitHub token in the environment variab"
  },
  {
    "path": "scripts/hooks/README.md",
    "chars": 140,
    "preview": "# Git Hooks\n\nOptional pre-push git hook. These are checked again in CI anyway, but may make it easier to check for issue"
  },
  {
    "path": "scripts/hooks/pre-push",
    "chars": 249,
    "preview": "#!/bin/sh\n\nset -e\n\necho \"Running pre-push hook:\"\n\necho \"Executing: cargo fmt --all -- --check\"\ncargo fmt --all -- --chec"
  },
  {
    "path": "scripts/schema/bad_file.toml",
    "chars": 29,
    "preview": "[flags]\nhide_avg_cpu = 'bad'\n"
  },
  {
    "path": "scripts/schema/generate.sh",
    "chars": 136,
    "preview": "#!/bin/bash\n\nset -e\n\ncd \"$(dirname \"$0\")\";\ncd ../..\n\ncargo run --bin schema --features=\"generate_schema\" -- $1 > schema/"
  },
  {
    "path": "scripts/schema/nightly.sh",
    "chars": 134,
    "preview": "#!/bin/bash\n\nset -e\n\ncd \"$(dirname \"$0\")\";\ncd ../..\n\ncargo run --bin schema --features=\"generate_schema\" > schema/nightl"
  },
  {
    "path": "scripts/schema/requirements.txt",
    "chars": 24,
    "preview": "jsonschema-rs == 0.32.1\n"
  },
  {
    "path": "scripts/schema/validator.py",
    "chars": 2162,
    "preview": "#!/bin/python3\n\n# A simple script to validate that a schema is valid for a file.\n\nimport argparse\nimport tomllib\nimport "
  },
  {
    "path": "scripts/windows/choco/bottom.nuspec.template",
    "chars": 3715,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Read this before creating packages: https://chocolatey.org/docs/create-packa"
  },
  {
    "path": "scripts/windows/choco/choco_packager.py",
    "chars": 1979,
    "preview": "# Because choco is a special case and I'm too lazy to make my\n# packaging script robust enough, so whatever, hard-code t"
  },
  {
    "path": "scripts/windows/choco/chocolateyinstall.ps1.template",
    "chars": 487,
    "preview": "$ErrorActionPreference = 'Stop';\n$toolsDir   = \"$(Split-Path -parent $MyInvocation.MyCommand.Definition)\"\n$url        = "
  },
  {
    "path": "src/app/data/mod.rs",
    "chars": 216,
    "preview": "//! How we manage data internally.\n\nmod time_series;\npub use time_series::{TimeSeriesData, Values};\n\nmod process;\npub us"
  },
  {
    "path": "src/app/data/process.rs",
    "chars": 1979,
    "preview": "use std::{collections::BTreeMap, vec::Vec};\n\nuse nohash::IntMap;\n\nuse crate::collection::processes::{Pid, ProcessHarvest"
  },
  {
    "path": "src/app/data/store.rs",
    "chars": 10815,
    "preview": "use std::{\n    time::{Duration, Instant},\n    vec::Vec,\n};\n\nuse super::{ProcessData, TimeSeriesData};\n#[cfg(feature = \"b"
  },
  {
    "path": "src/app/data/temperature.rs",
    "chars": 2374,
    "preview": "//! Code around temperature data.\n\nuse std::{fmt::Display, str::FromStr};\n\n#[derive(Clone, Debug, Copy, PartialEq, Eq, D"
  },
  {
    "path": "src/app/data/time_series.rs",
    "chars": 6600,
    "preview": "//! Time series data.\n\nuse std::{\n    cmp::Ordering,\n    time::{Duration, Instant},\n    vec::Vec,\n};\n\n#[cfg(feature = \"g"
  },
  {
    "path": "src/app/filter.rs",
    "chars": 3863,
    "preview": "use regex::Regex;\n\n/// Filters used by widgets to filter out certain entries.\n/// TODO: Move this out maybe?\n#[derive(De"
  },
  {
    "path": "src/app/layout_manager.rs",
    "chars": 46994,
    "preview": "use std::collections::BTreeMap;\n\nuse tui::layout::Constraint;\n\nuse crate::{constants::DEFAULT_WIDGET_ID, options::Option"
  },
  {
    "path": "src/app/states.rs",
    "chars": 14987,
    "preview": "use std::ops::Range;\n\nuse indexmap::IndexMap;\nuse rustc_hash::FxHashMap as HashMap;\nuse unicode_ellipsis::grapheme_width"
  },
  {
    "path": "src/app.rs",
    "chars": 117233,
    "preview": "pub mod data;\npub mod filter;\npub mod layout_manager;\npub mod states;\n\nuse std::time::Instant;\n\nuse concat_string::conca"
  },
  {
    "path": "src/bin/main.rs",
    "chars": 287,
    "preview": "//! Main entrypoint for the application.\n\nuse bottom::{reset_stdout, start_bottom};\n\nfn main() -> anyhow::Result<()> {\n "
  },
  {
    "path": "src/bin/schema.rs",
    "chars": 3052,
    "preview": "#![cfg(feature = \"generate_schema\")]\n#![expect(\n    clippy::unwrap_used,\n    reason = \"this is just used to generate jso"
  },
  {
    "path": "src/canvas/components/data_table/column.rs",
    "chars": 8292,
    "preview": "use std::{\n    borrow::Cow,\n    cmp::{max, min},\n    num::NonZeroU16,\n};\n\n/// A bound on the width of a column.\n#[derive"
  },
  {
    "path": "src/canvas/components/data_table/data_type.rs",
    "chars": 1417,
    "preview": "use std::{borrow::Cow, num::NonZeroU16};\n\nuse tui::widgets::Row;\n\nuse super::{ColumnHeader, DataTableColumn};\nuse crate:"
  },
  {
    "path": "src/canvas/components/data_table/draw.rs",
    "chars": 9966,
    "preview": "use std::{\n    cmp::{max, min},\n    iter::once,\n};\n\nuse concat_string::concat_string;\nuse tui::{\n    Frame,\n    layout::"
  },
  {
    "path": "src/canvas/components/data_table/props.rs",
    "chars": 635,
    "preview": "use std::borrow::Cow;\n\npub struct DataTableProps {\n    /// An optional title for the table.\n    pub title: Option<Cow<'s"
  },
  {
    "path": "src/canvas/components/data_table/sortable.rs",
    "chars": 14942,
    "preview": "use std::{borrow::Cow, marker::PhantomData, num::NonZeroU16};\n\nuse concat_string::concat_string;\nuse itertools::Itertool"
  },
  {
    "path": "src/canvas/components/data_table/state.rs",
    "chars": 2965,
    "preview": "use std::num::NonZeroU16;\n\nuse tui::{layout::Rect, widgets::TableState};\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq, De"
  },
  {
    "path": "src/canvas/components/data_table/styling.rs",
    "chars": 852,
    "preview": "use tui::{style::Style, widgets::BorderType};\n\nuse crate::options::config::style::Styles;\n\n#[derive(Default)]\npub struct"
  },
  {
    "path": "src/canvas/components/data_table.rs",
    "chars": 10558,
    "preview": "pub mod column;\npub mod data_type;\npub mod draw;\npub mod props;\npub mod sortable;\npub mod state;\npub mod styling;\n\nuse s"
  },
  {
    "path": "src/canvas/components/mod.rs",
    "chars": 155,
    "preview": "//! Lower-level or shared drawing components used throughout bottom.\n\npub mod data_table;\npub mod pipe_gauge;\npub mod ti"
  },
  {
    "path": "src/canvas/components/pipe_gauge.rs",
    "chars": 6934,
    "preview": "use tui::{\n    buffer::Buffer,\n    layout::Rect,\n    style::Style,\n    text::Line,\n    widgets::{Block, Widget},\n};\n\n#[d"
  },
  {
    "path": "src/canvas/components/time_graph/base.rs",
    "chars": 7957,
    "preview": "use std::{borrow::Cow, time::Instant};\n\nuse concat_string::concat_string;\nuse tui::{\n    Frame,\n    layout::{Constraint,"
  },
  {
    "path": "src/canvas/components/time_graph/variants/auto_y_axis.rs",
    "chars": 142,
    "preview": "//! A variant of a [`crate::canvas::components::time_graph::TimeGraph`] that\n//! automatically adjusts the y-axis based "
  },
  {
    "path": "src/canvas/components/time_graph/variants/percent.rs",
    "chars": 3096,
    "preview": "//! A variant of a [`TimeGraph`] that expects data to be in a percentage format, from 0.0 to 100.0.\n\nuse std::borrow::Co"
  },
  {
    "path": "src/canvas/components/time_graph/variants.rs",
    "chars": 377,
    "preview": "use tui::style::Style;\n\nuse crate::options::config::style::Styles;\n\npub(crate) mod auto_y_axis;\npub(crate) mod percent;\n"
  },
  {
    "path": "src/canvas/components/time_graph/vendored/canvas.rs",
    "chars": 11705,
    "preview": "//! Vendored from <https://github.com/fdehau/tui-rs/blob/fafad6c96109610825aad89c4bba5253e01101ed/src/widgets/canvas/mod"
  },
  {
    "path": "src/canvas/components/time_graph/vendored/grid.rs",
    "chars": 16511,
    "preview": "//! Vendored [starting from here](https://github.com/ratatui/ratatui/blob/65c520245aa20e99e64d9ffcb2062a4502a699ea/ratat"
  },
  {
    "path": "src/canvas/components/time_graph/vendored/points.rs",
    "chars": 5016,
    "preview": "use itertools::Itertools;\nuse tui::{\n    style::Color,\n    widgets::{\n        GraphType,\n        canvas::{Line as Canvas"
  },
  {
    "path": "src/canvas/components/time_graph/vendored.rs",
    "chars": 49502,
    "preview": "//! A [`tui::widgets::Chart`] but slightly more specialized to show\n//! right-aligned timeseries data.\n//!\n//! Generally"
  },
  {
    "path": "src/canvas/components/time_graph.rs",
    "chars": 413,
    "preview": "//! A graph displaying data in the y-axis over time in the x-axis.\n//!\n//! A \"base\" version is available, based on a ven"
  },
  {
    "path": "src/canvas/components/widget_carousel.rs",
    "chars": 7658,
    "preview": "use tui::{\n    Frame,\n    layout::{Alignment, Constraint, Direction, Layout, Rect},\n    text::{Line, Span},\n    widgets:"
  },
  {
    "path": "src/canvas/dialogs/help_dialog.rs",
    "chars": 4242,
    "preview": "use std::cmp::{max, min};\n\nuse tui::{\n    Frame,\n    layout::{Alignment, Rect},\n    text::{Line, Span},\n    widgets::{Pa"
  },
  {
    "path": "src/canvas/dialogs/mod.rs",
    "chars": 50,
    "preview": "pub mod help_dialog;\npub mod process_kill_dialog;\n"
  },
  {
    "path": "src/canvas/dialogs/process_kill_dialog.rs",
    "chars": 31232,
    "preview": "//! A dialog box to handle killing processes.\n\nuse std::time::Instant;\n\nuse cfg_if::cfg_if;\n#[cfg(any(target_os = \"linux"
  },
  {
    "path": "src/canvas/drawing_utils.rs",
    "chars": 2830,
    "preview": "use std::time::Instant;\n\nuse tui::{\n    layout::Rect,\n    widgets::{Block, BorderType, Borders},\n};\n\npub const SIDE_BORD"
  },
  {
    "path": "src/canvas/widgets/battery_display.rs",
    "chars": 13031,
    "preview": "use std::cmp::min;\n\nuse tui::{\n    Frame,\n    layout::{Constraint, Direction, Layout, Rect},\n    text::{Line, Span},\n   "
  },
  {
    "path": "src/canvas/widgets/cpu_basic.rs",
    "chars": 6529,
    "preview": "use std::cmp::min;\n\nuse itertools::Itertools;\nuse tui::{\n    Frame,\n    layout::{Constraint, Direction, Layout, Rect},\n}"
  },
  {
    "path": "src/canvas/widgets/cpu_graph.rs",
    "chars": 9727,
    "preview": "use tui::{\n    Frame,\n    layout::{Constraint, Direction, Layout, Rect},\n};\n\nuse crate::{\n    app::{App, data::StoredDat"
  },
  {
    "path": "src/canvas/widgets/disk_table.rs",
    "chars": 1103,
    "preview": "use tui::{Frame, layout::Rect};\n\nuse crate::{\n    app,\n    canvas::{\n        Painter,\n        components::data_table::{D"
  },
  {
    "path": "src/canvas/widgets/mem_basic.rs",
    "chars": 6362,
    "preview": "use std::borrow::Cow;\n\nuse tui::{\n    Frame,\n    layout::{Constraint, Direction, Layout, Rect},\n};\n\nuse crate::{\n    app"
  },
  {
    "path": "src/canvas/widgets/mem_graph.rs",
    "chars": 6670,
    "preview": "use std::time::Instant;\n\nuse tui::{\n    Frame,\n    layout::{Constraint, Rect},\n    style::Style,\n};\n\nuse crate::{\n    ap"
  },
  {
    "path": "src/canvas/widgets/mod.rs",
    "chars": 1934,
    "preview": "use crate::{collection::network::NetworkHarvest, utils::data_units::convert_bytes};\n\npub mod cpu_basic;\npub mod cpu_grap"
  },
  {
    "path": "src/canvas/widgets/network_basic.rs",
    "chars": 11910,
    "preview": "use tui::{\n    Frame,\n    layout::{Constraint, Direction, Layout, Rect},\n    text::{Line, Span},\n    widgets::{Block, Pa"
  },
  {
    "path": "src/canvas/widgets/network_graph.rs",
    "chars": 26415,
    "preview": "use std::time::Duration;\n\nuse tui::{\n    Frame,\n    layout::{Constraint, Direction, Layout, Rect},\n    symbols::Marker,\n"
  },
  {
    "path": "src/canvas/widgets/process_table.rs",
    "chars": 12127,
    "preview": "use tui::{\n    Frame,\n    layout::{Alignment, Constraint, Direction, Layout, Rect},\n    style::Style,\n    text::{Line, S"
  },
  {
    "path": "src/canvas/widgets/temperature_table.rs",
    "chars": 1103,
    "preview": "use tui::{Frame, layout::Rect};\n\nuse crate::{\n    app,\n    canvas::{\n        Painter,\n        components::data_table::{D"
  },
  {
    "path": "src/canvas.rs",
    "chars": 18595,
    "preview": "//! Code related to drawing.\n//!\n//! Note that eventually this should not contain any widget-specific draw code, but rat"
  },
  {
    "path": "src/collection/amd/amd_gpu_marketing.rs",
    "chars": 27309,
    "preview": "// from https://github.com/GPUOpen-Tools/device_info/blob/master/DeviceInfo.cpp\n\npub const AMDGPU_DEFAULT_NAME: &str = \""
  },
  {
    "path": "src/collection/amd.rs",
    "chars": 13499,
    "preview": "mod amd_gpu_marketing;\n\nuse std::{\n    fs::{self, read_to_string},\n    num::NonZeroU64,\n    path::{Path, PathBuf},\n    s"
  },
  {
    "path": "src/collection/batteries.rs",
    "chars": 3229,
    "preview": "//! Uses the battery crate.\n//!\n//! Covers battery usage for:\n//! - Linux 2.6.39+\n//! - MacOS 10.10+\n//! - iOS\n//! - Win"
  },
  {
    "path": "src/collection/cpu/sysinfo.rs",
    "chars": 1057,
    "preview": "//! CPU stats through sysinfo.\n//! Supports FreeBSD.\n\nuse sysinfo::System;\n\nuse super::{CpuData, CpuDataType, CpuHarvest"
  },
  {
    "path": "src/collection/cpu.rs",
    "chars": 351,
    "preview": "//! Data collection for CPU usage and load average.\n\npub mod sysinfo;\npub use self::sysinfo::*;\n\npub type LoadAvgHarvest"
  },
  {
    "path": "src/collection/disks/freebsd.rs",
    "chars": 3047,
    "preview": "//! Disk stats for FreeBSD.\n\nuse std::io;\n\nuse rustc_hash::FxHashMap as HashMap;\nuse serde::Deserialize;\n\nuse super::{Di"
  },
  {
    "path": "src/collection/disks/io_counters.rs",
    "chars": 569,
    "preview": "use std::ffi::OsStr;\n\n#[derive(Debug, Default)]\npub struct IoCounters {\n    name: String,\n    read_bytes: u64,\n    write"
  },
  {
    "path": "src/collection/disks/other.rs",
    "chars": 1616,
    "preview": "//! Fallback disk info using sysinfo.\n\nuse super::{DiskHarvest, keep_disk_entry};\nuse crate::collection::DataCollector;\n"
  },
  {
    "path": "src/collection/disks/unix/file_systems.rs",
    "chars": 5889,
    "preview": "use std::str::FromStr;\n\nuse crate::multi_eq_ignore_ascii_case;\n\n/// Known filesystems. Original list from\n/// [heim](htt"
  },
  {
    "path": "src/collection/disks/unix/linux/counters.rs",
    "chars": 3408,
    "preview": "//! Based on [heim's implementation](https://github.com/heim-rs/heim/blob/master/heim-disk/src/sys/linux/counters.rs).\n\n"
  },
  {
    "path": "src/collection/disks/unix/linux/mod.rs",
    "chars": 80,
    "preview": "mod counters;\nmod partition;\n\npub use counters::*;\npub(crate) use partition::*;\n"
  },
  {
    "path": "src/collection/disks/unix/linux/partition.rs",
    "chars": 6664,
    "preview": "//! Implementation based on [heim's](https://github.com/heim-rs/heim)\n//! Unix disk usage.\n\nuse std::{\n    ffi::CString,"
  },
  {
    "path": "src/collection/disks/unix/macos/counters.rs",
    "chars": 2326,
    "preview": "//! Based on [heim's implementation](https://github.com/heim-rs/heim/blob/master/heim-disk/src/sys/macos/counters.rs).\n\n"
  },
  {
    "path": "src/collection/disks/unix/macos/io_kit/bindings.rs",
    "chars": 2194,
    "preview": "//! C FFI bindings for [IOKit](https://developer.apple.com/documentation/iokit/).\n//!\n//! Based on [heim](https://github"
  },
  {
    "path": "src/collection/disks/unix/macos/io_kit/io_disks.rs",
    "chars": 638,
    "preview": "use anyhow::bail;\nuse mach2::kern_return;\n\nuse super::{IoIterator, bindings::*};\n\npub fn get_disks() -> anyhow::Result<I"
  },
  {
    "path": "src/collection/disks/unix/macos/io_kit/io_iterator.rs",
    "chars": 1403,
    "preview": "//! Based on [heim's](https://github.com/heim-rs/heim/blob/master/heim-common/src/sys/macos/iokit/io_iterator.rs).\n//! i"
  },
  {
    "path": "src/collection/disks/unix/macos/io_kit/io_object.rs",
    "chars": 4851,
    "preview": "//! Based on [heim's](https://github.com/heim-rs/heim/blob/master/heim-common/src/sys/macos/iokit/io_object.rs)\n//! impl"
  },
  {
    "path": "src/collection/disks/unix/macos/io_kit.rs",
    "chars": 136,
    "preview": "mod bindings;\nmod io_disks;\nmod io_iterator;\nmod io_object;\n\npub use io_disks::get_disks;\npub use io_iterator::*;\npub us"
  },
  {
    "path": "src/collection/disks/unix/macos/mod.rs",
    "chars": 48,
    "preview": "mod counters;\nmod io_kit;\n\npub use counters::*;\n"
  },
  {
    "path": "src/collection/disks/unix/other/bindings.rs",
    "chars": 1676,
    "preview": "//! Based on [heim's](https://github.com/heim-rs/heim/blob/master/heim-disk/src/sys/unix/bindings/mod.rs)\n//! implementa"
  },
  {
    "path": "src/collection/disks/unix/other/mod.rs",
    "chars": 59,
    "preview": "mod bindings;\nmod partition;\n\npub(crate) use partition::*;\n"
  },
  {
    "path": "src/collection/disks/unix/other/partition.rs",
    "chars": 2993,
    "preview": "use std::{\n    ffi::{CStr, CString},\n    os::unix::prelude::OsStrExt,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\nu"
  },
  {
    "path": "src/collection/disks/unix/usage.rs",
    "chars": 1166,
    "preview": "pub struct Usage(libc::statvfs);\n\n// Note that x86 returns `u32` values while x86-64 returns `u64`s, so we convert\n// ev"
  },
  {
    "path": "src/collection/disks/unix.rs",
    "chars": 2657,
    "preview": "//! Disk stats for Unix-like systems that aren't supported through other means.\n//! Officially, for now, this means Linu"
  },
  {
    "path": "src/collection/disks/windows/bindings.rs",
    "chars": 6136,
    "preview": "//! Windows bindings to get disk I/O counters.\n\nuse std::{\n    ffi::OsString,\n    io, mem,\n    os::windows::prelude::{Os"
  },
  {
    "path": "src/collection/disks/windows.rs",
    "chars": 2283,
    "preview": "//! Disk stats via sysinfo.\n\nmod bindings;\n\nuse bindings::*;\nuse itertools::Itertools;\n\nuse super::{DiskHarvest, keep_di"
  },
  {
    "path": "src/collection/disks/zfs_io_counters.rs",
    "chars": 6351,
    "preview": "use crate::collection::disks::IoCounters;\n\n/// Returns zpool I/O stats. Pulls data from `sysctl\n/// kstat.zfs.{POOL}.dat"
  },
  {
    "path": "src/collection/disks.rs",
    "chars": 5934,
    "preview": "//! Data collection about disks (e.g. I/O, usage, space).\n\ncfg_if! {\n    if #[cfg(target_os = \"freebsd\")] {\n        mod "
  },
  {
    "path": "src/collection/error.rs",
    "chars": 1278,
    "preview": "use anyhow::anyhow;\n\n/// An error to do with data collection.\n#[derive(Debug)]\npub enum CollectionError {\n    /// A gene"
  },
  {
    "path": "src/collection/linux/utils.rs",
    "chars": 1231,
    "preview": "use std::{fs, path::Path};\n\n/// Whether the temperature should *actually* be read during enumeration.\n/// Will return fa"
  },
  {
    "path": "src/collection/memory/arc.rs",
    "chars": 3289,
    "preview": "#[cfg(all(feature = \"zfs\", any(target_os = \"linux\", target_os = \"freebsd\")))]\nuse super::MemData;\n#[cfg(all(feature = \"z"
  },
  {
    "path": "src/collection/memory/sysinfo.rs",
    "chars": 1535,
    "preview": "//! Collecting memory data using sysinfo.\n\nuse std::num::NonZeroU64;\n\nuse sysinfo::System;\n\nuse crate::collection::memor"
  },
  {
    "path": "src/collection/memory/windows.rs",
    "chars": 3246,
    "preview": "use std::{mem::zeroed, num::NonZeroU64};\n\nuse sysinfo::System;\nuse windows::{\n    Win32::{\n        Foundation::ERROR_SUC"
  },
  {
    "path": "src/collection/memory.rs",
    "chars": 725,
    "preview": "//! Memory data collection.\n\nuse std::num::NonZeroU64;\n\npub(crate) use self::sysinfo::get_ram_usage;\n\npub mod sysinfo;\n\n"
  },
  {
    "path": "src/collection/network/sysinfo.rs",
    "chars": 2043,
    "preview": "//! Gets network data via sysinfo.\n\nuse std::time::Instant;\n\nuse sysinfo::Networks;\n\nuse super::NetworkHarvest;\nuse crat"
  },
  {
    "path": "src/collection/network.rs",
    "chars": 480,
    "preview": "//! Data collection for network usage/IO.\n\npub mod sysinfo;\npub use self::sysinfo::*;\n\n#[derive(Default, Clone, Debug)]\n"
  },
  {
    "path": "src/collection/nvidia.rs",
    "chars": 7432,
    "preview": "use std::{num::NonZeroU64, sync::OnceLock};\n\nuse nohash::IntMap;\nuse nvml_wrapper::{\n    Nvml, enum_wrappers::device::Te"
  },
  {
    "path": "src/collection/processes/freebsd.rs",
    "chars": 1781,
    "preview": "//! Process data collection for FreeBSD.  Uses sysinfo.\n\nuse std::{io, process::Command};\n\nuse nohash::IntMap;\nuse serde"
  },
  {
    "path": "src/collection/processes/linux/mod.rs",
    "chars": 19036,
    "preview": "//! Process data collection for Linux.\n\nmod process;\n\nuse std::{\n    fs::{self, File},\n    io::{BufRead, BufReader},\n   "
  },
  {
    "path": "src/collection/processes/linux/process.rs",
    "chars": 11949,
    "preview": "//! Linux process code for getting process data via `/proc/`.\n//! Based on the [procfs](https://github.com/eminence/proc"
  },
  {
    "path": "src/collection/processes/macos/sysctl_bindings.rs",
    "chars": 7877,
    "preview": "//! Partial bindings from Apple's open source code for getting process\n//! information. Some of this is based on [heim's"
  },
  {
    "path": "src/collection/processes/macos.rs",
    "chars": 1874,
    "preview": "//! Process data collection for macOS.  Uses sysinfo and custom bindings.\n\npub mod sysctl_bindings;\n\nuse std::{io, proce"
  },
  {
    "path": "src/collection/processes/unix/process_ext.rs",
    "chars": 9632,
    "preview": "//! Shared process data harvesting code from macOS and FreeBSD via sysinfo.\n\nuse std::{io, time::Duration};\n\nuse cfg_if:"
  },
  {
    "path": "src/collection/processes/unix/user_table.rs",
    "chars": 1273,
    "preview": "use std::sync::Arc;\n\nuse rustc_hash::FxHashMap as HashMap;\n\nuse crate::collection::error::{CollectionError, CollectionRe"
  },
  {
    "path": "src/collection/processes/unix.rs",
    "chars": 1414,
    "preview": "//! Unix-specific parts of process collection.\n\nmod user_table;\n\nuse cfg_if::cfg_if;\npub use user_table::*;\n\ncfg_if! {\n "
  },
  {
    "path": "src/collection/processes/windows.rs",
    "chars": 6164,
    "preview": "//! Process data collection for Windows. Uses sysinfo.\n\nuse std::time::Duration;\n\nuse anyhow::bail;\nuse itertools::Itert"
  },
  {
    "path": "src/collection/processes.rs",
    "chars": 6662,
    "preview": "//! Data collection for processes.\n//!\n//! For Linux, this is handled by a custom set of functions.\n//! For Windows, mac"
  },
  {
    "path": "src/collection/temperature/linux.rs",
    "chars": 18194,
    "preview": "//! Gets temperature sensor data for Linux platforms.\n\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n};\n\nuse anyhow::Res"
  },
  {
    "path": "src/collection/temperature/sysinfo.rs",
    "chars": 1428,
    "preview": "//! Gets temperature data via sysinfo.\n\nuse anyhow::Result;\n\nuse super::TempSensorData;\nuse crate::app::filter::Filter;\n"
  },
  {
    "path": "src/collection/temperature.rs",
    "chars": 529,
    "preview": "//! Data collection for temperature metrics.\n//!\n//! For Linux, this is handled by custom code.\n//! For everything else,"
  },
  {
    "path": "src/collection.rs",
    "chars": 22055,
    "preview": "//! This is the main file to house data collection functions.\n//!\n//! TODO: Rename this to intake? Collection?\n\n#[cfg(fe"
  },
  {
    "path": "src/constants.rs",
    "chars": 19440,
    "preview": "//! A bunch of constants used throughout the application.\n//!\n//! FIXME: Move these to where it makes more sense.\n\n// De"
  }
]

// ... and 85 more files (download for full content)

About this extraction

This page contains the full source code of the ClementTsang/bottom GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 285 files (1.6 MB), approximately 386.2k tokens, and a symbol index with 1377 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!