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

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