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

536 lines, 311 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
77
78SHOPT_SPEC = FlagSpec('shopt')
79SHOPT_SPEC.ShortFlag('-s', long_name='--set')
80SHOPT_SPEC.ShortFlag('-u', long_name='--unset')
81SHOPT_SPEC.ShortFlag('-o') # use 'set -o' names
82# TODO: --print could print in a verbose format. (Annoying: codegen conflicts
83# with Python keyword.)
84SHOPT_SPEC.ShortFlag('-p')
85SHOPT_SPEC.ShortFlag('-q') # query option settings
86
87HASH_SPEC = FlagSpec('hash')
88HASH_SPEC.ShortFlag('-r')
89
90ECHO_SPEC = FlagSpec('echo')
91ECHO_SPEC.ShortFlag('-e') # no backslash escapes
92ECHO_SPEC.ShortFlag('-n')
93
94#
95# osh/builtin_printf.py
96#
97
98PRINTF_SPEC = FlagSpec('printf')
99PRINTF_SPEC.ShortFlag('-v', args.String)
100
101#
102# osh/builtin_misc.py
103#
104
105READ_SPEC = FlagSpec('read')
106READ_SPEC.ShortFlag('-r')
107READ_SPEC.ShortFlag('-s') # silent
108READ_SPEC.ShortFlag('-u', args.Int) # file descriptor
109READ_SPEC.ShortFlag('-t', args.Float) # timeout
110READ_SPEC.ShortFlag('-n', args.Int)
111READ_SPEC.ShortFlag('-N', args.Int)
112READ_SPEC.ShortFlag('-a', args.String) # name of array to read into
113READ_SPEC.ShortFlag('-d', args.String)
114READ_SPEC.ShortFlag('-p', args.String) # prompt
115
116# YSH extensions
117READ_SPEC.ShortFlag('-0') # until NUL, like -r -d ''
118READ_SPEC.LongFlag('--all')
119READ_SPEC.LongFlag('--line')
120READ_SPEC.LongFlag('--num-bytes', args.Int)
121# don't strip the trailing newline
122READ_SPEC.LongFlag('--with-eol')
123READ_SPEC.LongFlag('--json',
124 args.Bool,
125 default=False,
126 help='Read elements as JSON strings')
127READ_SPEC.LongFlag('--j8',
128 args.Bool,
129 default=False,
130 help='Read elements as J8 strings')
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', 'cat-em'
241])
242
243MAIN_SPEC.ShortFlag('-i') # interactive
244MAIN_SPEC.ShortFlag('-l') # login - currently no-op
245MAIN_SPEC.LongFlag('--login') # login - currently no-op
246MAIN_SPEC.LongFlag('--headless') # accepts ECMD, etc.
247
248# TODO: -h too
249# the output format when passing -n
250MAIN_SPEC.LongFlag(
251 '--ast-format',
252 ['text', 'abbrev-text', 'html', 'abbrev-html', 'oheap', 'none'],
253 default='abbrev-text')
254
255# Defines completion style.
256MAIN_SPEC.LongFlag('--completion-display', ['minimal', 'nice'], default='nice')
257# TODO: Add option for YSH prompt style? RHS prompt?
258
259MAIN_SPEC.LongFlag('--completion-demo')
260
261# Debugging feature only. $SH -n won't reparse a[x+1] and ``. Note that $SH
262# --tool automatically turns it on.
263MAIN_SPEC.LongFlag('--do-lossless')
264
265MAIN_SPEC.LongFlag('--print-status') # TODO: Replace with a shell hook
266MAIN_SPEC.LongFlag('--debug-file', args.String)
267MAIN_SPEC.LongFlag('--xtrace-to-debug-file')
268
269# This flag has is named like bash's equivalent. We got rid of --norc because
270# it can simply by --rcfile /dev/null.
271MAIN_SPEC.LongFlag('--rcfile', args.String)
272MAIN_SPEC.LongFlag('--rcdir', args.String)
273MAIN_SPEC.LongFlag('--norc')
274
275# e.g. to pass data on stdin but pretend that it came from a .hay file
276MAIN_SPEC.LongFlag('--location-str', args.String)
277MAIN_SPEC.LongFlag('--location-start-line', args.Int)
278
279_AddShellOptions(MAIN_SPEC)
280
281SET_SPEC = FlagSpecAndMore('set')
282_AddShellOptions(SET_SPEC)
283
284#
285# Types for completion
286#
287
288
289def _DefineCompletionFlags(spec):
290 # type: (_FlagSpecAndMore) -> None
291 spec.ShortFlag('-F', args.String, help='Complete with this function')
292 spec.ShortFlag('-W', args.String, help='Complete with these words')
293 spec.ShortFlag('-C',
294 args.String,
295 help='Complete with stdout lines of this command')
296
297 spec.ShortFlag(
298 '-P',
299 args.String,
300 help=
301 'Prefix is added at the beginning of each possible completion after '
302 'all other options have been applied.')
303 spec.ShortFlag('-S',
304 args.String,
305 help='Suffix is appended to each possible completion after '
306 'all other options have been applied.')
307 spec.ShortFlag('-X',
308 args.String,
309 help='''
310A glob pattern to further filter the matches. It is applied to the list of
311possible completions generated by the preceding options and arguments, and each
312completion matching filterpat is removed from the list. A leading ! in
313filterpat negates the pattern; in this case, any completion not matching
314filterpat is removed.
315''')
316
317
318def _DefineCompletionOptions(spec):
319 # type: (_FlagSpecAndMore) -> None
320 """Common -o options for complete and compgen."""
321 spec.InitOptions()
322
323 # bashdefault, default, filenames, nospace are used in git
324 spec.Option2('bashdefault',
325 help='If nothing matches, perform default bash completions')
326 spec.Option2(
327 'default',
328 help="If nothing matches, use readline's default filename completion")
329 spec.Option2(
330 'filenames',
331 help="The completion function generates filenames and should be "
332 "post-processed")
333 spec.Option2('dirnames',
334 help="If nothing matches, perform directory name completion")
335 spec.Option2(
336 'nospace',
337 help="Don't append a space to words completed at the end of the line")
338 spec.Option2(
339 'plusdirs',
340 help="After processing the compspec, attempt directory name completion "
341 "and return those matches.")
342
343
344def _DefineCompletionActions(spec):
345 # type: (_FlagSpecAndMore) -> None
346 """Common -A actions for complete and compgen."""
347
348 # NOTE: git-completion.bash uses -f and -v.
349 # My ~/.bashrc on Ubuntu uses -d, -u, -j, -v, -a, -c, -b
350 spec.InitActions()
351 spec.Action('a', 'alias')
352 spec.Action('b', 'binding')
353 spec.Action('c', 'command')
354 spec.Action('d', 'directory')
355 spec.Action('e', 'export')
356 spec.Action('f', 'file')
357 spec.Action('k', 'keyword')
358 spec.Action('j', 'job')
359 spec.Action('u', 'user')
360 spec.Action('v', 'variable')
361 spec.Action(None, 'builtin')
362 spec.Action(None, 'function')
363 spec.Action(None, 'helptopic') # help
364 spec.Action(None, 'setopt') # set -o
365 spec.Action(None, 'shopt') # shopt -s
366 spec.Action(None, 'signal') # kill -s
367 spec.Action(None, 'stopped')
368
369
370COMPLETE_SPEC = FlagSpecAndMore('complete')
371
372_DefineCompletionFlags(COMPLETE_SPEC)
373_DefineCompletionOptions(COMPLETE_SPEC)
374_DefineCompletionActions(COMPLETE_SPEC)
375
376COMPLETE_SPEC.ShortFlag('-E', help='Define the compspec for an empty line')
377COMPLETE_SPEC.ShortFlag(
378 '-D', help='Define the compspec that applies when nothing else matches')
379
380# I would like this to be less compatible
381# Field name conflicts with 'print' keyword
382#COMPLETE_SPEC.LongFlag(
383# '--print', help='Print spec')
384
385COMPGEN_SPEC = FlagSpecAndMore('compgen') # for -o and -A
386
387# TODO: Add -l for COMP_LINE. -p for COMP_POINT ?
388_DefineCompletionFlags(COMPGEN_SPEC)
389_DefineCompletionOptions(COMPGEN_SPEC)
390_DefineCompletionActions(COMPGEN_SPEC)
391
392COMPOPT_SPEC = FlagSpecAndMore('compopt') # for -o
393_DefineCompletionOptions(COMPOPT_SPEC)
394
395COMPADJUST_SPEC = FlagSpecAndMore('compadjust')
396
397COMPADJUST_SPEC.ShortFlag(
398 '-n',
399 args.String,
400 help=
401 'Do NOT split by these characters. It omits them from COMP_WORDBREAKS.')
402COMPADJUST_SPEC.ShortFlag('-s',
403 help='Treat --foo=bar and --foo bar the same way.')
404
405COMPEXPORT_SPEC = FlagSpecAndMore('compexport')
406
407COMPEXPORT_SPEC.ShortFlag('-c',
408 args.String,
409 help='Shell string to complete, like sh -c')
410
411COMPEXPORT_SPEC.LongFlag('--begin',
412 args.Int,
413 help='Simulate readline begin index into line buffer')
414
415COMPEXPORT_SPEC.LongFlag('--end',
416 args.Int,
417 help='Simulate readline end index into line buffer')
418
419# jlines is an array of strings with NO header line
420# TSV8 has a header line. It can have flag descriptions and other data.
421COMPEXPORT_SPEC.LongFlag('--format', ['jlines', 'tsv8'],
422 default='jlines',
423 help='Output format')
424
425#
426# Pure YSH
427#
428
429TRY_SPEC = FlagSpec('try_')
430TRY_SPEC.LongFlag('--assign',
431 args.String,
432 help='Assign status to this variable, and return 0')
433
434ERROR_SPEC = FlagSpec('error')
435
436BOOLSTATUS_SPEC = FlagSpec('boolstatus')
437
438# Future directions:
439# run --builtin, run --command, run --proc:
440# to "replace" 'builtin' and # 'command'
441
442APPEND_SPEC = FlagSpec('append')
443
444SHVAR_SPEC = FlagSpec('shvar')
445#SHVAR_SPEC.Flag('-temp', args.String,
446# help='Push a NAME=val binding')
447#SHVAR_SPEC.Flag('-env', args.String,
448# help='Push a NAME=val binding and set the -x flag')
449
450CTX_SPEC = FlagSpec('ctx')
451
452PP_SPEC = FlagSpec('pp')
453
454SHVM_SPEC = FlagSpec('shvm')
455
456# --verbose?
457FORK_SPEC = FlagSpec('fork')
458FORKWAIT_SPEC = FlagSpec('forkwait')
459
460# Might want --list at some point
461MODULE_SPEC = FlagSpec('module')
462
463RUNPROC_SPEC = FlagSpec('runproc')
464RUNPROC_SPEC.ShortFlag('-h', args.Bool, help='Show all procs')
465
466WRITE_SPEC = FlagSpec('write')
467WRITE_SPEC.LongFlag('--sep',
468 args.String,
469 default='\n',
470 help='Characters to separate each argument')
471WRITE_SPEC.LongFlag('--end',
472 args.String,
473 default='\n',
474 help='Characters to terminate the whole invocation')
475WRITE_SPEC.ShortFlag('-n',
476 args.Bool,
477 help="Omit newline (synonym for -end '')")
478# Do we need these two?
479WRITE_SPEC.LongFlag('--json',
480 args.Bool,
481 default=False,
482 help='Write elements as JSON strings(lossy)')
483WRITE_SPEC.LongFlag('--j8',
484 args.Bool,
485 default=False,
486 help='Write elements as J8 strings')
487# TODO: --jlines for conditional j"" prefix? Like maybe_shell_encode()
488
489# Legacy that's not really needed with J8 notation. The = operator might use a
490# separate pretty printer that shows \u{3bc}
491#
492# x means I want \x00
493# u means I want \u{1234}
494# raw is utf-8
495if 0:
496 WRITE_SPEC.LongFlag(
497 '--unicode', ['raw', 'u', 'x'],
498 default='raw',
499 help='Encode QSN with these options. '
500 'x assumes an opaque byte string, while raw and u try to '
501 'decode UTF-8.')
502
503PUSH_REGISTERS_SPEC = FlagSpec('push-registers')
504
505FOPEN_SPEC = FlagSpec('fopen')
506
507#
508# JSON
509#
510
511JSON_WRITE_SPEC = FlagSpec('json_write')
512
513# TODO: --compact is probably better
514# --pretty=F is like JSON.stringify(d, null, 0)
515JSON_WRITE_SPEC.LongFlag('--pretty',
516 args.Bool,
517 default=True,
518 help='Whitespace in output (default true)')
519
520# Unused:
521# JSON has the questionable decision of allowing (unpaired) surrogate like
522# \udc00.
523# When encoding, we try to catch the error on OUR side, rather than letting it
524# travel over the wire. But you can disable this.
525JSON_WRITE_SPEC.LongFlag(
526 '--surrogate-ok',
527 args.Bool,
528 default=False,
529 help='Invalid UTF-8 can be encoded as surrogate like \\udc00')
530
531JSON_WRITE_SPEC.LongFlag('--indent',
532 args.Int,
533 default=2,
534 help='Indent JSON by this amount')
535
536JSON_READ_SPEC = FlagSpec('json_read')