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

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