diff --git a/modules/default.nix b/modules/default.nix index 97db96b95..0b163c7d2 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -21,6 +21,7 @@ let ./programs/git.nix ./programs/gnome-terminal.nix ./programs/home-manager.nix + ./programs/htop.nix ./programs/info.nix ./programs/lesspipe.nix ./programs/ssh.nix diff --git a/modules/programs/htop.nix b/modules/programs/htop.nix new file mode 100644 index 000000000..b0f1a237d --- /dev/null +++ b/modules/programs/htop.nix @@ -0,0 +1,331 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.htop; + + list = xs: concatMapStrings (x: "${toString x} ") xs; + + bool = b: if b then "1" else "0"; + + 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; + }; + + # Mapping from names to defaults + meters = { + Clock = 2; + LoadAverage = 2; + Load = 2; + Memory = 1; + Swap = 1; + Tasks = 2; + Uptime = 2; + Battery = 2; + Hostname = 2; + AllCPUs = 1; + AllCPUs2 = 1; + LeftCPUs = 1; + RightCPUs = 1; + LeftCPUs2 = 1; + RightCPUs2 = 1; + Blank = 2; + CPU = 1; + "CPU(1)"= 1; + "CPU(2)" = 1; + "CPU(3)" = 1; + "CPU(4)" = 1; + }; + + singleMeterType = types.either (types.enum (attrNames meters)) (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)."; + }; + }; + }); + + # Converts the meter to an attribute set if it isn't already + meterStandard = m: if builtins.isString m then { + kind = m; + mode = meters.${m}; + } else m; + + + 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"; + + fields = mkOption { + type = types.listOf (types.enum (attrNames fields)); + default = [ "PID" "USER" "PRIORITY" "NICE" "M_SIZE" "M_RESIDENT" "M_SHARE" "STATE" "PERCENT_CPU" "PERCENT_MEM" "TIME" "COMM" ]; + example = [ "PID" "USER" "PRIORITY" "PERCENT_CPU" "M_RESIDENT" "PERCENT_MEM" "TIME" "COMM" ]; + description = "Active fields shown in the table."; + }; + + sortKey = mkOption { + type = types.enum (attrNames fields); + default = "PERCENT_CPU"; + example = "TIME"; + description = "Which field to use for sorting."; + }; + + sortDescending = mkOption { + type = types.bool; + default = true; + description = "Whether to sort descending or not."; + }; + + hideThreads = mkOption { + type = types.bool; + default = false; + description = "Hide threads."; + }; + + hideKernelThreads = mkOption { + type = types.bool; + default = true; + description = "Hide kernel threads."; + }; + + hideUserlandThreads = mkOption { + type = types.bool; + default = false; + description = "Hide userland process threads."; + }; + + shadowOtherUsers = mkOption { + type = types.bool; + default = false; + description = "Shadow other users' processes."; + }; + + showThreadNames = mkOption { + type = types.bool; + default = false; + description = "Show custom thread names."; + }; + + showProgramPath = mkOption { + type = types.bool; + default = true; + description = "Show program path."; + }; + + highlightBaseName = mkOption { + type = types.bool; + default = false; + description = "Highlight program basename."; + }; + + highlightMegabytes = mkOption { + type = types.bool; + default = true; + description = "Highlight large numbers in memory counters."; + }; + + highlightThreads = mkOption { + type = types.bool; + default = true; + description = "Display threads in a different color."; + }; + + treeView = mkOption { + type = types.bool; + default = false; + description = "Tree view."; + }; + + headerMargin = mkOption { + type = types.bool; + default = true; + description = "Leave a margin around header."; + }; + + detailedCpuTime = mkOption { + type = types.bool; + default = false; + description = "Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)."; + }; + + cpuCountFromZero = mkOption { + type = types.bool; + default = false; + description = "Count CPUs from 0 instead of 1."; + }; + + updateProcessNames = mkOption { + type = types.bool; + default = false; + description = "Update process names on every refresh."; + }; + + accountGuestInCpuMeter = mkOption { + type = types.bool; + default = false; + description = "Add guest time in CPU meter percentage."; + }; + + colorScheme = mkOption { + type = types.enum [ 0 1 2 3 4 5 6 ]; + default = 0; + example = 6; + description = "Which color scheme to use."; + }; + + delay = mkOption { + type = types.int; + default = 15; + example = 2; + description = "Set the delay between updates, in tenths of seconds."; + }; + + meters = mkOption { + description = "Meters shown in the header."; + default = { + left = [ "AllCPUs" "Memory" "Swap" ]; + right = [ "Tasks" "LoadAverage" "Uptime" ]; + }; + example = { + left = [ + "Memory" + "CPU" + "LeftCPUs2" + "RightCPUs2" + { kind = "CPU"; mode = 3; } + ]; + right = [ + { kind = "Clock"; mode = 4; } + "Uptime" + "Tasks" + "LoadAverage" + { kind = "Battery"; mode = 1; } + ]; + }; + type = meterType; + }; + + }; + + config = mkIf cfg.enable { + home.packages = [ pkgs.htop ]; + + home.file.".config/htop/htoprc".text = let + leftMeters = map (m: (meterStandard m).kind) cfg.meters.left; + leftModes = map (m: (meterStandard m).mode) cfg.meters.left; + rightMeters = map (m: (meterStandard m).kind) cfg.meters.right; + rightModes = map (m: (meterStandard m).mode) cfg.meters.right; + in '' + # This file is regenerated by home-manager + # when options are changed in the config + fields=${list (map (n: fields.${n}) cfg.fields)} + sort_key=${toString (fields.${cfg.sortKey})} + sort_direction=${bool cfg.sortDescending} + hide_threads=${bool cfg.hideThreads} + hide_kernel_threads=${bool cfg.hideKernelThreads} + hide_userland_threads=${bool cfg.hideUserlandThreads} + shadow_other_users=${bool cfg.shadowOtherUsers} + show_thread_names=${bool cfg.showThreadNames} + show_program_path=${bool cfg.showProgramPath} + highlight_base_name=${bool cfg.highlightBaseName} + highlight_megabytes=${bool cfg.highlightMegabytes} + highlight_threads=${bool cfg.highlightThreads} + tree_view=${bool cfg.treeView} + header_margin=${bool cfg.headerMargin} + detailed_cpu_time=${bool cfg.detailedCpuTime} + cpu_count_from_zero=${bool cfg.cpuCountFromZero} + update_process_names=${bool cfg.updateProcessNames} + account_guest_in_cpu_meter=${bool cfg.accountGuestInCpuMeter} + color_scheme=${toString cfg.colorScheme} + delay=${toString cfg.delay} + left_meters=${list leftMeters} + left_meter_modes=${list leftModes} + right_meters=${list rightMeters} + right_meter_modes=${list rightModes} + ''; + }; +}