1def _obj_to_csv_kv:
2  [to_entries[] | [.key, .value] | join("=")] | join(",");
3
4def _opt_build_default_fixed:
5  ( (null | stdout) as $stdout
6  | {
7      addrbase:       16,
8      arg:            [],
9      argjson:        [],
10      array_truncate: 50,
11      bits_format:    "snippet",
12      byte_colors:    "0-0xff=brightwhite,0=brightblack,32-126:9-13=white",
13      color:          ($stdout.is_terminal and (env.NO_COLOR | . == null or . == "")),
14      colors: (
15        {
16          null: "brightblack",
17          false: "yellow",
18          true: "yellow",
19          number: "cyan",
20          string: "green",
21          objectkey: "brightblue",
22          array: "white",
23          object: "white",
24          index: "white",
25          value: "white",
26          error: "brightred",
27          dumpheader: "yellow+underline",
28          dumpaddr: "yellow"
29        } | _obj_to_csv_kv
30      ),
31      compact:         false,
32      decode_file:      [],
33      decode_format:   "probe",
34      decode_progress: (env.NO_DECODE_PROGRESS == null),
35      depth:           0,
36      expr:            ".",
37      expr_eval_path:  "arg",
38      expr_file:       null,
39      filenames:       null,
40      include_path:    null,
41      join_string:     "\n",
42      null_input:      false,
43      raw_file:         [],
44      raw_output:      ($stdout.is_terminal | not),
45      raw_string:      false,
46      repl:            false,
47      sizebase:        10,
48      show_formats:    false,
49      show_help:       false,
50      slurp:           false,
51      string_input:    false,
52      unicode:         ($stdout.is_terminal and env.CLIUNICODE != null),
53      verbose:         false,
54    }
55  );
56
57def _opt_default_dynamic:
58  ( (null | stdout) as $stdout
59  | {
60      # TODO: intdiv 2 * 2 to get even number, nice or maybe not needed?
61      display_bytes:   (if $stdout.is_terminal then [_intdiv(_intdiv($stdout.width; 8); 2) * 2, 4] | max else 16 end),
62      line_bytes:      (if $stdout.is_terminal then [_intdiv(_intdiv($stdout.width; 8); 2) * 2, 4] | max else 16 end),
63    }
64  );
65
66# these _to* function do a bit for fuzzy string to type conversions
67def _opt_toboolean:
68  try
69    if . == "true" then true
70    elif . == "false" then false
71    else tonumber != 0
72    end
73  catch
74    null;
75
76def _opt_tonumber:
77  try tonumber catch null;
78
79def _opt_tostring:
80  if . != null then
81    ( "\"\(.)\""
82    | try
83        ( fromjson
84        | if type != "string" then error end
85        )
86      catch null
87    )
88  end;
89
90def _opt_toarray(f):
91  try
92    ( fromjson
93    | if type == "array" and (all(f) | not) then null end
94    )
95  catch null;
96
97def _opt_is_string_pair:
98  type == "array" and length == 2 and all(type == "string");
99
100def _opt_cli_arg_options:
101  ( {
102      addrbase:        (.addrbase | _opt_tonumber),
103      arg:             (.arg | _opt_toarray(_opt_is_string_pair)),
104      argjson:         (.argjson | _opt_toarray(_opt_is_string_pair)),
105      array_truncate:  (.array_truncate | _opt_tonumber),
106      bits_format:     (.bits_format | _opt_tostring),
107      byte_colors:     (.byte_colors | _opt_tostring),
108      color:           (.color | _opt_toboolean),
109      colors:          (.colors | _opt_tostring),
110      compact:         (.compact | _opt_toboolean),
111      decode_file:     (.decode_file | _opt_toarray(_opt_is_string_pair)),
112      decode_format:   (.decode_format | _opt_tostring),
113      decode_progress: (.decode_progress | _opt_toboolean),
114      depth:           (.depth | _opt_tonumber),
115      display_bytes:   (.display_bytes | _opt_tonumber),
116      expr:            (.expr | _opt_tostring),
117      expr_file:       (.expr_file | _opt_tostring),
118      filenames:       (.filenames | _opt_toarray(type == "string")),
119      include_path:    (.include_path | _opt_tostring),
120      join_string:     (.join_string | _opt_tostring),
121      line_bytes:      (.line_bytes | _opt_tonumber),
122      null_input:      (.null_input | _opt_toboolean),
123      raw_file:        (.raw_file| _opt_toarray(_opt_is_string_pair)),
124      raw_output:      (.raw_output | _opt_toboolean),
125      raw_string:      (.raw_string | _opt_toboolean),
126      repl:            (.repl | _opt_toboolean),
127      sizebase:        (.sizebase | _opt_tonumber),
128      show_formats:    (.show_formats | _opt_toboolean),
129      show_help:       (.show_help | _opt_toboolean),
130      slurp:           (.slurp | _opt_toboolean),
131      string_input:    (.string_input | _opt_toboolean),
132      unicode:         (.unicode | _opt_toboolean),
133      verbose:         (.verbose | _opt_toboolean),
134    }
135  | with_entries(select(.value != null))
136  );
137
138def _opt_cli_opts:
139  {
140    "arg": {
141      long: "--arg",
142      description: "Set variable $NAME to string VALUE",
143      pairs: "NAME VALUE"
144    },
145    "argjson": {
146      long: "--argjson",
147      description: "Set variable $NAME to JSON",
148      pairs: "NAME JSON"
149    },
150    "compact": {
151      short: "-c",
152      long: "--compact-output",
153      description: "Compact output",
154      bool: true
155    },
156    "color_output": {
157      short: "-C",
158      long: "--color-output",
159      description: "Force color output",
160      bool: true
161    },
162    "decode_format": {
163      short: "-d",
164      long: "--decode",
165      description: "Decode format (probe)",
166      string: "NAME"
167    },
168    "decode_file": {
169      long: "--decode-file",
170      description: "Set variable $NAME to decode of file",
171      pairs: "NAME PATH"
172    },
173    "expr_file": {
174      short: "-f",
175      long: "--from-file",
176      description: "Read EXPR from file",
177      string: "PATH"
178    },
179    "show_formats": {
180      long: "--formats",
181      description: "Show supported formats",
182      bool: true
183    },
184    "show_help": {
185      short: "-h",
186      long: "--help",
187      description: "Show help",
188      bool: true
189    },
190    "join_output": {
191      short: "-j",
192      long: "--join-output",
193      description: "No newline between outputs",
194      bool: true
195    },
196    "include_path": {
197      short: "-L",
198      long: "--include-path",
199      description: "Include search path",
200      array: "PATH"
201    },
202    "null_output": {
203      short: "-0",
204      long: "--null-output",
205      # for jq compatibility
206      aliases: ["--nul-output"],
207      description: "Null byte between outputs",
208      bool: true
209    },
210    "null_input": {
211      short: "-n",
212      long: "--null-input",
213      description: "Null input (use input/0 and inputs/0 to read input)",
214      bool: true
215    },
216    "monochrome_output": {
217      short: "-M",
218      long: "--monochrome-output",
219      description: "Force monochrome output",
220      bool: true
221    },
222    "option": {
223      short: "-o",
224      long: "--option",
225      description: "Set option, eg: color=true (use options/0 to see all options)",
226      object: "KEY=VALUE",
227    },
228    "string_input": {
229      short: "-R",
230      long: "--raw-input",
231      description: "Read raw input strings (don't decode)",
232      bool: true
233    },
234    "raw_file": {
235      long: "--raw-file",
236      # for jq compatibility
237      aliases: ["--raw-file"],
238      description: "Set variable $NAME to string content of file",
239      pairs: "NAME PATH"
240    },
241    "raw_string": {
242      short: "-r",
243      # for jq compat, is called raw string internally, "raw output" is if
244      # we can output raw bytes or not
245      long: "--raw-output",
246      description: "Raw string output (without quotes)",
247      bool: true
248    },
249    "repl": {
250      short: "-i",
251      long: "--repl",
252      description: "Interactive REPL",
253      bool: true
254    },
255    "slurp": {
256      short: "-s",
257      long: "--slurp",
258      description: "Read (slurp) all inputs into an array",
259      bool: true
260    },
261    "show_version": {
262      short: "-v",
263      long: "--version",
264      description: "Show version",
265      bool: true
266    },
267  };
268
269def options($opts):
270  [_opt_default_dynamic] + _options_stack + [$opts] | add;
271def options: options({});
272