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

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