OILS / frontend / flag_def.py View on Github | oils.pub

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