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

602 lines, 360 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
184FC_SPEC = FlagSpec('fc')
185FC_SPEC.ShortFlag('-e', args.String)
186FC_SPEC.ShortFlag('-l')
187FC_SPEC.ShortFlag('-n')
188FC_SPEC.ShortFlag('-r')
189
190#
191# osh/builtin_process.py
192#
193
194EXEC_SPEC = FlagSpec('exec')
195
196WAIT_SPEC = FlagSpec('wait')
197WAIT_SPEC.ShortFlag('-n')
198WAIT_SPEC.LongFlag('--all')
199WAIT_SPEC.LongFlag('--verbose')
200
201TRAP_SPEC = FlagSpec('trap')
202TRAP_SPEC.ShortFlag('-p')
203TRAP_SPEC.ShortFlag('-l')
204TRAP_SPEC.LongFlag('--add')
205TRAP_SPEC.LongFlag('--remove')
206
207KILL_SPEC = FlagSpec('kill')
208KILL_SPEC.ShortFlag('-l', args.Bool)
209KILL_SPEC.ShortFlag('-L', args.Bool)
210KILL_SPEC.ShortFlag('-n', args.String)
211KILL_SPEC.ShortFlag('-s', args.String)
212
213JOB_SPEC = FlagSpec('jobs')
214JOB_SPEC.ShortFlag('-l', help='long format')
215JOB_SPEC.ShortFlag('-p', help='prints PID only')
216JOB_SPEC.LongFlag('--debug', help='display debug info')
217
218ULIMIT_SPEC = FlagSpec('ulimit')
219
220ULIMIT_SPEC.ShortFlag('-a', help='Print all limits')
221ULIMIT_SPEC.LongFlag('--all', help='Alias for -a')
222ULIMIT_SPEC.ShortFlag('-H', help='Use hard limit')
223ULIMIT_SPEC.ShortFlag('-S', help='Use soft limit')
224
225_ULIMIT_RESOURCES = [
226 '-c',
227 '-d',
228 '-f',
229 '-n',
230 '-s',
231 '-t',
232 '-v',
233]
234
235for u_flag in _ULIMIT_RESOURCES:
236 ULIMIT_SPEC.ShortFlag(u_flag)
237
238#
239# FlagSpecAndMore
240#
241
242#
243# set and shopt
244#
245
246
247def _AddShellOptions(spec):
248 # type: (_FlagSpecAndMore) -> None
249 """Shared between 'set' builtin and the shell's own arg parser."""
250 spec.InitOptions()
251 spec.InitShopt()
252
253 for opt in option_def.All():
254 if opt.builtin == 'set':
255 spec.Option(opt.short_flag, opt.name)
256 # Notes:
257 # - shopt option don't need to be registered; we validate elsewhere
258 # - 'interactive' Has a cell for internal use, but isn't allowed to be
259 # modified.
260
261
262MAIN_SPEC = FlagSpecAndMore('main')
263
264# Special case: Define --eval and --eval-pure
265MAIN_SPEC.EvalFlags()
266
267MAIN_SPEC.ShortFlag('-c', args.String,
268 quit_parsing_flags=True) # command string
269MAIN_SPEC.LongFlag('--help')
270MAIN_SPEC.LongFlag('--version')
271
272# --tool ysh-ify, etc.
273# default is ''
274#
275# More ideas for tools
276# undefined-vars - a static analysis pass
277# parse-glob - to debug parsing
278# parse-printf
279MAIN_SPEC.LongFlag('--tool', [
280 'tokens',
281 'lossless-cat',
282 'syntax-tree',
283 'fmt',
284 'test',
285 'ysh-ify',
286 'deps',
287 'cat-em',
288 'find-lhs-array',
289])
290
291MAIN_SPEC.ShortFlag('-i') # interactive
292MAIN_SPEC.ShortFlag('-l') # login - currently no-op
293MAIN_SPEC.LongFlag('--login') # login - currently no-op
294MAIN_SPEC.LongFlag('--headless') # accepts ECMD, etc.
295
296# TODO: -h too
297# the output format when passing -n
298MAIN_SPEC.LongFlag('--ast-format',
299 ['text', 'abbrev-text', 'none', '__perf', '__dumpdoc'],
300 default='abbrev-text')
301
302# Defines completion style.
303MAIN_SPEC.LongFlag('--completion-display', ['minimal', 'nice'],
304 default='minimal')
305# TODO: Add option for YSH prompt style? RHS prompt?
306
307MAIN_SPEC.LongFlag('--completion-demo')
308
309# Debugging feature only. $SH -n won't reparse a[x+1] and ``. Note that $SH
310# --tool automatically turns it on.
311MAIN_SPEC.LongFlag('--do-lossless')
312
313MAIN_SPEC.LongFlag('--print-status') # TODO: Replace with a shell hook
314MAIN_SPEC.LongFlag('--debug-file', args.String)
315MAIN_SPEC.LongFlag('--xtrace-to-debug-file')
316
317# This flag has is named like bash's equivalent. We got rid of --norc because
318# it can simply by --rcfile /dev/null.
319MAIN_SPEC.LongFlag('--rcfile', args.String)
320MAIN_SPEC.LongFlag('--rcdir', args.String)
321MAIN_SPEC.LongFlag('--norc')
322
323# e.g. to pass data on stdin but pretend that it came from a .hay file
324MAIN_SPEC.LongFlag('--location-str', args.String)
325MAIN_SPEC.LongFlag('--location-start-line', args.Int)
326
327_AddShellOptions(MAIN_SPEC)
328
329SET_SPEC = FlagSpecAndMore('set')
330_AddShellOptions(SET_SPEC)
331
332#
333# Types for completion
334#
335
336
337def _DefineCompletionFlags(spec):
338 # type: (_FlagSpecAndMore) -> None
339 spec.ShortFlag('-F', args.String, help='Complete with this function')
340 spec.ShortFlag('-W', args.String, help='Complete with these words')
341 spec.ShortFlag('-C',
342 args.String,
343 help='Complete with stdout lines of this command')
344
345 spec.ShortFlag(
346 '-P',
347 args.String,
348 help=
349 'Prefix is added at the beginning of each possible completion after '
350 'all other options have been applied.')
351 spec.ShortFlag('-S',
352 args.String,
353 help='Suffix is appended to each possible completion after '
354 'all other options have been applied.')
355 spec.ShortFlag('-X',
356 args.String,
357 help='''
358A glob pattern to further filter the matches. It is applied to the list of
359possible completions generated by the preceding options and arguments, and each
360completion matching filterpat is removed from the list. A leading ! in
361filterpat negates the pattern; in this case, any completion not matching
362filterpat is removed.
363''')
364
365
366def _DefineCompletionOptions(spec):
367 # type: (_FlagSpecAndMore) -> None
368 """Common -o options for complete and compgen."""
369 spec.InitOptions()
370
371 # bashdefault, default, filenames, nospace are used in git
372 spec.Option2('bashdefault',
373 help='If nothing matches, perform default bash completions')
374 spec.Option2(
375 'default',
376 help="If nothing matches, use readline's default filename completion")
377 spec.Option2(
378 'filenames',
379 help="The completion function generates filenames and should be "
380 "post-processed")
381 spec.Option2('dirnames',
382 help="If nothing matches, perform directory name completion")
383 spec.Option2(
384 'nospace',
385 help="Don't append a space to words completed at the end of the line")
386 spec.Option2(
387 'plusdirs',
388 help="After processing the compspec, attempt directory name completion "
389 "and return those matches.")
390
391
392def _DefineCompletionActions(spec):
393 # type: (_FlagSpecAndMore) -> None
394 """Common -A actions for complete and compgen."""
395
396 # NOTE: git-completion.bash uses -f and -v.
397 # My ~/.bashrc on Ubuntu uses -d, -u, -j, -v, -a, -c, -b
398 spec.InitActions()
399 spec.Action('a', 'alias')
400 spec.Action('b', 'binding')
401 spec.Action('c', 'command')
402 spec.Action('d', 'directory')
403 spec.Action('e', 'export')
404 spec.Action('f', 'file')
405 spec.Action('k', 'keyword')
406 spec.Action('j', 'job')
407 spec.Action('u', 'user')
408 spec.Action('v', 'variable')
409 spec.Action(None, 'builtin')
410 spec.Action(None, 'function')
411 spec.Action(None, 'helptopic') # help
412 spec.Action(None, 'setopt') # set -o
413 spec.Action(None, 'shopt') # shopt -s
414 spec.Action(None, 'signal') # kill -s
415 spec.Action(None, 'stopped')
416
417
418COMPLETE_SPEC = FlagSpecAndMore('complete')
419
420_DefineCompletionFlags(COMPLETE_SPEC)
421_DefineCompletionOptions(COMPLETE_SPEC)
422_DefineCompletionActions(COMPLETE_SPEC)
423
424COMPLETE_SPEC.ShortFlag('-E', help='Define the compspec for an empty line')
425COMPLETE_SPEC.ShortFlag(
426 '-D', help='Define the compspec that applies when nothing else matches')
427
428# I would like this to be less compatible
429# Field name conflicts with 'print' keyword
430#COMPLETE_SPEC.LongFlag(
431# '--print', help='Print spec')
432
433COMPGEN_SPEC = FlagSpecAndMore('compgen') # for -o and -A
434
435# TODO: Add -l for COMP_LINE. -p for COMP_POINT ?
436_DefineCompletionFlags(COMPGEN_SPEC)
437_DefineCompletionOptions(COMPGEN_SPEC)
438_DefineCompletionActions(COMPGEN_SPEC)
439
440COMPOPT_SPEC = FlagSpecAndMore('compopt') # for -o
441_DefineCompletionOptions(COMPOPT_SPEC)
442
443COMPADJUST_SPEC = FlagSpecAndMore('compadjust')
444
445COMPADJUST_SPEC.ShortFlag(
446 '-n',
447 args.String,
448 help=
449 'Do NOT split by these characters. It omits them from COMP_WORDBREAKS.')
450COMPADJUST_SPEC.ShortFlag('-s',
451 help='Treat --foo=bar and --foo bar the same way.')
452
453COMPEXPORT_SPEC = FlagSpecAndMore('compexport')
454
455COMPEXPORT_SPEC.ShortFlag('-c',
456 args.String,
457 help='Shell string to complete, like sh -c')
458
459COMPEXPORT_SPEC.LongFlag('--begin',
460 args.Int,
461 help='Simulate readline begin index into line buffer')
462
463COMPEXPORT_SPEC.LongFlag('--end',
464 args.Int,
465 help='Simulate readline end index into line buffer')
466
467# jlines is an array of strings with NO header line
468# TSV8 has a header line. It can have flag descriptions and other data.
469COMPEXPORT_SPEC.LongFlag('--format', ['jlines', 'tsv8'],
470 default='jlines',
471 help='Output format')
472
473#
474# Pure YSH
475#
476
477TRY_SPEC = FlagSpec('try_')
478TRY_SPEC.LongFlag('--assign',
479 args.String,
480 help='Assign status to this variable, and return 0')
481
482ERROR_SPEC = FlagSpec('error')
483FAILED_SPEC = FlagSpec('failed')
484
485BOOLSTATUS_SPEC = FlagSpec('boolstatus')
486ASSERT_SPEC = FlagSpec('assert')
487
488# Future directions:
489# run --builtin, run --command, run --proc:
490# to "replace" 'builtin' and # 'command'
491
492APPEND_SPEC = FlagSpec('append')
493
494SHVAR_SPEC = FlagSpec('shvar')
495#SHVAR_SPEC.Flag('-temp', args.String,
496# help='Push a NAME=val binding')
497#SHVAR_SPEC.Flag('-env', args.String,
498# help='Push a NAME=val binding and set the -x flag')
499
500CTX_SPEC = FlagSpec('ctx')
501
502PP_SPEC = FlagSpec('pp')
503
504# --verbose?
505FORK_SPEC = FlagSpec('fork')
506FORKWAIT_SPEC = FlagSpec('forkwait')
507
508# Might want --list at some point
509SOURCE_GUARD_SPEC = FlagSpec('source-guard')
510USE_SPEC = FlagSpec('use')
511USE_SPEC.LongFlag('--extern')
512
513RUNPROC_SPEC = FlagSpec('runproc')
514RUNPROC_SPEC.ShortFlag('-h', args.Bool, help='Show all procs')
515
516INVOKE_SPEC = FlagSpec('invoke')
517INVOKE_SPEC.LongFlag('--builtin') # like 'builtin'
518INVOKE_SPEC.LongFlag('--proc')
519INVOKE_SPEC.LongFlag('--sh-func')
520INVOKE_SPEC.LongFlag('--extern') # new functionality
521INVOKE_SPEC.LongFlag('--show') # like type -a with private builtins
522
523EXTERN_SPEC = FlagSpec('extern')
524
525SLEEP_SPEC = FlagSpec('sleep')
526
527CAT_SPEC = FlagSpec('cat')
528
529RM_SPEC = FlagSpec('rm')
530RM_SPEC.ShortFlag('-f', args.Bool, help="Don't fail when a file doesn't exist")
531
532WRITE_SPEC = FlagSpec('write')
533WRITE_SPEC.LongFlag('--sep',
534 args.String,
535 default='\n',
536 help='Characters to separate each argument')
537WRITE_SPEC.LongFlag('--end',
538 args.String,
539 default='\n',
540 help='Characters to terminate the whole invocation')
541WRITE_SPEC.ShortFlag('-n',
542 args.Bool,
543 help="Omit newline (synonym for -end '')")
544
545# Note: these 2 aren't documented, but they are implemented
546WRITE_SPEC.LongFlag('--json',
547 args.Bool,
548 default=False,
549 help='Write elements as JSON strings(lossy)')
550WRITE_SPEC.LongFlag('--j8',
551 args.Bool,
552 default=False,
553 help='Write elements as J8 strings')
554# TODO: --jlines for conditional j"" prefix? Like maybe_shell_encode()
555
556# Legacy that's not really needed with J8 notation. The = operator might use a
557# separate pretty printer that shows \u{3bc}
558#
559# x means I want \x00
560# u means I want \u{1234}
561# raw is utf-8
562if 0:
563 WRITE_SPEC.LongFlag(
564 '--unicode', ['raw', 'u', 'x'],
565 default='raw',
566 help='Encode QSN with these options. '
567 'x assumes an opaque byte string, while raw and u try to '
568 'decode UTF-8.')
569
570PUSH_REGISTERS_SPEC = FlagSpec('push-registers')
571
572FOPEN_SPEC = FlagSpec('redir')
573
574#
575# JSON
576#
577
578JSON_WRITE_SPEC = FlagSpec('json_write')
579
580if 0:
581 JSON_WRITE_SPEC.LongFlag('--pretty',
582 args.Bool,
583 default=True,
584 help='Whitespace in output (default true)')
585
586 # Unused:
587 # JSON has the questionable decision of allowing (unpaired) surrogate like
588 # \udc00.
589 # When encoding, we try to catch the error on OUR side, rather than letting it
590 # travel over the wire. But you can disable this.
591 JSON_WRITE_SPEC.LongFlag(
592 '--surrogate-ok',
593 args.Bool,
594 default=False,
595 help='Invalid UTF-8 can be encoded as surrogate like \\udc00')
596
597JSON_WRITE_SPEC.LongFlag('--indent',
598 args.Int,
599 default=2,
600 help='Indent JSON by this amount')
601
602JSON_READ_SPEC = FlagSpec('json_read')