1{ config, lib, pkgs, ... }:
2
3let
4
5 cfg = config.programs.less;
6
7 configText = if (cfg.configFile != null) then (builtins.readFile cfg.configFile) else ''
8 #command
9 ${builtins.concatStringsSep "\n"
10 (lib.mapAttrsToList (command: action: "${command} ${action}") cfg.commands)
11 }
12 ${lib.optionalString cfg.clearDefaultCommands "#stop"}
13
14 #line-edit
15 ${builtins.concatStringsSep "\n"
16 (lib.mapAttrsToList (command: action: "${command} ${action}") cfg.lineEditingKeys)
17 }
18
19 #env
20 ${builtins.concatStringsSep "\n"
21 (lib.mapAttrsToList (variable: values: "${variable}=${values}") cfg.envVariables)
22 }
23 '';
24
25 lessKey = pkgs.writeText "lessconfig" configText;
26
27in
28
29{
30 options = {
31
32 programs.less = {
33
34 # note that environment.nix sets PAGER=less, and
35 # therefore also enables this module
36 enable = lib.mkEnableOption "less, a file pager";
37
38 configFile = lib.mkOption {
39 type = lib.types.nullOr lib.types.path;
40 default = null;
41 example = lib.literalExpression ''"''${pkgs.my-configs}/lesskey"'';
42 description = ''
43 Path to lesskey configuration file.
44
45 {option}`configFile` takes precedence over {option}`commands`,
46 {option}`clearDefaultCommands`, {option}`lineEditingKeys`, and
47 {option}`envVariables`.
48 '';
49 };
50
51 commands = lib.mkOption {
52 type = lib.types.attrsOf lib.types.str;
53 default = {};
54 example = {
55 h = "noaction 5\\e(";
56 l = "noaction 5\\e)";
57 };
58 description = "Defines new command keys.";
59 };
60
61 clearDefaultCommands = lib.mkOption {
62 type = lib.types.bool;
63 default = false;
64 description = ''
65 Clear all default commands.
66 You should remember to set the quit key.
67 Otherwise you will not be able to leave less without killing it.
68 '';
69 };
70
71 lineEditingKeys = lib.mkOption {
72 type = lib.types.attrsOf lib.types.str;
73 default = {};
74 example = {
75 e = "abort";
76 };
77 description = "Defines new line-editing keys.";
78 };
79
80 envVariables = lib.mkOption {
81 type = lib.types.attrsOf lib.types.str;
82 default = {
83 LESS = "-R";
84 };
85 example = {
86 LESS = "--quit-if-one-screen";
87 };
88 description = "Defines environment variables.";
89 };
90
91 lessopen = lib.mkOption {
92 type = lib.types.nullOr lib.types.str;
93 default = "|${pkgs.lesspipe}/bin/lesspipe.sh %s";
94 defaultText = lib.literalExpression ''"|''${pkgs.lesspipe}/bin/lesspipe.sh %s"'';
95 description = ''
96 Before less opens a file, it first gives your input preprocessor a chance to modify the way the contents of the file are displayed.
97 '';
98 };
99
100 lessclose = lib.mkOption {
101 type = lib.types.nullOr lib.types.str;
102 default = null;
103 description = ''
104 When less closes a file opened in such a way, it will call another program, called the input postprocessor,
105 which may perform any desired clean-up action (such as deleting the replacement file created by LESSOPEN).
106 '';
107 };
108 };
109 };
110
111 config = lib.mkIf cfg.enable {
112
113 environment.systemPackages = [ pkgs.less ];
114
115 environment.variables = {
116 LESSKEYIN_SYSTEM = builtins.toString lessKey;
117 } // lib.optionalAttrs (cfg.lessopen != null) {
118 LESSOPEN = cfg.lessopen;
119 } // lib.optionalAttrs (cfg.lessclose != null) {
120 LESSCLOSE = cfg.lessclose;
121 };
122
123 warnings = lib.optional (
124 cfg.clearDefaultCommands && (builtins.all (x: x != "quit") (builtins.attrValues cfg.commands))
125 ) ''
126 config.programs.less.clearDefaultCommands clears all default commands of less but there is no alternative binding for exiting.
127 Consider adding a binding for 'quit'.
128 '';
129 };
130
131 meta.maintainers = with lib.maintainers; [ johnazoidberg ];
132
133}