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

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