OILS / frontend / flag_def.py View on Github | oilshell.org

536 lines, 305 significant
1#!/usr/bin/env python2
2"""Flag parser defintions."""
3
4from __future__ import print_function
5
6from frontend import args
7from frontend.flag_spec import (FlagSpec, FlagSpecAndMore, _FlagSpecAndMore)
8from frontend import option_def
9
10#
11# Definitions for builtin_assign
12#
13
14EXPORT_SPEC = FlagSpec('export_')
15EXPORT_SPEC.ShortFlag('-n')
16EXPORT_SPEC.ShortFlag('-f') # stubbed
17EXPORT_SPEC.ShortFlag('-p')
18
19READONLY_SPEC = FlagSpec('readonly')
20
21# TODO: Check the consistency of -a and -A against values, here and below.
22READONLY_SPEC.ShortFlag('-a')
23READONLY_SPEC.ShortFlag('-A')
24READONLY_SPEC.ShortFlag('-p')
25
26NEW_VAR_SPEC = FlagSpec('new_var')
27
28# print stuff
29NEW_VAR_SPEC.ShortFlag('-f')
30NEW_VAR_SPEC.ShortFlag('-F')
31NEW_VAR_SPEC.ShortFlag('-p')
32
33NEW_VAR_SPEC.ShortFlag('-g') # Look up in global scope
34
35# Options +r +x +n
36NEW_VAR_SPEC.PlusFlag('x') # export
37NEW_VAR_SPEC.PlusFlag('r') # readonly
38NEW_VAR_SPEC.PlusFlag('n') # named ref
39
40# Common between readonly/declare
41NEW_VAR_SPEC.ShortFlag('-a')
42NEW_VAR_SPEC.ShortFlag('-A')
43NEW_VAR_SPEC.ShortFlag('-i') # no-op for integers
44
45UNSET_SPEC = FlagSpec('unset')
46UNSET_SPEC.ShortFlag('-v')
47UNSET_SPEC.ShortFlag('-f')
48#UNSET_SPEC.ShortFlag('-z', args.String)
49
50#
51# Definitions for builtin_meta
52#
53
54# Unused because there are no flags! Just --.
55EVAL_SPEC = FlagSpec('eval')
56SOURCE_SPEC = FlagSpec('source')
57SOURCE_SPEC.LongFlag('--builtin')
58
59COMMAND_SPEC = FlagSpec('command')
60COMMAND_SPEC.ShortFlag('-v')
61COMMAND_SPEC.ShortFlag('-V')
62COMMAND_SPEC.ShortFlag('-p')
63
64TYPE_SPEC = FlagSpec('type')
65TYPE_SPEC.ShortFlag('-f')
66TYPE_SPEC.ShortFlag('-t')
67TYPE_SPEC.ShortFlag('-p')
68TYPE_SPEC.ShortFlag('-P')
69TYPE_SPEC.ShortFlag('-a')
70
71#
72# Definitions for builtin_pure
73#
74
75ALIAS_SPEC = FlagSpec('alias') # no flags yet
76UNALIAS_SPEC = FlagSpec('unalias') # no flags yet
77UNALIAS_SPEC.ShortFlag('-a')
78
79SHOPT_SPEC = FlagSpec('shopt')
80SHOPT_SPEC.ShortFlag('-s', long_name='--set')
81SHOPT_SPEC.ShortFlag('-u', long_name='--unset')
82SHOPT_SPEC.ShortFlag('-o') # use 'set -o' names
83# TODO: --print could print in a verbose format. (Annoying: codegen conflicts
84# with Python keyword.)
85SHOPT_SPEC.ShortFlag('-p')
86SHOPT_SPEC.ShortFlag('-q') # query option settings
87
88HASH_SPEC = FlagSpec('hash')
89HASH_SPEC.ShortFlag('-r')
90
91ECHO_SPEC = FlagSpec('echo')
92ECHO_SPEC.ShortFlag('-e') # no backslash escapes
93ECHO_SPEC.ShortFlag('-n')
94
95#
96# osh/builtin_printf.py
97#
98
99PRINTF_SPEC = FlagSpec('printf')
100PRINTF_SPEC.ShortFlag('-v', args.String)
101
102#
103# osh/builtin_misc.py
104#
105
106READ_SPEC = FlagSpec('read')
107READ_SPEC.ShortFlag('-r')
108READ_SPEC.ShortFlag('-s') # silent
109READ_SPEC.ShortFlag('-u', args.Int) # file descriptor
110READ_SPEC.ShortFlag('-t', args.Float) # timeout
111READ_SPEC.ShortFlag('-n', args.Int)
112READ_SPEC.ShortFlag('-N', args.Int)
113READ_SPEC.ShortFlag('-a', args.String) # name of array to read into
114READ_SPEC.ShortFlag('-d', args.String)
115READ_SPEC.ShortFlag('-p', args.String) # prompt
116
117# YSH extensions
118READ_SPEC.ShortFlag('-0') # until NUL, like -r -d ''
119READ_SPEC.LongFlag('--all')
120
121# Why not have --j8-line, a shortcut for fromJ8Line()?
122# Because buffered vs. unbuffered should be ORTHOGONAL to encoding
123# TODO: my-j8-read should be possible
124
125READ_SPEC.LongFlag('--raw-line')
126READ_SPEC.LongFlag('--num-bytes', args.Int)
127# don't strip the trailing newline
128READ_SPEC.LongFlag('--with-eol')
129
130MAPFILE_SPEC = FlagSpec('mapfile')
131MAPFILE_SPEC.ShortFlag('-t')
132
133CD_SPEC = FlagSpec('cd')
134CD_SPEC.ShortFlag('-L')
135CD_SPEC.ShortFlag('-P')
136
137PUSHD_SPEC = FlagSpec('pushd')
138
139POPD_SPEC = FlagSpec('popd')
140
141DIRS_SPEC = FlagSpec('dirs')
142DIRS_SPEC.ShortFlag('-c')
143DIRS_SPEC.ShortFlag('-l')
144DIRS_SPEC.ShortFlag('-p')
145DIRS_SPEC.ShortFlag('-v')
146
147PWD_SPEC = FlagSpec('pwd')
148PWD_SPEC.ShortFlag('-L')
149PWD_SPEC.ShortFlag('-P')
150
151HELP_SPEC = FlagSpec('help')
152#HELP_SPEC.ShortFlag('-i') # show index
153# Note: bash has help -d -m -s, which change the formatting
154
155HISTORY_SPEC = FlagSpec('history')
156HISTORY_SPEC.ShortFlag('-a')
157HISTORY_SPEC.ShortFlag('-r')
158HISTORY_SPEC.ShortFlag('-c')
159HISTORY_SPEC.ShortFlag('-d', args.Int)
160
161#
162# osh/builtin_process.py
163#
164
165EXEC_SPEC = FlagSpec('exec')
166
167WAIT_SPEC = FlagSpec('wait')
168WAIT_SPEC.ShortFlag('-n')
169
170TRAP_SPEC = FlagSpec('trap')
171TRAP_SPEC.ShortFlag('-p')
172TRAP_SPEC.ShortFlag('-l')
173
174JOB_SPEC = FlagSpec('jobs')
175JOB_SPEC.ShortFlag('-l', help='long format')
176JOB_SPEC.ShortFlag('-p', help='prints PID only')
177JOB_SPEC.LongFlag('--debug', help='display debug info')
178
179ULIMIT_SPEC = FlagSpec('ulimit')
180
181ULIMIT_SPEC.ShortFlag('-a', help='Print all limits')
182ULIMIT_SPEC.LongFlag('--all', help='Alias for -a')
183ULIMIT_SPEC.ShortFlag('-H', help='Use hard limit')
184ULIMIT_SPEC.ShortFlag('-S', help='Use soft limit')
185
186_ULIMIT_RESOURCES = [
187 '-c',
188 '-d',
189 '-f',
190 '-n',
191 '-s',
192 '-t',
193 '-v',
194]
195
196for u_flag in _ULIMIT_RESOURCES:
197 ULIMIT_SPEC.ShortFlag(u_flag)
198
199#
200# FlagSpecAndMore
201#
202
203#
204# set and shopt
205#
206
207
208def _AddShellOptions(spec):
209 # type: (_FlagSpecAndMore) -> None
210 """Shared between 'set' builtin and the shell's own arg parser."""
211 spec.InitOptions()
212 spec.InitShopt()
213
214 for opt in option_def.All():
215 if opt.builtin == 'set':
216 spec.Option(opt.short_flag, opt.name)
217 # Notes:
218 # - shopt option don't need to be registered; we validate elsewhere
219 # - 'interactive' Has a cell for internal use, but isn't allowed to be
220 # modified.
221
222
223MAIN_SPEC = FlagSpecAndMore('main')
224
225MAIN_SPEC.ShortFlag('-c', args.String,
226 quit_parsing_flags=True) # command string
227MAIN_SPEC.LongFlag('--help')
228MAIN_SPEC.LongFlag('--version')
229
230# --tool ysh-ify, etc.
231# default is ''
232#
233# More ideas for tools
234# undefined-vars - a static analysis pass
235# parse-glob - to debug parsing
236# parse-printf
237MAIN_SPEC.LongFlag('--tool', [
238 'tokens', 'lossless-cat', 'syntax-tree', 'fmt', 'test', 'ysh-ify', 'deps',
239 'cat-em'
240])
241
242MAIN_SPEC.ShortFlag('-i') # interactive
243MAIN_SPEC.ShortFlag('-l') # login - currently no-op
244MAIN_SPEC.LongFlag('--login') # login - currently no-op
245MAIN_SPEC.LongFlag('--headless') # accepts ECMD, etc.
246
247# TODO: -h too
248# the output format when passing -n
249MAIN_SPEC.LongFlag(
250 '--ast-format',
251 ['text', 'abbrev-text', 'html', 'abbrev-html', 'oheap', 'none'],
252 default='abbrev-text')
253
254# Defines completion style.
255MAIN_SPEC.LongFlag('--completion-display', ['minimal', 'nice'], default='nice')
256# TODO: Add option for YSH prompt style? RHS prompt?
257
258MAIN_SPEC.LongFlag('--completion-demo')
259
260# Debugging feature only. $SH -n won't reparse a[x+1] and ``. Note that $SH
261# --tool automatically turns it on.
262MAIN_SPEC.LongFlag('--do-lossless')
263
264MAIN_SPEC.LongFlag('--print-status') # TODO: Replace with a shell hook
265MAIN_SPEC.LongFlag('--debug-file', args.String)
266MAIN_SPEC.LongFlag('--xtrace-to-debug-file')
267
268# This flag has is named like bash's equivalent. We got rid of --norc because
269# it can simply by --rcfile /dev/null.
270MAIN_SPEC.LongFlag('--rcfile', args.String)
271MAIN_SPEC.LongFlag('--rcdir', args.String)
272MAIN_SPEC.LongFlag('--norc')
273
274# e.g. to pass data on stdin but pretend that it came from a .hay file
275MAIN_SPEC.LongFlag('--location-str', args.String)
276MAIN_SPEC.LongFlag('--location-start-line', args.Int)
277
278_AddShellOptions(MAIN_SPEC)
279
280SET_SPEC = FlagSpecAndMore('set')
281_AddShellOptions(SET_SPEC)
282
283#
284# Types for completion
285#
286
287
288def _DefineCompletionFlags(spec):
289 # type: (_FlagSpecAndMore) -> None
290 spec.ShortFlag('-F', args.String, help='Complete with this function')
291 spec.ShortFlag('-W', args.String, help='Complete with these words')
292 spec.ShortFlag('-C',
293 args.String,
294 help='Complete with stdout lines of this command')
295
296 spec.ShortFlag(
297 '-P',
298 args.String,
299 help=
300 'Prefix is added at the beginning of each possible completion after '
301 'all other options have been applied.')
302 spec.ShortFlag('-S',
303 args.String,
304 help='Suffix is appended to each possible completion after '
305 'all other options have been applied.')
306 spec.ShortFlag('-X',
307 args.String,
308 help='''
309A glob pattern to further filter the matches. It is applied to the list of
310possible completions generated by the preceding options and arguments, and each
311completion matching filterpat is removed from the list. A leading ! in
312filterpat negates the pattern; in this case, any completion not matching
313filterpat is removed.
314''')
315
316
317def _DefineCompletionOptions(spec):
318 # type: (_FlagSpecAndMore) -> None
319 """Common -o options for complete and compgen."""
320 spec.InitOptions()
321
322 # bashdefault, default, filenames, nospace are used in git
323 spec.Option2('bashdefault',
324 help='If nothing matches, perform default bash completions')
325 spec.Option2(
326 'default',
327 help="If nothing matches, use readline's default filename completion")
328 spec.Option2(
329 'filenames',
330 help="The completion function generates filenames and should be "
331 "post-processed")
332 spec.Option2('dirnames',
333 help="If nothing matches, perform directory name completion")
334 spec.Option2(
335 'nospace',
336 help="Don't append a space to words completed at the end of the line")
337 spec.Option2(
338 'plusdirs',
339 help="After processing the compspec, attempt directory name completion "
340 "and return those matches.")
341
342
343def _DefineCompletionActions(spec):
344 # type: (_FlagSpecAndMore) -> None
345 """Common -A actions for complete and compgen."""
346
347 # NOTE: git-completion.bash uses -f and -v.
348 # My ~/.bashrc on Ubuntu uses -d, -u, -j, -v, -a, -c, -b
349 spec.InitActions()
350 spec.Action('a', 'alias')
351 spec.Action('b', 'binding')
352 spec.Action('c', 'command')
353 spec.Action('d', 'directory')
354 spec.Action('e', 'export')
355 spec.Action('f', 'file')
356 spec.Action('k', 'keyword')
357 spec.Action('j', 'job')
358 spec.Action('u', 'user')
359 spec.Action('v', 'variable')
360 spec.Action(None, 'builtin')
361 spec.Action(None, 'function')
362 spec.Action(None, 'helptopic') # help
363 spec.Action(None, 'setopt') # set -o
364 spec.Action(None, 'shopt') # shopt -s
365 spec.Action(None, 'signal') # kill -s
366 spec.Action(None, 'stopped')
367
368
369COMPLETE_SPEC = FlagSpecAndMore('complete')
370
371_DefineCompletionFlags(COMPLETE_SPEC)
372_DefineCompletionOptions(COMPLETE_SPEC)
373_DefineCompletionActions(COMPLETE_SPEC)
374
375COMPLETE_SPEC.ShortFlag('-E', help='Define the compspec for an empty line')
376COMPLETE_SPEC.ShortFlag(
377 '-D', help='Define the compspec that applies when nothing else matches')
378
379# I would like this to be less compatible
380# Field name conflicts with 'print' keyword
381#COMPLETE_SPEC.LongFlag(
382# '--print', help='Print spec')
383
384COMPGEN_SPEC = FlagSpecAndMore('compgen') # for -o and -A
385
386# TODO: Add -l for COMP_LINE. -p for COMP_POINT ?
387_DefineCompletionFlags(COMPGEN_SPEC)
388_DefineCompletionOptions(COMPGEN_SPEC)
389_DefineCompletionActions(COMPGEN_SPEC)
390
391COMPOPT_SPEC = FlagSpecAndMore('compopt') # for -o
392_DefineCompletionOptions(COMPOPT_SPEC)
393
394COMPADJUST_SPEC = FlagSpecAndMore('compadjust')
395
396COMPADJUST_SPEC.ShortFlag(
397 '-n',
398 args.String,
399 help=
400 'Do NOT split by these characters. It omits them from COMP_WORDBREAKS.')
401COMPADJUST_SPEC.ShortFlag('-s',
402 help='Treat --foo=bar and --foo bar the same way.')
403
404COMPEXPORT_SPEC = FlagSpecAndMore('compexport')
405
406COMPEXPORT_SPEC.ShortFlag('-c',
407 args.String,
408 help='Shell string to complete, like sh -c')
409
410COMPEXPORT_SPEC.LongFlag('--begin',
411 args.Int,
412 help='Simulate readline begin index into line buffer')
413
414COMPEXPORT_SPEC.LongFlag('--end',
415 args.Int,
416 help='Simulate readline end index into line buffer')
417
418# jlines is an array of strings with NO header line
419# TSV8 has a header line. It can have flag descriptions and other data.
420COMPEXPORT_SPEC.LongFlag('--format', ['jlines', 'tsv8'],
421 default='jlines',
422 help='Output format')
423
424#
425# Pure YSH
426#
427
428TRY_SPEC = FlagSpec('try_')
429TRY_SPEC.LongFlag('--assign',
430 args.String,
431 help='Assign status to this variable, and return 0')
432
433ERROR_SPEC = FlagSpec('error')
434FAILED_SPEC = FlagSpec('failed')
435
436BOOLSTATUS_SPEC = FlagSpec('boolstatus')
437
438# Future directions:
439# run --builtin, run --command, run --proc:
440# to "replace" 'builtin' and # 'command'
441
442APPEND_SPEC = FlagSpec('append')
443
444SHVAR_SPEC = FlagSpec('shvar')
445#SHVAR_SPEC.Flag('-temp', args.String,
446# help='Push a NAME=val binding')
447#SHVAR_SPEC.Flag('-env', args.String,
448# help='Push a NAME=val binding and set the -x flag')
449
450CTX_SPEC = FlagSpec('ctx')
451
452PP_SPEC = FlagSpec('pp')
453
454SHVM_SPEC = FlagSpec('shvm')
455
456# --verbose?
457FORK_SPEC = FlagSpec('fork')
458FORKWAIT_SPEC = FlagSpec('forkwait')
459
460# Might want --list at some point
461MODULE_SPEC = FlagSpec('module')
462
463RUNPROC_SPEC = FlagSpec('runproc')
464RUNPROC_SPEC.ShortFlag('-h', args.Bool, help='Show all procs')
465
466WRITE_SPEC = FlagSpec('write')
467WRITE_SPEC.LongFlag('--sep',
468 args.String,
469 default='\n',
470 help='Characters to separate each argument')
471WRITE_SPEC.LongFlag('--end',
472 args.String,
473 default='\n',
474 help='Characters to terminate the whole invocation')
475WRITE_SPEC.ShortFlag('-n',
476 args.Bool,
477 help="Omit newline (synonym for -end '')")
478# Do we need these two?
479WRITE_SPEC.LongFlag('--json',
480 args.Bool,
481 default=False,
482 help='Write elements as JSON strings(lossy)')
483WRITE_SPEC.LongFlag('--j8',
484 args.Bool,
485 default=False,
486 help='Write elements as J8 strings')
487# TODO: --jlines for conditional j"" prefix? Like maybe_shell_encode()
488
489# Legacy that's not really needed with J8 notation. The = operator might use a
490# separate pretty printer that shows \u{3bc}
491#
492# x means I want \x00
493# u means I want \u{1234}
494# raw is utf-8
495if 0:
496 WRITE_SPEC.LongFlag(
497 '--unicode', ['raw', 'u', 'x'],
498 default='raw',
499 help='Encode QSN with these options. '
500 'x assumes an opaque byte string, while raw and u try to '
501 'decode UTF-8.')
502
503PUSH_REGISTERS_SPEC = FlagSpec('push-registers')
504
505FOPEN_SPEC = FlagSpec('fopen')
506
507#
508# JSON
509#
510
511JSON_WRITE_SPEC = FlagSpec('json_write')
512
513# TODO: --compact is probably better
514# --pretty=F is like JSON.stringify(d, null, 0)
515JSON_WRITE_SPEC.LongFlag('--pretty',
516 args.Bool,
517 default=True,
518 help='Whitespace in output (default true)')
519
520# Unused:
521# JSON has the questionable decision of allowing (unpaired) surrogate like
522# \udc00.
523# When encoding, we try to catch the error on OUR side, rather than letting it
524# travel over the wire. But you can disable this.
525JSON_WRITE_SPEC.LongFlag(
526 '--surrogate-ok',
527 args.Bool,
528 default=False,
529 help='Invalid UTF-8 can be encoded as surrogate like \\udc00')
530
531JSON_WRITE_SPEC.LongFlag('--indent',
532 args.Int,
533 default=2,
534 help='Indent JSON by this amount')
535
536JSON_READ_SPEC = FlagSpec('json_read')