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

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