OILS / _gen / bin / text_files.cc View on Github | oilshell.org

1125 lines, 117 significant
1
2#include "cpp/embedded_file.h"
3
4namespace embedded_file {
5GLOBAL_STR(gStr0, R"zZXx(Errors
6
7 [J8 Lines] j8-lines-decode-err
8 [JSON] json-encode-err json-decode-err
9 [JSON8] json8-encode-err json8-decode-err
10 [Packle] packle-encode-err packle-decode-err
11 [UTF8] utf8-encode-err utf8-decode-err
12)zZXx");
13
14GLOBAL_STR(gStr1, R"zZXx(Front End
15
16 [Lexing] ascii-whitespace [ \t\r\n]
17 ascii-control-chars
18)zZXx");
19
20GLOBAL_STR(gStr2, R"zZXx(J8 Notation
21
22 [J8 Strings] json-string "hi" json-escape \" \\ \u1234
23 surrogate-pair \ud83e\udd26
24 u-prefix u'hi' b-prefix b'hi'
25 j8-escape \u{1f926} \yff
26 no-prefix 'hi'
27 [J8 Lines] unquoted-line
28 [JSON8] json8-num json8-str
29 json8-list json-dict
30 json8-comment
31 [TSV8] column-attrs column-types
32)zZXx");
33
34GLOBAL_STR(gStr3, R"zZXx(Packle
35
36 [Atoms] Null Bool Int Float Bytes Unicode
37 [Compound] List Dict
38)zZXx");
39
40GLOBAL_STR(gStr4, R"zZXx(Usage: help TOPIC?
41
42Examples:
43
44 help # this help
45 help echo # help on the 'echo' builtin
46 help command-sub # help on command sub $(date)
47
48 help oils-usage # identical to oils-for-unix --help
49 help osh-usage # osh --help
50 help ysh-usage # ysh --help
51)zZXx");
52
53GLOBAL_STR(gStr5, R"zZXx(bin/oils-for-unix is an executable that contains OSH, YSH, and more.
54
55Usage: oils-for-unix MAIN_NAME ARG*
56 MAIN_NAME ARG*
57
58It behaves like busybox. The command name can be passed as the first argument:
59
60 oils-for-unix ysh -c 'echo hi'
61
62More commonly, it's invoked through a symlink like 'ysh', which causes it to
63behave like that command:
64
65 ysh -c 'echo hi'
66)zZXx");
67
68GLOBAL_STR(gStr6, R"zZXx(Builtin Commands
69
70 [I/O] read echo printf
71 readarray mapfile
72 [Run Code] source . eval trap
73 [Set Options] set shopt
74 [Working Dir] cd pwd pushd popd dirs
75 [Completion] complete compgen compopt compadjust compexport
76 [Shell Process] exec X logout
77 umask X ulimit times
78 [Child Process] jobs wait ampersand &
79 fg X bg X kill X disown
80 [External] test [ getopts
81 [Introspection] help hash type X caller
82 [Word Lookup] command builtin
83 [Interactive] alias unalias history X fc X bind
84X [Unsupported] enable
85)zZXx");
86
87GLOBAL_STR(gStr7, R"zZXx(The reference is divided in to "chapters", each of which has its own table of
88contents. Type:
89
90 help osh-$CHAPTER
91
92Where $CHAPTER is one of:
93
94 front-end
95 command-lang
96 osh-assign
97 word-lang
98 mini-lang
99 builtin-cmd
100 option
101 special-var
102 plugin
103
104Example:
105
106 help osh-word-lang
107)zZXx");
108
109GLOBAL_STR(gStr8, R"zZXx(Command Language
110
111 [Commands] simple-command semicolon ;
112 [Conditional] case if true false colon :
113 bang ! and && or || dbracket [[
114 [Iteration] while until for for-expr-sh ((
115 [Control Flow] break continue return exit
116 [Grouping] sh-func sh-block { subshell (
117 [Concurrency] pipe | X |&
118 ampersand &
119 [Redirects] redir-file > >> >| < <> X &>
120 redir-desc >& <&
121 here-doc << <<- <<<
122 [Other Command] dparen (( time X coproc X select
123)zZXx");
124
125GLOBAL_STR(gStr9, R"zZXx(Front End
126
127 [Usage] osh-usage config startup line-editing prompt
128 exit-codes
129 [Lexing] comment # line-continuation \ ascii-whitespace [ \t\r\n]
130)zZXx");
131
132GLOBAL_STR(gStr10, R"zZXx(Other Mini Languages
133
134 [Arithmetic] arith-context Where legacy arithmetic is allowed
135 sh-numbers 0xFF 0755 etc.
136 sh-arith 1 + 2*3 a *= 2
137 sh-logical !a && b
138 sh-bitwise ~a ^ b
139 [Boolean] dbracket [[ vs. the test builtin
140 bool-expr [[ ! $x && $y || $z ]]
141 test ! $x -a $y -o $z
142 bool-infix [[ $a -nt $b ]] [[ $x == $y ]]
143 bool-path [[ -d /etc ]]
144 bool-str [[ -z '' ]]
145 bool-other [[ -o errexit ]]
146 [Patterns] glob-pat *.py
147 extglob ,(*.py|*.sh)
148 regex [[ foo =~ [a-z]+ ]]
149 [Other Sublang] braces {alice,bob}@example.com
150 histsub !$ !! !n
151 char-escapes \t \c \x00 \u03bc
152)zZXx");
153
154GLOBAL_STR(gStr11, R"zZXx(Global Shell Options
155
156 [Errors] nounset pipefail errexit inherit_errexit
157 [Globbing] noglob nullglob failglob dashglob
158 [Debugging] xtrace X verbose X extdebug
159 [Interactive] emacs vi
160 [Other Option] X noclobber
161)zZXx");
162
163GLOBAL_STR(gStr12, R"zZXx(Assignments and Expressions
164
165 [Literals] sh-array array=(a b c) array[1]=B "${a[@]}"
166 sh-assoc assoc=(['a']=1 ['b']=2) assoc['x']=b
167 [Operators] sh-assign str='xyz'
168 sh-append str+='abc'
169 [Builtins] local readonly export unset shift
170 declare typeset X let
171)zZXx");
172
173GLOBAL_STR(gStr13, R"zZXx(Plugins and Hooks
174
175 [Signals] SIGTERM X SIGINT X SIGABRT SIG...
176 [Traps] DEBUG ERR EXIT X RETURN
177 [Words] PS1 X PS2 X PS3 PS4
178 [Completion] complete
179 [Other Plugin] X command_not_found PROMPT_COMMAND
180)zZXx");
181
182GLOBAL_STR(gStr14, R"zZXx(Special Variables
183
184 [Shell Vars] IFS X LANG X GLOBIGNORE
185 [Shell Options] SHELLOPTS X BASHOPTS
186 [Other Env] HOME PATH
187 [POSIX Special] $@ $* $# $? $- $$ $! $0 $9
188 [Other Special] BASH_REMATCH @PIPESTATUS
189 [Platform] HOSTNAME OSTYPE
190 [Call Stack] @BASH_SOURCE @FUNCNAME @BASH_LINENO
191 X @BASH_ARGV X @BASH_ARGC
192 [Tracing] LINENO
193 [Process State] X BASHPID X PPID UID EUID
194X [Process Stack] BASH_SUBSHELL SHLVL
195X [Shell State] BASH_CMDS @DIRSTACK
196 [Completion] @COMP_WORDS COMP_CWORD COMP_LINE COMP_POINT
197 COMP_WORDBREAKS @COMPREPLY X COMP_KEY
198 X COMP_TYPE COMP_ARGV
199 [History] HISTFILE
200 [cd] PWD OLDPWD X CDPATH
201 [getopts] OPTIND OPTARG X OPTERR
202 [read] REPLY
203 [Functions] X RANDOM X SECONDS
204)zZXx");
205
206GLOBAL_STR(gStr15, R"zZXx(bin/osh is compatible with POSIX shell, bash, and other shells.
207
208Usage: osh FLAG* SCRIPT ARG*
209 osh FLAG* -c COMMAND ARG*
210 osh FLAG*
211
212The command line accepted by `bin/osh` is compatible with /bin/sh and bash.
213
214 osh -c 'echo hi'
215 osh myscript.sh
216 echo 'echo hi' | osh
217
218It also has a few enhancements:
219
220 osh -n -c 'hello' # pretty-print the AST
221 osh --ast-format text -n -c 'hello' # print it full
222
223osh accepts POSIX sh flags, with these additions:
224
225 -n parse the program but don't execute it. Print the AST.
226 --ast-format what format the AST should be in
227)zZXx");
228
229GLOBAL_STR(gStr16, R"zZXx(Word Language
230
231 [Quotes] osh-string 'abc' $'line\n' "$var"
232 [Substitutions] command-sub $(command) `command`
233 var-sub ${var} $0 $9
234 arith-sub $((1 + 2))
235 tilde-sub ~/src
236 proc-sub diff <(sort L.txt) <(sort R.txt)
237 [Var Ops] op-test ${x:-default}
238 op-strip ${x%%suffix} etc.
239 op-replace ${x//y/z}
240 op-index ${a[i+1}
241 op-slice ${a[@]:0:1}
242 op-format ${x@P}
243)zZXx");
244
245GLOBAL_STR(gStr17, R"zZXx(Builtin Commands
246
247 [Memory] append Add elements to end of array
248 pp asdl cell X gc-stats line proc
249 [Handle Errors] try Run with errexit, set _status _error
250 boolstatus Enforce 0 or 1 exit status
251 error error 'failed' (status=2)
252 [Shell State] ysh-cd ysh-shopt compatible, and takes a block
253 shvar Temporary modify global settings
254 ctx Share and update a temporary "context"
255 push-registers Save registers like $?, PIPESTATUS
256 [Modules] runproc Run a proc; use as main entry point
257 module guard against duplicate 'source'
258 is-main false when sourcing a file
259 use change first word lookup
260 [I/O] ysh-read flags --all, -0
261 ysh-echo no -e -n with simple_echo
262 write Like echo, with --, --sep, --end
263 fork forkwait Replace & and (), and takes a block
264 fopen Open multiple streams, takes a block
265 X dbg Only thing that can be used in funcs
266 X log X die common functions (polyfill)
267 [Hay Config] hay haynode For DSLs and config files
268 [Completion] compadjust compexport
269 [Data Formats] json read write
270 json8 read write
271 X packle read write, Graph-shaped
272X [TSV8] rows pick rows; dplyr filter()
273 cols pick columns ('select' already taken)
274 group-by add a column with a group ID [ext]
275 sort-by sort by columns; dplyr arrange() [ext]
276 summary count, sum, histogram, etc. [ext]
277 [Args Parser] parser Parse command line arguments
278 flag
279 arg
280 rest
281 parseArgs()
282X [Testing] describe Test harness
283 assert takes an expression
284X [External Lang] BEGIN END when (awk)
285 rule (make) each (xargs) fs (find)
286)zZXx");
287
288GLOBAL_STR(gStr18, R"zZXx(Builtin Functions
289
290 [Values] len() type() X repeat()
291 [Conversions] bool() int() float() str() list() dict()
292 X chr() X ord() X runes()
293X [Str] strcmp() X split() shSplit()
294 [List] join() any() all()
295 [Collections] X copy() X deepCopy()
296 [Word] glob() maybe()
297 [Math] abs() max() min() X round() sum()
298 [Serialize] toJson() fromJson()
299 toJson8() fromJson8()
300X [J8 Decode] J8.Bool() J8.Int() ...
301X [Codecs] quoteUrl() quoteHtml() quoteSh() quoteC()
302 quoteMake() quoteNinja()
303 [Pattern] _group() _start() _end()
304 [Introspection] shvarGet() evalExpr()
305 [Hay Config] parseHay() evalHay()
306X [Wok] _field()
307X [Hashing] sha1dc() sha256()
308)zZXx");
309
310GLOBAL_STR(gStr19, R"zZXx(The reference is divided in to "chapters", each of which has its own table of
311contents. Type:
312
313 help ysh-$CHAPTER
314
315Where $CHAPTER is one of:
316
317 front-end
318 command-lang
319 expr-lang
320 word-lang
321 builtin-cmd
322 option
323 special-var
324 type-method
325 builtin-func
326
327Example:
328
329 help ysh-expr-lang
330)zZXx");
331
332GLOBAL_STR(gStr20, R"zZXx(Command Language
333
334 [YSH Simple] typed-arg json write (x)
335 lazy-expr-arg assert [42 === x]
336 block-arg cd /tmp { echo $PWD }; cd /tmp (; ; blockexpr)
337 [YSH Assign] const var setvar setglobal
338 [YSH Expr] equal = = 1 + 2*3
339 call call mylist->append(42)
340 [YSH Code] proc-def proc p (out Ref; pos, ...rest; n=0; b Block) {
341 func-def func f(x; opt1, opt2) { return (x + 1) }
342 ysh-return return (myexpr)
343 [YSH Cond] ysh-case case (x) { *.py { echo 'python' } }
344 ysh-if if (x > 0) { echo }
345 [YSH Iter] ysh-while while (x > 0) { echo }
346 ysh-for for i, item in (mylist) { echo }
347)zZXx");
348
349GLOBAL_STR(gStr21, R"zZXx(Expression Language and Assignments
350
351 [Assign Ops] = += -= *= /= **= //= %=
352 &= |= ^= <<= >>=
353 [Literals] bool-literal true false null
354 int-literal 42 65_536 0xFF 0o755 0b10
355 float-lit 3.14 1.5e-10
356 X num-suffix 42 K Ki M Mi G Gi T Ti / ms us
357 rune-literal #'a' #'_' \n \\ \u{3bc}
358 ysh-string "$x" r'[a-z]\n' u'line\n' b'byte \yff'
359 triple-quoted """ r''' u''' b'''
360 str-template ^"$a and $b" for Str::replace()
361 list-literal ['one', 'two', 3] :| unquoted words |
362 dict-literal {name: 'bob'}
363 range 1 .. n+1
364 block-literal ^(echo $PWD)
365 expr-lit ^[1 + 2*3]
366 X to-string $[myobj]
367 X to-array @[myobj]
368 [Operators] concat s1 ++ s2, L1 ++ L2
369 ysh-equals === !== ~== is, is not, in, not in
370 ysh-compare < <= > >= (numbers only)
371 ysh-logical not and or
372 ysh-arith + - * / // % **
373 ysh-bitwise ~ & | ^ << >>
374 ysh-ternary '+' if x >= 0 else '-'
375 ysh-index a[3] s[3]
376 ysh-attr mydict.key
377 ysh-slice a[1:-1] s[1:-1]
378 func-call f(x, y)
379 thin-arrow mylist->pop()
380 fat-arrow mystr => startsWith('prefix')
381 match-ops ~ !~ ~~ !~~
382 [Eggex] re-literal / d+ ; re-flags ; ERE /
383 re-primitive %zero 'sq'
384 class-literal [c a-z 'abc' @str_var \\ \xFF \u0100]
385 named-class dot digit space word d s w
386 re-repeat d? d* d+ d{3} d{2,4}
387 re-compound seq1 seq2 alt1|alt2 (expr1 expr2)
388 re-capture <capture d+ as name: int>
389 re-splice Subpattern @subpattern
390 re-flags reg_icase reg_newline
391 X re-multiline ///
392)zZXx");
393
394GLOBAL_STR(gStr22, R"zZXx(Front End
395
396 [Usage] bundle-usage ysh-usage
397 [Lexing] ascii-whitespace [ \t\r\n]
398 doc-comment ### multiline-command ...
399 [Tools] cat-em
400)zZXx");
401
402GLOBAL_STR(gStr23, R"zZXx(Shell Options
403
404 [Option Groups] strict:all ysh:upgrade ysh:all
405 [Strictness] ... More Runtime Errors
406 strict_argv No empty argv
407 strict_arith Fatal parse errors (on by default)
408 strict_array Arrays and strings aren't confused
409 strict_control_flow Disallow misplaced keyword, empty arg
410 strict_errexit Disallow code that ignores failure
411 strict_nameref trap invalid variable names
412 strict_word_eval Expose unicode and slicing errors
413 strict_tilde Tilde subst can result in error
414 X strict_glob Parse the sublanguage more strictly
415 [YSH Upgrade] ... Migrate Existing Code to YSH
416 parse_at echo @array @[arrayfunc(x, y)]
417 parse_brace if true { ... }; cd ~/src { ... }
418 parse_equals x = 'val' in Caps { } config blocks
419 parse_paren if (x > 0) ...
420 parse_proc proc p { ... }
421 parse_triple_quote """$x""" '''x''' (command mode)
422 parse_ysh_string echo r'\' u'\\' b'\\' (command mode)
423 command_sub_errexit Synchronous errexit check
424 process_sub_fail Analogous to pipefail for process subs
425 sigpipe_status_ok status 141 -> 0 in pipelines
426 simple_word_eval No splitting, static globbing
427 xtrace_rich Hierarchical and process tracing
428 xtrace_details (-u) Disable most tracing with +
429 dashglob (-u) Disabled to avoid files like -rf
430 redefine_proc (-u) Can procs be redefined?
431 [Interactive] redefine_module 'module' builtin always returns 0
432 X redefine_const Can consts be redefined?
433 [Simplicity] ... More Consistent Style
434 simple_echo echo doesn't accept flags -e -n
435 simple_eval_builtin eval takes exactly 1 argument
436 simple_test_builtin 3 args or fewer; use test not [
437 X simple_trap Function name only
438 [YSH Breaking] ... The Full YSH Language
439 parse_at_all @ starting any word is an operator
440 parse_backslash (-u) Allow bad backslashes in "" and $''
441 parse_backticks (-u) Allow legacy syntax `echo hi`
442 parse_bare_word (-u) 'case unquoted' and 'for x in unquoted'
443 parse_dollar (-u) Allow bare $ to mean \$ (maybe $/d+/)
444 parse_dbracket (-u) Is legacy [[ allowed?
445 parse_dparen (-u) Is (( legacy arithmetic allowed?
446 parse_ignored (-u) Parse, but ignore, certain redirects
447 parse_sh_arith (-u) Allow legacy shell arithmetic
448 expand_aliases (-u) Whether aliases are expanded
449 X copy_env (-u) Use $[ENV.PYTHONPATH] when false
450 X old_builtins (-u) local/declare/etc. pushd/popd/dirs
451 ... source unset printf [un]alias
452 ... getopts
453 X old_syntax (-u) [[ $(( )) ( ) ${x%prefix}
454 ${a[@]} $$
455 [Compatibility] eval_unsafe_arith Allow dynamically parsed a[$(echo 42)]
456 verbose_errexit Whether to print detailed errors
457 [More Options] _allow_command_sub To implement strict_errexit, eval_unsafe_arith
458 _allow_process_sub To implement strict_errexit
459 dynamic_scope To implement 'proc'
460 _no_debug_trap Used in pipelines in job control shell
461)zZXx");
462
463GLOBAL_STR(gStr24, R"zZXx(Plugins and Hooks
464
465 [YSH] renderPrompt()
466)zZXx");
467
468GLOBAL_STR(gStr25, R"zZXx(Special Variables
469
470 [YSH Vars] ARGV X ENV X _ESCAPE
471 _this_dir
472 [YSH Status] _status _error
473 _pipeline_status _process_sub_status
474 [YSH Tracing] SHX_indent SHX_punct SHX_pid_str
475 [YSH read] _reply
476 [History] YSH_HISTFILE
477 [Oils VM] OILS_VERSION
478 OILS_GC_THRESHOLD OILS_GC_ON_EXIT
479 OILS_GC_STATS OILS_GC_STATS_FD
480X [Wok] _filename _line
481X [Builtin Sub] _buffer
482)zZXx");
483
484GLOBAL_STR(gStr26, R"zZXx(Builtin Types and Methods
485
486 [Primitive] Bool Int Float Str Slice Range
487 [Str] X find(eggex) replace()
488 trim() trimStart() trimEnd()
489 startsWith() endsWith()
490 upper() lower() # ascii or unicode
491 search() leftMatch()
492 [Match] group() start() end()
493 X groups() X groupDict()
494 [List] append() pop() extend() indexOf()
495 X insert() X remove() reverse()
496 [Dict] keys() values() X get() X erase()
497 X inc() X accum()
498X [Func] name() location() toJson()
499X [Proc] name() location() toJson()
500X [Module] name() filename()
501 [Place] setValue()
502 [IO] X eval() X captureStdout()
503 promptVal()
504 X time() X strftime()
505 X glob()
506 [Quotation] Expr X Template Command
507 [Code] BuiltinFunc BuiltinMethod
508X [Guts] heapId()
509)zZXx");
510
511GLOBAL_STR(gStr27, R"zZXx(bin/ysh is the shell with data tYpes, influenced by pYthon, JavaScript, ...
512
513Usage: ysh FLAG* SCRIPT ARG*
514 ysh FLAG* -c COMMAND ARG*
515 ysh FLAG*
516
517`bin/ysh` is the same as `bin/osh` with a the `ysh:all` option group set. So
518`bin/ysh` also accepts shell flags.
519
520 ysh -c 'echo hi'
521 ysh myscript.ysh
522 echo 'echo hi' | ysh
523)zZXx");
524
525GLOBAL_STR(gStr28, R"zZXx(Word Language
526
527 [Quotes] ysh-string "$x" r'[a-z]\n' u'line\n' b'byte \yff'
528 triple-quoted """ r''' u''' b'''
529 X tagged-str "<span id=$x>"html
530 [Substitutions] expr-sub echo $[42 + a[i]]
531 expr-splice echo @[split(x)]
532 var-splice @myarray @ARGV
533 command-sub @(split command)
534 [Formatting] X ysh-printf ${x %.3f}
535 X ysh-format ${x|html}
536)zZXx");
537
538GLOBAL_STR(gStr29, R"zZXx(# args.ysh
539#
540# Usage:
541# source --builtin args.sh
542#
543# parser (&spec) {
544# flag -v --verbose (help="Verbosely") # default is Bool, false
545#
546# flag -P --max-procs ('int', default=-1, doc='''
547# Run at most P processes at a time
548# ''')
549#
550# flag -i --invert ('bool', default=true, doc='''
551# Long multiline
552# Description
553# ''')
554#
555# arg src (help='Source')
556# arg dest (help='Dest')
557# arg times (help='Foo')
558#
559# rest files
560# }
561#
562# var args = parseArgs(spec, ARGV)
563#
564# echo "Verbose $[args.verbose]"
565
566# TODO: See list
567# - It would be nice to keep `flag` and `arg` private, injecting them into the
568# proc namespace only within `Args`
569# - We need "type object" to replace the strings 'int', 'bool', etc.
570# - flag builtin:
571# - handle only long flag or only short flag
572# - flag aliases
573
574proc parser (; place ; ; block_def) {
575 ## Create an args spec which can be passed to parseArgs.
576 ##
577 ## Example:
578 ##
579 ## # NOTE: &spec will create a variable named spec
580 ## parser (&spec) {
581 ## flag -v --verbose ('bool')
582 ## }
583 ##
584 ## var args = parseArgs(spec, ARGV)
585
586 var p = {flags: [], args: []}
587 ctx push (p; ; block_def)
588
589 # Validate that p.rest = [name] or null and reduce p.rest into name or null.
590 if ('rest' in p) {
591 if (len(p.rest) > 1) {
592 error '`rest` was called more than once' (status=3)
593 } else {
594 setvar p.rest = p.rest[0]
595 }
596 } else {
597 setvar p.rest = null
598 }
599
600 var names = {}
601 for items in ([p.flags, p.args]) {
602 for x in (items) {
603 if (x.name in names) {
604 error "Duplicate flag/arg name $[x.name] in spec" (status=3)
605 }
606
607 setvar names[x.name] = null
608 }
609 }
610
611 # TODO: what about `flag --name` and then `arg name`?
612
613 call place->setValue(p)
614}
615
616proc flag (short, long ; type='bool' ; default=null, help=null) {
617 ## Declare a flag within an `arg-parse`.
618 ##
619 ## Examples:
620 ##
621 ## arg-parse (&spec) {
622 ## flag -v --verbose
623 ## flag -n --count ('int', default=1)
624 ## flag -f --file ('str', help="File to process")
625 ## }
626
627 # bool has a default of false, not null
628 if (type === 'bool' and default === null) {
629 setvar default = false
630 }
631
632 # TODO: validate `type`
633
634 # TODO: Should use "trimPrefix"
635 var name = long[2:]
636
637 ctx emit flags ({short, long, name, type, default, help})
638}
639
640proc arg (name ; ; help=null) {
641 ## Declare a positional argument within an `arg-parse`.
642 ##
643 ## Examples:
644 ##
645 ## arg-parse (&spec) {
646 ## arg name
647 ## arg config (help="config file path")
648 ## }
649
650 ctx emit args ({name, help})
651}
652
653proc rest (name) {
654 ## Take the remaining positional arguments within an `arg-parse`.
655 ##
656 ## Examples:
657 ##
658 ## arg-parse (&grepSpec) {
659 ## arg query
660 ## rest files
661 ## }
662
663 # We emit instead of set to detect multiple invocations of "rest"
664 ctx emit rest (name)
665}
666
667func parseArgs(spec, argv) {
668 ## Given a spec created by `parser`. Parse an array of strings `argv` per
669 ## that spec.
670 ##
671 ## See `parser` for examples of use.
672
673 var i = 0
674 var positionalPos = 0
675 var argc = len(argv)
676 var args = {}
677 var rest = []
678
679 var value
680 var found
681 while (i < argc) {
682 var arg = argv[i]
683 if (arg->startsWith('-')) {
684 setvar found = false
685
686 for flag in (spec.flags) {
687 if ( (flag.short and flag.short === arg) or
688 (flag.long and flag.long === arg) ) {
689 case (flag.type) {
690 ('bool') | (null) { setvar value = true }
691 int {
692 setvar i += 1
693 if (i >= len(argv)) {
694 error "Expected integer after '$arg'" (status=2)
695 }
696
697 try { setvar value = int(argv[i]) }
698 if (_status !== 0) {
699 error "Expected integer after '$arg', got '$[argv[i]]'" (status=2)
700 }
701 }
702 }
703
704 setvar args[flag.name] = value
705 setvar found = true
706 break
707 }
708 }
709
710 if (not found) {
711 error "Unknown flag '$arg'" (status=2)
712 }
713 } elif (positionalPos >= len(spec.args)) {
714 if (not spec.rest) {
715 error "Too many arguments, unexpected '$arg'" (status=2)
716 }
717
718 call rest->append(arg)
719 } else {
720 var pos = spec.args[positionalPos]
721 setvar positionalPos += 1
722 setvar value = arg
723 setvar args[pos.name] = value
724 }
725
726 setvar i += 1
727 }
728
729 if (spec.rest) {
730 setvar args[spec.rest] = rest
731 }
732
733 # Set defaults for flags
734 for flag in (spec.flags) {
735 if (flag.name not in args) {
736 setvar args[flag.name] = flag.default
737 }
738 }
739
740 # Raise error on missing args
741 for arg in (spec.args) {
742 if (arg.name not in args) {
743 error "Usage Error: Missing required argument $[arg.name]" (status=2)
744 }
745 }
746
747 return (args)
748}
749)zZXx");
750
751GLOBAL_STR(gStr30, R"zZXx(#!/usr/bin/env ysh
752
753module stdlib/synch || return 0
754
755############################
756### FIFO File Desriptors ###
757############################
758
759proc fifo-fd-new(; out_fd) {
760 # WARN: this section should be critical but for now it's not
761 # A solution may be retry on fail.
762 #====================
763 var fifo = $(mktemp -u)
764 mkfifo $fifo
765 #====================
766 exec {fd}<>$fifo
767 call out_fd->setValue(fd)
768}
769
770proc fifo-fd-destroy(; fd) {
771 var fifoFile = $(readlink /proc/$$/fd/$fd)
772 exec {fd}>&-
773 exec {fd}<&-
774 rm $fifoFile
775}
776
777#################
778### Semaphore ###
779#################
780
781proc sema-new(; value, out_sema) {
782 fifo-fd-new (&sema)
783 sema-up (sema, value)
784 call out_sema->setValue(sema)
785}
786
787proc sema-down(; sema) {
788 read <&$sema
789}
790
791proc sema-up(; sema, delta = 1) {
792 fork {
793 for _ in (0 .. delta) {
794 echo >&$sema
795 }
796 }
797}
798
799proc sema-destroy(; sema) {
800 fifo-fd-destroy (sema)
801}
802)zZXx");
803
804GLOBAL_STR(gStr31, R"zZXx(func identity(x) {
805 ## The identity function. Returns its argument.
806
807 return (x)
808}
809)zZXx");
810
811GLOBAL_STR(gStr32, R"zZXx(func any(list) {
812 ## Returns true if any value in the list is truthy.
813 ##
814 ## If the list is empty, return false.
815
816 for item in (list) {
817 if (item) {
818 return (true)
819 }
820 }
821 return (false)
822}
823
824func all(list) {
825 ## Returns true if all values in the list are truthy.
826 ##
827 ## If the list is empty, return true.
828
829 for item in (list) {
830 if (not item) {
831 return (false)
832 }
833 }
834 return (true)
835}
836
837func sum(list; start=0) {
838 ## Computes the sum of all elements in the list.
839 ##
840 ## Returns 0 for an empty list.
841
842 var sum = start
843 for item in (list) {
844 setvar sum += item
845 }
846 return (sum)
847}
848)zZXx");
849
850GLOBAL_STR(gStr33, R"zZXx(func __math_select(list, cmp) {
851 ## Internal helper for `max` and `min`.
852 ##
853 ## NOTE: If `list` is empty, then an error is thrown.
854
855 if (len(list) === 0) {
856 error "Unexpected empty list" (status=3)
857 }
858
859 if (len(list) === 1) {
860 return (list[0])
861 }
862
863 var match = list[0]
864 for i in (1 .. len(list)) {
865 setvar match = cmp(list[i], match)
866 }
867 return (match)
868}
869
870func max(...args) {
871 ## Compute the maximum of 2 or more values.
872 ##
873 ## `max` takes two different signatures:
874 ## - `max(a, b)` to return the maximum of `a`, `b`
875 ## - `max(list)` to return the greatest item in the `list`
876 ##
877 ## So, for example:
878 ##
879 ## max(1, 2) # => 2
880 ## max([1, 2, 3]) # => 3
881
882 case (len(args)) {
883 (1) { return (__math_select(args[0], max)) }
884 (2) {
885 if (args[0] > args[1]) {
886 return (args[0])
887 } else {
888 return (args[1])
889 }
890 }
891 (else) { error "max expects 1 or 2 args" (status=3) }
892 }
893}
894
895func min(...args) {
896 ## Compute the minimum of 2 or more values.
897 ##
898 ## `min` takes two different signatures:
899 ## - `min(a, b)` to return the minimum of `a`, `b`
900 ## - `min(list)` to return the least item in the `list`
901 ##
902 ## So, for example:
903 ##
904 ## min(2, 3) # => 2
905 ## max([1, 2, 3]) # => 1
906
907 case (len(args)) {
908 (1) { return (__math_select(args[0], min)) }
909 (2) {
910 if (args[0] < args[1]) {
911 return (args[0])
912 } else {
913 return (args[1])
914 }
915 }
916 (else) { error "min expects 1 or 2 args" (status=3) }
917 }
918}
919
920func abs(x) {
921 ## Compute the absolute (positive) value of a number (float or int).
922
923 if (x < 0) {
924 return (-x)
925 } else {
926 return (x)
927 }
928}
929)zZXx");
930
931GLOBAL_STR(gStr34, R"zZXx(# Can we define methods in pure YSH?
932#
933# (mylist->find(42) !== -1)
934#
935# instead of
936#
937# ('42' in mylist)
938#
939# Because 'in' is for Dict
940
941func find (haystack List, needle) {
942 for i, x in (haystack) {
943 if (x === needle) {
944 return (i)
945 }
946 }
947 return (-1)
948}
949)zZXx");
950
951GLOBAL_STR(gStr35, R"zZXx(# These were helpful while implementing args.ysh
952# Maybe we will want to export them in a prelude so that others can use them too?
953#
954# Prior art: Rust has `todo!()` which is quite nice. Other languages allow
955# users to `raise NotImplmentedError()`.
956
957# Andy comments:
958# - 'pass' can be : or true in shell. It's a little obscure / confusing, but
959# there is an argument for minimalism. Although I prefer words like 'true',
960# and that already means something.
961# - UPDATE: we once took 'pass' as a keyword, but users complained because
962# there is a command 'pass'. So we probably can't have this by default.
963# Need to discuss source --builtin.
964
965# - todo could be more static? Rust presumably does it at compile time
966
967proc todo () {
968 ## Raises a not implemented error when run.
969 error ("TODO: not implemented") # TODO: is error code 1 ok?
970}
971
972proc pass () {
973 ## Use when you want to temporarily leave a block empty.
974 _ null
975}
976)zZXx");
977
978GLOBAL_STR(gStr36, R"zZXx(# testing.ysh
979#
980# Usage:
981# source --builtin testing.sh
982#
983# func f(x) { return (x + 1) }
984#
985# describe foo {
986# assert (43 === f(42))
987# }
988#
989# if is-main {
990# run-tests @ARGV # --filter
991# }
992
993module stdlib/testing || return 0
994
995source --builtin args.ysh
996
997# Opt in to lazy evaluation
998
999proc assert ( ; cond LAZY ) {
1000 echo hi
1001
1002 # TODO: evalExpr() builtin
1003 var val = evalExpr(cond)
1004 if (not val) {
1005 # TODO: if it's an expr.Binary
1006 # Then
1007 #
1008 # Then print $left != $right
1009 #
1010 # I think you need to introspect on the source code
1011 #
1012 # Or print '5 != 3'
1013 #
1014 # Or you can evaluate left and right separately, and then compare them
1015
1016 echo
1017 }
1018}
1019
1020# What happens when there are duplicate test IDs?
1021#
1022# Also I think filter by "$test_id/$case_id"
1023
1024proc __it (case_id ; ; ; block) {
1025 # This uses a clean directory
1026 echo TODO
1027}
1028
1029# is this accessible to users?
1030# It can contain a global list of things to run
1031
1032# Naming convention: a proc named 'describe' mutates a global named _describe?
1033# Or maybe _describe_list ?
1034
1035var _describe_list = []
1036
1037proc describe (test_id ; ; ; block) {
1038 echo describe
1039 = desc
1040
1041 # TODO:
1042 # - need append
1043 # - need ::
1044 # _ _describe->append(cmd)
1045 #
1046 # Need to clean this up
1047 # append (_describe, cmd) # does NOT work!
1048
1049 _ _describe_list->append(block)
1050}
1051
1052# Problem: this creates a global variable?
1053Args :spec {
1054 flag --filter 'Regex of test descriptions'
1055}
1056
1057proc run-tests {
1058
1059 # TODO: fix this crap
1060 var opt = null
1061 var i = null
1062 setvar opt, i = parseArgs(spec, ARGV)
1063
1064 # TODO:
1065 # - parse --filter foo, which you can use eggex for!
1066
1067 for cmd in (_describe) {
1068 # TODO: print filename and 'describe' name?
1069 try {
1070 eval (cmd)
1071 }
1072 if (_status !== 0) {
1073 echo 'failed'
1074 }
1075 }
1076}
1077)zZXx");
1078
1079
1080
1081TextFile array[] = {
1082 {.rel_path = "_devbuild/help/data-errors", .contents = gStr0},
1083 {.rel_path = "_devbuild/help/data-front-end", .contents = gStr1},
1084 {.rel_path = "_devbuild/help/data-j8-notation", .contents = gStr2},
1085 {.rel_path = "_devbuild/help/data-packle", .contents = gStr3},
1086 {.rel_path = "_devbuild/help/help", .contents = gStr4},
1087 {.rel_path = "_devbuild/help/oils-usage", .contents = gStr5},
1088 {.rel_path = "_devbuild/help/osh-builtin-cmd", .contents = gStr6},
1089 {.rel_path = "_devbuild/help/osh-chapters", .contents = gStr7},
1090 {.rel_path = "_devbuild/help/osh-cmd-lang", .contents = gStr8},
1091 {.rel_path = "_devbuild/help/osh-front-end", .contents = gStr9},
1092 {.rel_path = "_devbuild/help/osh-mini-lang", .contents = gStr10},
1093 {.rel_path = "_devbuild/help/osh-option", .contents = gStr11},
1094 {.rel_path = "_devbuild/help/osh-osh-assign", .contents = gStr12},
1095 {.rel_path = "_devbuild/help/osh-plugin", .contents = gStr13},
1096 {.rel_path = "_devbuild/help/osh-special-var", .contents = gStr14},
1097 {.rel_path = "_devbuild/help/osh-usage", .contents = gStr15},
1098 {.rel_path = "_devbuild/help/osh-word-lang", .contents = gStr16},
1099 {.rel_path = "_devbuild/help/ysh-builtin-cmd", .contents = gStr17},
1100 {.rel_path = "_devbuild/help/ysh-builtin-func", .contents = gStr18},
1101 {.rel_path = "_devbuild/help/ysh-chapters", .contents = gStr19},
1102 {.rel_path = "_devbuild/help/ysh-cmd-lang", .contents = gStr20},
1103 {.rel_path = "_devbuild/help/ysh-expr-lang", .contents = gStr21},
1104 {.rel_path = "_devbuild/help/ysh-front-end", .contents = gStr22},
1105 {.rel_path = "_devbuild/help/ysh-option", .contents = gStr23},
1106 {.rel_path = "_devbuild/help/ysh-plugin", .contents = gStr24},
1107 {.rel_path = "_devbuild/help/ysh-special-var", .contents = gStr25},
1108 {.rel_path = "_devbuild/help/ysh-type-method", .contents = gStr26},
1109 {.rel_path = "_devbuild/help/ysh-usage", .contents = gStr27},
1110 {.rel_path = "_devbuild/help/ysh-word-lang", .contents = gStr28},
1111 {.rel_path = "stdlib/args.ysh", .contents = gStr29},
1112 {.rel_path = "stdlib/draft-synch.ysh", .contents = gStr30},
1113 {.rel_path = "stdlib/funcs.ysh", .contents = gStr31},
1114 {.rel_path = "stdlib/list.ysh", .contents = gStr32},
1115 {.rel_path = "stdlib/math.ysh", .contents = gStr33},
1116 {.rel_path = "stdlib/methods.ysh", .contents = gStr34},
1117 {.rel_path = "stdlib/prelude.ysh", .contents = gStr35},
1118 {.rel_path = "stdlib/testing.ysh", .contents = gStr36},
1119
1120 {.rel_path = nullptr, .contents = nullptr},
1121};
1122
1123} // namespace embedded_file
1124
1125TextFile* gEmbeddedFiles = embedded_file::array; // turn array into pointer