{ config, lib, pkgs, ... }: with lib; let cfg = config.programs.htop; formatOption = n: v: let v' = if isBool v then (if v then "1" else "0") else toString v; in "${n}=${v'}"; formatMeters = side: meters: let warn' = warn "htop: meters should be passed as a list"; meters' = if isList meters then meters else warn' [ meters ]; in { "${side}_meters" = concatMap (mapAttrsToList (x: _: x)) meters'; "${side}_meter_modes" = concatMap (mapAttrsToList (_: y: y)) meters'; }; leftMeters = formatMeters "left"; rightMeters = formatMeters "right"; fields = { PID = 0; COMM = 1; STATE = 2; PPID = 3; PGRP = 4; SESSION = 5; TTY_NR = 6; TPGID = 7; MINFLT = 9; MAJFLT = 11; PRIORITY = 17; NICE = 18; STARTTIME = 20; PROCESSOR = 37; M_SIZE = 38; M_RESIDENT = 39; ST_UID = 45; PERCENT_CPU = 46; PERCENT_MEM = 47; USER = 48; TIME = 49; NLWP = 50; TGID = 51; CMINFLT = 10; CMAJFLT = 12; UTIME = 13; STIME = 14; CUTIME = 15; CSTIME = 16; M_SHARE = 40; M_TRS = 41; M_DRS = 42; M_LRS = 43; M_DT = 44; CTID = 99; VPID = 100; VXID = 102; RCHAR = 102; WCHAR = 103; SYSCR = 104; SYSCW = 105; RBYTES = 106; WBYTES = 107; CNCLWB = 108; IO_READ_RATE = 109; IO_WRITE_RATE = 110; IO_RATE = 111; CGROUP = 112; OOM = 113; IO_PRIORITY = 114; M_PSS = 118; M_SWAP = 119; M_PSSWP = 120; }; modes = { Bar = 1; Text = 2; Graph = 3; LED = 4; }; # Utilities for constructing meters meter = mode: name: { ${name} = mode; }; bar = meter modes.Bar; text = meter modes.Text; graph = meter modes.Graph; led = meter modes.LED; blank = text "Blank"; # Mapping from names to defaults meters = { Clock = 2; Date = 2; DateTime = 2; LoadAverage = 2; Load = 2; Memory = 1; Swap = 1; Zram = 2; HugePages = 2; Tasks = 2; Uptime = 2; Battery = 2; Hostname = 2; AllCPUs = 1; AllCPUs2 = 1; AllCPUs4 = 1; AllCPUs8 = 1; LeftCPUs = 1; RightCPUs = 1; Right = 1; CPUs = 1; LeftCPUs2 = 1; RightCPUs2 = 1; LeftCPUs4 = 1; RightCPUs4 = 1; LeftCPUs8 = 1; RightCPUs8 = 1; Blank = 2; PressureStallCPUSome = 2; PressureStallIOSome = 2; PressureStallIOFull = 2; PressureStallMemorySome = 2; PressureStallMemoryFull = 2; ZFSARC = 2; ZFSCARC = 2; CPU = 1; "CPU(1)" = 1; "CPU(2)" = 1; "CPU(3)" = 1; "CPU(4)" = 1; "CPU(5)" = 1; "CPU(6)" = 1; "CPU(7)" = 1; "CPU(8)" = 1; SELinux = 2; Systemd = 2; DiskIO = 2; NetworkIO = 2; }; singleMeterType = let meterEnum = types.enum (attrNames meters); meterSubmodule = types.submodule { options = { kind = mkOption { type = types.enum (attrNames meters); example = "AllCPUs"; description = "What kind of meter."; }; mode = mkOption { type = types.enum [ 1 2 3 4 ]; example = 2; description = "Which mode the meter should use, one of 1(Bar) 2(Text) 3(Graph) 4(LED)."; }; }; }; in types.coercedTo meterEnum (m: { kind = m; mode = meters.${m}; }) meterSubmodule; meterType = types.submodule { options = { left = mkOption { description = "Meters shown in the left header."; default = [ "AllCPUs" "Memory" "Swap" ]; example = [ "Memory" "LeftCPUs2" "RightCPUs2" { kind = "CPU"; mode = 3; } ]; type = types.listOf singleMeterType; }; right = mkOption { description = "Meters shown in the right header."; default = [ "Tasks" "LoadAverage" "Uptime" ]; example = [ { kind = "Clock"; mode = 4; } "Uptime" "Tasks" ]; type = types.listOf singleMeterType; }; }; }; in { options.programs.htop = { enable = mkEnableOption "htop"; settings = mkOption { type = types.attrs; default = { account_guest_in_cpu_meter = false; color_scheme = 0; cpu_count_from_zero = false; delay = 15; detailed_cpu_time = false; enable_mouse = true; fields = with fields; [ PID USER PRIORITY NICE M_SIZE M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME COMM ]; header_margin = true; hide_kernel_threads = true; hide_threads = false; hide_userland_threads = false; highlight_base_name = false; highlight_megabytes = true; highlight_threads = true; shadow_other_users = false; show_cpu_frequency = false; show_cpu_usage = false; show_program_path = true; show_thread_names = false; sort_direction = 1; sort_key = fields.PERCENT_CPU; tree_view = false; update_process_names = false; vim_mode = false; } // (leftMeters [ (bar "AllCPUs2") (bar "Memory") (bar "Swap") (text "Zram") ]) // (rightMeters [ (text "Tasks") (text "LoadAverage") (text "Uptime") (text "Systemd") ]); example = literalExample '' { color_scheme = 6; cpu_count_from_one = 0; delay = 15; fields = with config.lib.htop.fields; [ PID USER PRIORITY NICE M_SIZE M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME COMM ]; highlight_base_name = 1; highlight_megabytes = 1; highlight_threads = 1; } // (with config.lib.htop; leftMeters [ (bar "AllCPUs2") (bar "Memory") (bar "Swap") (text "Zram") ]) // (with config.lib.htop; rightMeters [ (text "Tasks") (text "LoadAverage") (text "Uptime") (text "Systemd") ]); ''; description = '' Configuration options to add to ~/.config/htop/htoprc. This superseedes any other (deprecated) settings in this module. ''; }; fields = mkOption { type = types.nullOr (types.listOf (types.enum (attrNames fields))); default = null; example = [ "PID" "USER" "PRIORITY" "PERCENT_CPU" "M_RESIDENT" "PERCENT_MEM" "TIME" "COMM" ]; description = '' Deprecated. Please use programs.htop.settings.fields instead. Active fields shown in the table. ''; }; sortKey = mkOption { type = types.nullOr (types.enum (attrNames fields)); default = null; example = "TIME"; description = '' Deprecated. Please use programs.htop.settings.sort_key instead. Which field to use for sorting. ''; }; sortDescending = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.sort_direction instead. Whether to sort descending or not. ''; }; hideThreads = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.hide_threads instead. Hide threads. ''; }; hideKernelThreads = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.hide_kernel_threads instead. Hide kernel threads. ''; }; hideUserlandThreads = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.hide_userland_threads instead. Hide userland process threads. ''; }; shadowOtherUsers = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.shadow_other_users instead. Shadow other users' processes. ''; }; showThreadNames = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.show_thread_names instead. Show custom thread names. ''; }; showProgramPath = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.show_program_path instead. Show program path. ''; }; highlightBaseName = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.highlight_base_name instead. Highlight program basename. ''; }; highlightMegabytes = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.highlight_megabytes instead. Highlight large numbers in memory counters. ''; }; highlightThreads = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.highlight_threads instead. Display threads in a different color. ''; }; treeView = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.tree_view instead. Tree view. ''; }; headerMargin = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.header_margin instead. Leave a margin around header. ''; }; detailedCpuTime = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.detailed_cpu_time instead. Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest). ''; }; cpuCountFromZero = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.cpu_count_from_zero instead. Count CPUs from 0 instead of 1. ''; }; showCpuUsage = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.show_cpu_usage instead. Show CPU usage frequency. ''; }; showCpuFrequency = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.show_cpu_frequency instead. Show CPU frequency. ''; }; updateProcessNames = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.update_process_names instead. Update process names on every refresh. ''; }; accountGuestInCpuMeter = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.account_guest_in_cpu_meter instead. Add guest time in CPU meter percentage. ''; }; colorScheme = mkOption { type = types.nullOr (types.enum [ 0 1 2 3 4 5 6 ]); default = null; example = 6; description = '' Deprecated. Please use programs.htop.settings.color_scheme instead. Which color scheme to use. ''; }; enableMouse = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.enable_mouse instead. Enable mouse support. ''; }; delay = mkOption { type = types.nullOr types.int; default = null; example = 2; description = '' Deprecated. Please use programs.htop.settings.delay instead. Set the delay between updates, in tenths of seconds. ''; }; meters = mkOption { description = '' Deprecated. Please use programs.htop.settings.left_meters, programs.htop.settings.left_meter_modes, programs.htop.settings.right_meters and programs.htop.settings.right_meter_modes instead. Or consider using lib.htop.leftMeters and lib.htop.rightMeters. Meters shown in the header. ''; default = null; example = { left = [ "Memory" "CPU" "LeftCPUs2" "RightCPUs2" { kind = "CPU"; mode = 3; } ]; right = [ { kind = "Clock"; mode = 4; } "Uptime" "Tasks" "LoadAverage" { kind = "Battery"; mode = 1; } ]; }; type = types.nullOr meterType; }; vimMode = mkOption { type = types.nullOr types.bool; default = null; description = '' Deprecated. Please use programs.htop.settings.vim_mode instead. Vim key bindings. ''; }; }; config = mkIf cfg.enable { lib.htop = { inherit fields modes leftMeters rightMeters bar text graph led blank; }; home.packages = [ pkgs.htop ]; xdg.configFile."htop/htoprc".text = let deprecate = settingsKey: optionKey: optionValue: let warn' = warn "htop: programs.htop.${optionKey} is deprecated; please is programs.htop.settings.${settingsKey} instead"; in if !isNull optionValue then warn' optionValue else if hasAttr settingsKey cfg.settings then cfg.settings.${settingsKey} else null; deprecate' = settingsKey: optionKey: deprecate settingsKey optionKey cfg.${optionKey}; ifNonNull = x: y: if isNull x then null else y; leftMeters = deprecate "left_meters" "meters.left" (ifNonNull cfg.meters (map (m: m.kind) cfg.meters.left)); leftModes = deprecate "left_meter_modes" "meters.left" (ifNonNull cfg.meters (map (m: m.mode) cfg.meters.left)); rightMeters = deprecate "right_meters" "meters.right" (ifNonNull cfg.meters (map (m: m.kind) cfg.meters.right)); rightModes = deprecate "right_meter_modes" "meters.right" (ifNonNull cfg.meters (map (m: m.mode) cfg.meters.right)); settings' = cfg.settings // (filterAttrs (_: v: !isNull v) { fields = deprecate "fields" "fields" (ifNonNull cfg.fields (map (n: fields.${n}) cfg.fields)); sort_key = deprecate "sort_key" "sortKey" (ifNonNull cfg.sortKey fields.${cfg.sortKey}); sort_direction = deprecate' "sort_direction" "sortDescending"; hide_threads = deprecate' "hide_threads" "hideThreads"; hide_kernel_threads = deprecate' "hide_kernel_threads" "hideKernelThreads"; hide_userland_threads = deprecate' "hide_userland_threads" "hideUserlandThreads"; shadow_other_users = deprecate' "shadow_other_users" "shadowOtherUsers"; show_thread_names = deprecate' "show_thread_names" "showThreadNames"; show_program_path = deprecate' "show_program_path" "showProgramPath"; highlight_base_name = deprecate' "highlight_base_name" "highlightBaseName"; highlight_megabytes = deprecate' "highlight_megabytes" "highlightMegabytes"; highlight_threads = deprecate' "highlight_threads" "highlightThreads"; tree_view = deprecate' "tree_view" "treeView"; header_margin = deprecate' "header_margin" "headerMargin"; detailed_cpu_time = deprecate' "detailed_cpu_time" "detailedCpuTime"; cpu_count_from_zero = deprecate' "cpu_count_from_zero" "cpuCountFromZero"; show_cpu_usage = deprecate' "show_cpu_usage" "showCpuUsage"; show_cpu_frequency = deprecate' "show_cpu_frequency" "showCpuFrequency"; update_process_names = deprecate' "update_process_names" "updateProcessNames"; account_guest_in_cpu_meter = deprecate' "account_guest_in_cpu_meter" "accountGuestInCpuMeter"; color_scheme = deprecate' "color_scheme" "colorScheme"; enable_mouse = deprecate' "enable_mouse" "enableMouse"; delay = deprecate' "delay" "delay"; left_meters = leftMeters; left_meter_modes = leftModes; right_meters = rightMeters; right_meter_modes = rightModes; vim_mode = deprecate' "vim_mode" "vimMode"; }); in concatStringsSep "\n" (mapAttrsToList formatOption settings'); }; }