| 1 | 
 | 
| 2 | #include "cpp/embedded_file.h"
 | 
| 3 | 
 | 
| 4 | namespace embedded_file {
 | 
| 5 | GLOBAL_STR(gStr0, R"zZXx(
 | 
| 6 |   Errors
 | 
| 7 |   <a class="group-link" href="chap-errors.html">errors</a>
 | 
| 8 | 
 | 
| 9 | 
 | 
| 10 |   [UTF8]      err-utf8-encode       err-utf8-decode
 | 
| 11 |   [J8 String] err-j8-str-encode     err-j8-str-decode
 | 
| 12 |   [J8 Lines]  err-j8-lines-encode   err-j8-lines-decode
 | 
| 13 |   [JSON]      err-json-encode       err-json-decode
 | 
| 14 |   [JSON8]     err-json8-encode      err-json8-decode
 | 
| 15 | )zZXx");
 | 
| 16 | 
 | 
| 17 | GLOBAL_STR(gStr1, R"zZXx(
 | 
| 18 |   
 | 
| 19 |   Front End <a class="group-link" href="chap-front-end.html">front-end</a>
 | 
| 20 | 
 | 
| 21 | 
 | 
| 22 |   [Lexing]        ascii-whitespace [ \t\r\n]
 | 
| 23 |                   ascii-control-chars
 | 
| 24 | )zZXx");
 | 
| 25 | 
 | 
| 26 | GLOBAL_STR(gStr2, R"zZXx(
 | 
| 27 |   J8 Notation
 | 
| 28 |   <a class="group-link" href="chap-j8.html">j8</a>
 | 
| 29 | 
 | 
| 30 | 
 | 
| 31 |   [J8 Strings]   json-string        "hi"
 | 
| 32 |                  json-escape        \"  \\  \u1234
 | 
| 33 |                  surrogate-pair     \ud83e\udd26
 | 
| 34 |                  j8-escape          \'  \u{1f926}  \yff
 | 
| 35 |                  u-prefix           u'hi'
 | 
| 36 |                  b-prefix           b'hi'
 | 
| 37 |                  no-prefix          'hi'
 | 
| 38 |   [J8 Lines]     unquoted-line
 | 
| 39 |   [JSON8]        json8-num          json8-str
 | 
| 40 |                X json8-list       X json8-dict
 | 
| 41 |                  json8-comment
 | 
| 42 |   [TSV8]         column-attrs       column-types
 | 
| 43 | )zZXx");
 | 
| 44 | 
 | 
| 45 | GLOBAL_STR(gStr3, R"zZXx(Usage: help TOPIC?
 | 
| 46 | 
 | 
| 47 | Examples:
 | 
| 48 | 
 | 
| 49 |     help               # this help
 | 
| 50 |     help echo          # help on the 'echo' builtin
 | 
| 51 |     help command-sub   # help on command sub $(date)
 | 
| 52 | 
 | 
| 53 |     help oils-usage    # identical to oils-for-unix --help
 | 
| 54 |     help osh-usage     #              osh --help
 | 
| 55 |     help ysh-usage     #              ysh --help
 | 
| 56 | )zZXx");
 | 
| 57 | 
 | 
| 58 | GLOBAL_STR(gStr4, R"zZXx(bin/oils-for-unix is an executable that contains OSH, YSH, and more.
 | 
| 59 | 
 | 
| 60 | Usage: oils-for-unix MAIN_NAME ARG*
 | 
| 61 |        MAIN_NAME ARG*
 | 
| 62 | 
 | 
| 63 | It behaves like busybox.  The command name can be passed as the first argument:
 | 
| 64 | 
 | 
| 65 |     oils-for-unix ysh -c 'echo hi'
 | 
| 66 | 
 | 
| 67 | More commonly, it's invoked through a symlink like 'ysh', which causes it to
 | 
| 68 | behave like that command:
 | 
| 69 | 
 | 
| 70 |     ysh -c 'echo hi'
 | 
| 71 | )zZXx");
 | 
| 72 | 
 | 
| 73 | GLOBAL_STR(gStr5, R"zZXx(
 | 
| 74 |   Builtin Commands <a class="group-link" href="chap-builtin-cmd.html">builtin-cmd</a>
 | 
| 75 | 
 | 
| 76 | 
 | 
| 77 |   [I/O]           read        echo      printf
 | 
| 78 |                   readarray   mapfile
 | 
| 79 |   [Run Code]      source .    eval      trap
 | 
| 80 |   [Set Options]   set         shopt
 | 
| 81 |   [Working Dir]   cd          pwd       pushd     popd         dirs
 | 
| 82 |   [Completion]    complete    compgen   compopt   compadjust   compexport
 | 
| 83 |   [Shell Process] exec      X logout 
 | 
| 84 |                   umask       ulimit    times
 | 
| 85 |   [Child Process] jobs        wait
 | 
| 86 |                   fg        X bg      X kill        X disown 
 | 
| 87 |   [External]      test [      getopts
 | 
| 88 |   [Introspection] help        hash      cmd/type    X caller
 | 
| 89 |   [Word Lookup]   command     builtin
 | 
| 90 |   [Interactive]   alias       unalias   history     X fc     X bind
 | 
| 91 | X [Unsupported]   enable
 | 
| 92 | )zZXx");
 | 
| 93 | 
 | 
| 94 | GLOBAL_STR(gStr6, R"zZXx(The reference is divided in to "chapters", each of which has its own table of
 | 
| 95 | contents.  Type:
 | 
| 96 | 
 | 
| 97 |     help osh-$CHAPTER
 | 
| 98 | 
 | 
| 99 | Where $CHAPTER is one of:
 | 
| 100 | 
 | 
| 101 |     front-end
 | 
| 102 |     command-lang
 | 
| 103 |     osh-assign
 | 
| 104 |     word-lang
 | 
| 105 |     mini-lang
 | 
| 106 |     builtin-cmd
 | 
| 107 |     option
 | 
| 108 |     special-var
 | 
| 109 |     plugin
 | 
| 110 | 
 | 
| 111 | Example:
 | 
| 112 | 
 | 
| 113 |     help osh-word-lang
 | 
| 114 | )zZXx");
 | 
| 115 | 
 | 
| 116 | GLOBAL_STR(gStr7, R"zZXx(
 | 
| 117 |   Command Language <a class="group-link" href="chap-cmd-lang.html">cmd-lang</a>
 | 
| 118 | 
 | 
| 119 | 
 | 
| 120 |   [Commands]      simple-command            semicolon ;
 | 
| 121 |   [Conditional]   case        if            dbracket [[
 | 
| 122 |                   true        false         colon :
 | 
| 123 |                   bang !      and &&        or ||
 | 
| 124 |   [Iteration]     while       until         for            for-expr-sh ((
 | 
| 125 |   [Control Flow]  break       continue      return         exit
 | 
| 126 |   [Grouping]      sh-func     sh-block {    subshell (
 | 
| 127 |   [Concurrency]   pipe |    X pipe-amp |&   ampersand &
 | 
| 128 |   [Redirects]     redir-file  >  >>  >|  <  <>   not impl: &>
 | 
| 129 |                   redir-desc  >&  <&
 | 
| 130 |                   here-doc    <<  <<-  <<<
 | 
| 131 |   [Other Command] dparen ((   time        X coproc       X select
 | 
| 132 | )zZXx");
 | 
| 133 | 
 | 
| 134 | GLOBAL_STR(gStr8, R"zZXx(
 | 
| 135 |   Front End <a class="group-link" href="chap-front-end.html">front-end</a>
 | 
| 136 | 
 | 
| 137 | 
 | 
| 138 |   [Usage]         oils-usage   osh-usage             config
 | 
| 139 |                   startup      line-editing          exit-codes
 | 
| 140 |   [Lexing]        comment #    line-continuation \   ascii-whitespace [ \t\r\n]
 | 
| 141 | )zZXx");
 | 
| 142 | 
 | 
| 143 | GLOBAL_STR(gStr9, R"zZXx(
 | 
| 144 |   Other Mini Languages <a class="group-link" href="chap-mini-lang.html">mini-lang</a>
 | 
| 145 | 
 | 
| 146 | 
 | 
| 147 |   [Arithmetic]    arith-context Where legacy arithmetic is allowed
 | 
| 148 |                   sh-numbers    0xFF  0755  etc.
 | 
| 149 |                   sh-arith      1 + 2*3   a *= 2
 | 
| 150 |                   sh-logical    !a && b
 | 
| 151 |                   sh-bitwise    ~a ^ b
 | 
| 152 |   [Boolean]       bool-expr     [[ ! $x && $y || $z ]]
 | 
| 153 |                                 test ! $x -a $y -o $z
 | 
| 154 |                   bool-infix    $a -nt $b    $x == $y
 | 
| 155 |                   bool-path     -d /etc
 | 
| 156 |                   bool-str      -n foo   -z '' 
 | 
| 157 |                   bool-other    -o errexit   -v name[index]
 | 
| 158 |   [Patterns]      glob-pat      *.py
 | 
| 159 |                   extglob       ,(*.py|*.sh)
 | 
| 160 |                   regex         [[ foo =~ [a-z]+ ]]
 | 
| 161 |   [Other Sublang] braces        {alice,bob}@example.com
 | 
| 162 |                   histsub       !$  !!  !n
 | 
| 163 |                   char-escapes  \t  \c  \x00  \u03bc
 | 
| 164 | )zZXx");
 | 
| 165 | 
 | 
| 166 | GLOBAL_STR(gStr10, R"zZXx(
 | 
| 167 |   Global Shell Options <a class="group-link" href="chap-option.html">option</a>
 | 
| 168 | 
 | 
| 169 | 
 | 
| 170 |   [Errors]         nounset -u      errexit -e   inherit_errexit   pipefail
 | 
| 171 |   [Globbing]       noglob -f       nullglob     failglob        X dotglob
 | 
| 172 |                    dashglob (true)
 | 
| 173 |   [Debugging]      xtrace        X verbose    X extdebug
 | 
| 174 |   [Interactive]    emacs           vi
 | 
| 175 |   [Other POSIX]  X noclobber
 | 
| 176 |   [Compat]         eval_unsafe_arith            ignore_flags_not_impl
 | 
| 177 | )zZXx");
 | 
| 178 | 
 | 
| 179 | GLOBAL_STR(gStr11, R"zZXx(
 | 
| 180 |   Assignments and Expressions <a class="group-link" href="chap-osh-assign.html">osh-assign</a>
 | 
| 181 | 
 | 
| 182 | 
 | 
| 183 |   [Literals]      sh-array      array=(a b c)   array[1]=B   "${a[@]}"
 | 
| 184 |                   sh-assoc      assoc=(['a']=1 ['b']=2)   assoc['x']=b
 | 
| 185 |   [Operators]     sh-assign     str='xyz'
 | 
| 186 |                   sh-append     str+='abc'
 | 
| 187 |   [Builtins]      local     readonly    export   unset   shift
 | 
| 188 |                   declare   typeset   X let
 | 
| 189 | )zZXx");
 | 
| 190 | 
 | 
| 191 | GLOBAL_STR(gStr12, R"zZXx(
 | 
| 192 |   Plugins and Hooks <a class="group-link" href="chap-plugin.html">plugin</a>
 | 
| 193 | 
 | 
| 194 | 
 | 
| 195 |   [Signals]       SIGTERM     SIGINT     SIGQUIT
 | 
| 196 |                   SIGTTIN     SIGTTOU    SIGWINCH
 | 
| 197 |   [Traps]         DEBUG       ERR        EXIT    X RETURN
 | 
| 198 |   [Words]         PS1       X PS2      X PS3       PS4
 | 
| 199 |   [Completion]    complete
 | 
| 200 |   [Other Plugin]  PROMPT_COMMAND       X command_not_found    
 | 
| 201 | )zZXx");
 | 
| 202 | 
 | 
| 203 | GLOBAL_STR(gStr13, R"zZXx(
 | 
| 204 |   Special Variables <a class="group-link" href="chap-special-var.html">special-var</a>
 | 
| 205 | 
 | 
| 206 | 
 | 
| 207 |   [POSIX Special] $@  $*  $#     $?  $-     $$  $!   $0  $9
 | 
| 208 |   [Shell Vars]    IFS             X LANG       X GLOBIGNORE
 | 
| 209 |   [Shell Options] SHELLOPTS       X BASHOPTS
 | 
| 210 |   [Other Env]     HOME              PATH
 | 
| 211 |   [Other Special] BASH_REMATCH     @PIPESTATUS
 | 
| 212 |   [Platform]      HOSTNAME          OSTYPE
 | 
| 213 |   [Call Stack]    @BASH_SOURCE     @FUNCNAME    @BASH_LINENO   
 | 
| 214 |                 X @BASH_ARGV     X @BASH_ARGC
 | 
| 215 |   [Tracing]       LINENO
 | 
| 216 |   [Process State] UID               EUID         PPID       X BASHPID
 | 
| 217 | X [Process Stack] BASH_SUBSHELL     SHLVL
 | 
| 218 | X [Shell State]   BASH_CMDS        @DIRSTACK
 | 
| 219 |   [Completion]   @COMP_WORDS        COMP_CWORD    COMP_LINE   COMP_POINT
 | 
| 220 |                   COMP_WORDBREAKS  @COMPREPLY   X COMP_KEY
 | 
| 221 |                 X COMP_TYPE         COMP_ARGV
 | 
| 222 |   [History]       HISTFILE
 | 
| 223 |   [cd]            PWD               OLDPWD      X CDPATH
 | 
| 224 |   [getopts]       OPTIND            OPTARG      X OPTERR
 | 
| 225 |   [read]          REPLY
 | 
| 226 |   [Functions]   X RANDOM            SECONDS
 | 
| 227 | )zZXx");
 | 
| 228 | 
 | 
| 229 | GLOBAL_STR(gStr14, R"zZXx(
 | 
| 230 |   OSH Types <a class="group-link" href="chap-type-method.html">type-method</a>
 | 
| 231 | 
 | 
| 232 | 
 | 
| 233 |   [OSH]           BashArray   BashAssoc
 | 
| 234 | )zZXx");
 | 
| 235 | 
 | 
| 236 | GLOBAL_STR(gStr15, R"zZXx(bin/osh is compatible with POSIX shell, bash, and other shells.
 | 
| 237 | 
 | 
| 238 | Usage: osh FLAG* SCRIPT ARG*
 | 
| 239 |        osh FLAG* -c COMMAND ARG*
 | 
| 240 |        osh FLAG*
 | 
| 241 | 
 | 
| 242 | The command line accepted by `bin/osh` is compatible with /bin/sh and bash.
 | 
| 243 | 
 | 
| 244 |     osh -c 'echo hi'
 | 
| 245 |     osh myscript.sh
 | 
| 246 |     echo 'echo hi' | osh
 | 
| 247 | 
 | 
| 248 | It also has a few enhancements:
 | 
| 249 | 
 | 
| 250 |     osh -n -c 'hello'                    # pretty-print the AST
 | 
| 251 |     osh --ast-format text -n -c 'hello'  # print it full
 | 
| 252 | 
 | 
| 253 | osh accepts POSIX sh flags, with these additions:
 | 
| 254 | 
 | 
| 255 |     -n             parse the program but don't execute it.  Print the AST.
 | 
| 256 |     --ast-format   what format the AST should be in
 | 
| 257 | )zZXx");
 | 
| 258 | 
 | 
| 259 | GLOBAL_STR(gStr16, R"zZXx(
 | 
| 260 |   Word Language <a class="group-link" href="chap-word-lang.html">word-lang</a>
 | 
| 261 | 
 | 
| 262 | 
 | 
| 263 |   [Quotes]        osh-string    'abc'  $'line\n'  "$var"
 | 
| 264 |   [Substitutions] command-sub   $(command)   `command`
 | 
| 265 |                   var-sub       ${var}   $0   $9   
 | 
| 266 |                   arith-sub     $((1 + 2))
 | 
| 267 |                   tilde-sub     ~/src
 | 
| 268 |                   proc-sub      diff <(sort L.txt) <(sort R.txt)
 | 
| 269 |   [Var Ops]       op-test       ${x:-default}  
 | 
| 270 |                   op-strip      ${x%%suffix}  etc.
 | 
| 271 |                   op-replace    ${x//y/z}
 | 
| 272 |                   op-index      ${a[i+1}
 | 
| 273 |                   op-slice      ${a[@]:0:1}
 | 
| 274 |                   op-format     ${x@P}
 | 
| 275 | )zZXx");
 | 
| 276 | 
 | 
| 277 | GLOBAL_STR(gStr17, R"zZXx(
 | 
| 278 |   Builtin Commands <a class="group-link" href="chap-builtin-cmd.html">builtin-cmd</a>
 | 
| 279 | 
 | 
| 280 | 
 | 
| 281 |   [Memory]        cmd/append             Add elements to end of array
 | 
| 282 |                   pp                     asdl   cell   X gc-stats   line   proc
 | 
| 283 |   [Handle Errors] error                  error 'failed' (status=2)
 | 
| 284 |                   try                    Run with errexit, set _error
 | 
| 285 |                   failed                 Test if _error.code !== 0
 | 
| 286 |                   boolstatus             Enforce 0 or 1 exit status
 | 
| 287 |   [Shell State]   ysh-cd       ysh-shopt compatible, and takes a block
 | 
| 288 |                   shvar                  Temporary modify global settings
 | 
| 289 |                   ctx                    Share and update a temporary "context"
 | 
| 290 |                   push-registers         Save registers like $?, PIPESTATUS
 | 
| 291 |   [Modules]       runproc                Run a proc; use as main entry point
 | 
| 292 |                   module                 guard against duplicate 'source'
 | 
| 293 |                   is-main                false when sourcing a file
 | 
| 294 |                   use                    change first word lookup
 | 
| 295 |   [I/O]           ysh-read               flags --all, -0
 | 
| 296 |                   ysh-echo               no -e -n with simple_echo
 | 
| 297 |                   write                  Like echo, with --, --sep, --end
 | 
| 298 |                   fork         forkwait  Replace & and (), and takes a block
 | 
| 299 |                   fopen                  Open multiple streams, takes a block
 | 
| 300 |                 X dbg                    Only thing that can be used in funcs
 | 
| 301 |                 X log        X die       Common functions (polyfill)
 | 
| 302 |   [Hay Config]    hay          haynode   For DSLs and config files
 | 
| 303 |   [Completion]    compadjust   compexport
 | 
| 304 |   [Data Formats]  json                   read write
 | 
| 305 |                   json8                  read write
 | 
| 306 | X [Lines]         slurp-by               combine adjacent lines into cells
 | 
| 307 | X [Awk]           each-line              --j8 --max-jobs (Str, Template, Block) - xargs
 | 
| 308 |                   each-row               --max-jobs (Str, Template, Block) - xargs
 | 
| 309 |                   split-by               (str=\n, ifs=':', pattern=/s+/)
 | 
| 310 |                   if-split-by  
 | 
| 311 |                   chop                   alias for split-by (pattern=/s+/)
 | 
| 312 |                   must-match             (/ <capture d+> </capture w+> /)
 | 
| 313 |                   if-match               
 | 
| 314 | X [Table Create]  table                  --by-row --by-col (&place); construct/parse a table
 | 
| 315 |                   table/cols             cols name age - cols name:Str age:Int
 | 
| 316 |                   types                  type       Str Int
 | 
| 317 |                   attr                   attr units -   secs
 | 
| 318 |                   row                    emit row
 | 
| 319 |                   table cat              concatenate TSV8
 | 
| 320 |                   table align            to ssv8
 | 
| 321 |                   table tabify           to tsv8
 | 
| 322 |                   table header           (cols = :|name age|, types = :|Str Int|, units = :|- secs|)
 | 
| 323 |                   table slice            e.g. slice (1, -1)   slice (5, 7)
 | 
| 324 |                   table to-tsv           lose type info, and error on \t in cells
 | 
| 325 | X [Table Ops]     where                  subset of rows; dplyr filter()
 | 
| 326 |                   pick                   subset of columns ('select' taken by shell)
 | 
| 327 |                   mutate    transmute    [average = count / sum] - drop the ones that are used?
 | 
| 328 |                   rename                 (bytes='bytes', path='filename')
 | 
| 329 |                   group-by               add a column with a group ID [ext]
 | 
| 330 |                   sort-by                sort by columns; dplyr arrange() [ext]
 | 
| 331 |                   summary                count, sum, histogram, any, all, reduce(), etc. [ext]
 | 
| 332 |   [Args Parser]   parser                 Parse command line arguments
 | 
| 333 |                   flag
 | 
| 334 |                   arg
 | 
| 335 |                   rest
 | 
| 336 |                   parseArgs()
 | 
| 337 | X [Testing]       describe               Test harness
 | 
| 338 |                   assert                 takes an expression
 | 
| 339 | )zZXx");
 | 
| 340 | 
 | 
| 341 | GLOBAL_STR(gStr18, R"zZXx(
 | 
| 342 |   Builtin Functions <a class="group-link" href="chap-builtin-func.html">builtin-func</a>
 | 
| 343 | 
 | 
| 344 | 
 | 
| 345 |   [Values]        len()        func/type()   X repeat()
 | 
| 346 |   [Conversions]   bool()       int()           float()   str()   list()   dict()
 | 
| 347 |                 X runes()    X encodeRunes()
 | 
| 348 |                 X bytes()    X encodeBytes()
 | 
| 349 |   [Str]         X strcmp()   X split()         shSplit()
 | 
| 350 |   [List]          join()       any()           all()
 | 
| 351 |   [Collections] X copy()     X deepCopy()
 | 
| 352 |   [Word]          glob()       maybe()
 | 
| 353 |   [Math]          abs()        max()           min()   X round()   sum()
 | 
| 354 |   [Serialize]     toJson()     fromJson()
 | 
| 355 |                   toJson8()    fromJson8()
 | 
| 356 | X [J8 Decode]     J8.Bool()    J8.Int()        ...
 | 
| 357 |   [Pattern]       _group()     _start()        _end()
 | 
| 358 |   [Introspection] shvarGet()   getVar()        evalExpr()
 | 
| 359 |   [Hay Config]    parseHay()   evalHay()
 | 
| 360 | X [Hashing]       sha1dc()     sha256()
 | 
| 361 | )zZXx");
 | 
| 362 | 
 | 
| 363 | GLOBAL_STR(gStr19, R"zZXx(The reference is divided in to "chapters", each of which has its own table of
 | 
| 364 | contents.  Type:
 | 
| 365 | 
 | 
| 366 |     help ysh-$CHAPTER
 | 
| 367 | 
 | 
| 368 | Where $CHAPTER is one of:
 | 
| 369 | 
 | 
| 370 |     front-end
 | 
| 371 |     command-lang
 | 
| 372 |     expr-lang
 | 
| 373 |     word-lang
 | 
| 374 |     builtin-cmd
 | 
| 375 |     option
 | 
| 376 |     special-var
 | 
| 377 |     type-method
 | 
| 378 |     builtin-func
 | 
| 379 | 
 | 
| 380 | Example:
 | 
| 381 | 
 | 
| 382 |     help ysh-expr-lang
 | 
| 383 | )zZXx");
 | 
| 384 | 
 | 
| 385 | GLOBAL_STR(gStr20, R"zZXx(
 | 
| 386 |   Command Language <a class="group-link" href="chap-cmd-lang.html">cmd-lang</a>
 | 
| 387 | 
 | 
| 388 | 
 | 
| 389 |   [YSH Simple]    typed-arg     json write (x)
 | 
| 390 |                   lazy-expr-arg assert [42 === x]
 | 
| 391 |                   block-arg     cd /tmp { echo $PWD }; cd /tmp (; ; blockexpr)
 | 
| 392 |   [YSH Cond]      ysh-case      case (x) { *.py { echo 'python' } }
 | 
| 393 |                   ysh-if        if (x > 0) { echo }
 | 
| 394 |   [YSH Iter]      ysh-while     while (x > 0) { echo }
 | 
| 395 |                   ysh-for       for i, item in (mylist) { echo }
 | 
| 396 | )zZXx");
 | 
| 397 | 
 | 
| 398 | GLOBAL_STR(gStr21, R"zZXx(
 | 
| 399 |   Expression Language and Assignments <a class="group-link" href="chap-expr-lang.html">expr-lang</a>
 | 
| 400 | 
 | 
| 401 | 
 | 
| 402 |   [Assignment]    assign        =
 | 
| 403 |                   aug-assign    +=   -=   *=   /=   **=   //=   %=
 | 
| 404 |                                 &=   |=   ^=   <<=   >>=
 | 
| 405 |   [Literals]      atom-literal  true   false   null
 | 
| 406 |                   int-literal   42  65_536  0xFF  0o755  0b10
 | 
| 407 |                   float-lit     3.14  1.5e-10
 | 
| 408 |                 X num-suffix    42 K Ki M Mi G Gi T Ti / ms us
 | 
| 409 |                   ysh-string    "x is $x"  $"x is $x"   r'[a-z]\n'
 | 
| 410 |                                 u'line\n'  b'byte \yff'
 | 
| 411 |                   triple-quoted """  $"""  r'''  u'''  b'''
 | 
| 412 |                   str-template  ^"$a and $b" for Str::replace()
 | 
| 413 |                   list-literal  ['one', 'two', 3]  :| unquoted words |
 | 
| 414 |                   dict-literal  {name: 'bob'}  {a, b}
 | 
| 415 |                   range         1 .. n+1
 | 
| 416 |                   block-expr    ^(echo $PWD)
 | 
| 417 |                   expr-literal  ^[1 + 2*3]
 | 
| 418 |                 X expr-sub      $[myobj]
 | 
| 419 |                 X expr-splice   @[myobj]
 | 
| 420 |   [Operators]     op-precedence Like Python
 | 
| 421 |                   concat        s1 ++ s2,  L1 ++ L2
 | 
| 422 |                   ysh-equals    ===   !==   ~==   is, is not
 | 
| 423 |                   ysh-in        in, not in
 | 
| 424 |                   ysh-compare   <  <=  >  >=  (numbers only)
 | 
| 425 |                   ysh-logical   not  and  or
 | 
| 426 |                   ysh-arith     +  -  *  /  //  %   ** 
 | 
| 427 |                   ysh-bitwise   ~  &  |  ^  <<  >>
 | 
| 428 |                   ysh-ternary   '+' if x >= 0 else '-'
 | 
| 429 |                   ysh-index     s[0]  mylist[3]  mydict['key']
 | 
| 430 |                   ysh-attr      mydict.key
 | 
| 431 |                   ysh-slice     a[1:-1]  s[1:-1]
 | 
| 432 |                   func-call     f(x, y; ...named)
 | 
| 433 |                   thin-arrow    mylist->pop()
 | 
| 434 |                   fat-arrow     mystr => startsWith('prefix')
 | 
| 435 |                   match-ops     ~   !~   ~~   !~~
 | 
| 436 |   [Eggex]         re-literal    / d+ ; re-flags ; ERE /
 | 
| 437 |                   re-primitive  %zero    'sq'
 | 
| 438 |                   class-literal [c a-z 'abc' @str_var \\ \xFF \u0100]
 | 
| 439 |                   named-class    dot   digit   space   word   d  s  w
 | 
| 440 |                   re-repeat     d?   d*   d+   d{3}   d{2,4}
 | 
| 441 |                   re-compound    seq1 seq2   alt1|alt2   (expr1 expr2)
 | 
| 442 |                   re-capture    <capture d+ as name: int>
 | 
| 443 |                   re-splice     Subpattern   @subpattern
 | 
| 444 |                   re-flags      reg_icase   reg_newline
 | 
| 445 |                 X re-multiline  ///
 | 
| 446 | )zZXx");
 | 
| 447 | 
 | 
| 448 | GLOBAL_STR(gStr22, R"zZXx(
 | 
| 449 |   Front End <a class="group-link" href="chap-front-end.html">front-end</a>
 | 
| 450 | 
 | 
| 451 | 
 | 
| 452 |   [Usage]         oils-usage                   ysh-usage
 | 
| 453 |   [Lexing]        ascii-whitespace [ \t\r\n]
 | 
| 454 |                   doc-comment ###              multiline-command ...
 | 
| 455 |   [Tools]         cat-em
 | 
| 456 | )zZXx");
 | 
| 457 | 
 | 
| 458 | GLOBAL_STR(gStr23, R"zZXx(
 | 
| 459 |   Other Mini Languages <a class="group-link" href="chap-mini-lang.html">mini-lang</a>
 | 
| 460 | 
 | 
| 461 | 
 | 
| 462 |   [Patterns]      glob-pat      *.py
 | 
| 463 |   [Other Sublang] braces        {alice,bob}@example.com
 | 
| 464 | )zZXx");
 | 
| 465 | 
 | 
| 466 | GLOBAL_STR(gStr24, R"zZXx(
 | 
| 467 |   Global Shell Options <a class="group-link" href="chap-option.html">option</a>
 | 
| 468 | 
 | 
| 469 | 
 | 
| 470 |   [Groups]       strict:all      ysh:upgrade     ysh:all
 | 
| 471 |   [YSH Details]  opts-redefine   opts-internal
 | 
| 472 | )zZXx");
 | 
| 473 | 
 | 
| 474 | GLOBAL_STR(gStr25, R"zZXx(
 | 
| 475 |   Plugins and Hooks <a class="group-link" href="chap-plugin.html">plugin</a>
 | 
| 476 | 
 | 
| 477 | 
 | 
| 478 |   [YSH]   renderPrompt()
 | 
| 479 | )zZXx");
 | 
| 480 | 
 | 
| 481 | GLOBAL_STR(gStr26, R"zZXx(
 | 
| 482 |   Special Variables <a class="group-link" href="chap-special-var.html">special-var</a>
 | 
| 483 | 
 | 
| 484 | 
 | 
| 485 |   [YSH Vars]      ARGV              X ENV                 X _ESCAPE
 | 
| 486 |                   _this_dir
 | 
| 487 |   [YSH Status]    _error
 | 
| 488 |                   _pipeline_status    _process_sub_status
 | 
| 489 |   [YSH Tracing]   SHX_indent          SHX_punct             SHX_pid_str
 | 
| 490 |   [YSH read]      _reply
 | 
| 491 |   [History]       YSH_HISTFILE
 | 
| 492 |   [Oils VM]       OILS_VERSION
 | 
| 493 |                   OILS_GC_THRESHOLD   OILS_GC_ON_EXIT
 | 
| 494 |                   OILS_GC_STATS       OILS_GC_STATS_FD
 | 
| 495 | )zZXx");
 | 
| 496 | 
 | 
| 497 | GLOBAL_STR(gStr27, R"zZXx(
 | 
| 498 |   Types and Methods <a class="group-link" href="chap-type-method.html">type-method</a>
 | 
| 499 | 
 | 
| 500 | 
 | 
| 501 |   [Atom Types]     Null           Bool
 | 
| 502 |   [Number Types]   Int            Float
 | 
| 503 |   [Str]          X find()         replace()
 | 
| 504 |                    trim()         trimStart()   trimEnd()
 | 
| 505 |                    startsWith()   endsWith()
 | 
| 506 |                    upper()        lower()
 | 
| 507 |                    search()       leftMatch()
 | 
| 508 |   [List]           List/append()  pop()         extend()    indexOf()
 | 
| 509 |                  X insert()     X remove()      reverse()
 | 
| 510 |   [Dict]           keys()         values()    X get()     X erase()
 | 
| 511 |                  X inc()        X accum()
 | 
| 512 |   [Range] 
 | 
| 513 |   [Eggex] 
 | 
| 514 |   [Match]          group()        start()       end()
 | 
| 515 |                  X groups()     X groupDict()
 | 
| 516 |   [Place]          setValue()
 | 
| 517 |   [Code Types]     Expr           Command
 | 
| 518 |                    BuiltinFunc    BoundFunc
 | 
| 519 | X [Func]           name()         location()    toJson()
 | 
| 520 | X [Proc]           name()         location()    toJson()
 | 
| 521 | X [Module]         name()         filename()
 | 
| 522 |   [IO]           X eval()       X captureStdout()
 | 
| 523 |                    promptVal()
 | 
| 524 |                  X time()       X strftime()
 | 
| 525 |                  X glob()
 | 
| 526 | X [Guts]           heapId()
 | 
| 527 | )zZXx");
 | 
| 528 | 
 | 
| 529 | GLOBAL_STR(gStr28, R"zZXx(bin/ysh is the shell with data tYpes, influenced by pYthon, JavaScript, ...
 | 
| 530 | 
 | 
| 531 | Usage: ysh FLAG* SCRIPT ARG*
 | 
| 532 |        ysh FLAG* -c COMMAND ARG*
 | 
| 533 |        ysh FLAG*
 | 
| 534 | 
 | 
| 535 | `bin/ysh` is the same as `bin/osh` with a the `ysh:all` option group set.  So
 | 
| 536 | `bin/ysh` also accepts shell flags.
 | 
| 537 | 
 | 
| 538 |     ysh -c 'echo hi'
 | 
| 539 |     ysh myscript.ysh
 | 
| 540 |     echo 'echo hi' | ysh
 | 
| 541 | )zZXx");
 | 
| 542 | 
 | 
| 543 | GLOBAL_STR(gStr29, R"zZXx(
 | 
| 544 |   Word Language <a class="group-link" href="chap-word-lang.html">word-lang</a>
 | 
| 545 | 
 | 
| 546 | 
 | 
| 547 |   [Quotes]        ysh-string    "x is $x"  $"x is $x"  r'[a-z]\n'
 | 
| 548 |                                 u'line\n'  b'byte \yff'
 | 
| 549 |                   triple-quoted """  $"""  r'''  u'''  b'''
 | 
| 550 |                 X tagged-str    "<span id=$x>"html
 | 
| 551 |   [Substitutions] expr-sub      echo $[42 + a[i]]
 | 
| 552 |                   expr-splice   echo @[split(x)]
 | 
| 553 |                   var-splice    @myarray @ARGV
 | 
| 554 |                   command-sub   @(split command)
 | 
| 555 |   [Formatting]  X ysh-printf    ${x %.3f}
 | 
| 556 |                 X ysh-format    ${x|html}
 | 
| 557 | )zZXx");
 | 
| 558 | 
 | 
| 559 | GLOBAL_STR(gStr30, R"zZXx(
 | 
| 560 |   YSH Command Language Keywords <a class="group-link" href="chap-ysh-cmd.html">ysh-cmd</a>
 | 
| 561 | 
 | 
| 562 | 
 | 
| 563 |   [Assignment]    const   var   Declare variables
 | 
| 564 |                   setvar        setvar a[i] = 42
 | 
| 565 |                   setglobal     setglobal d.key = 'foo'
 | 
| 566 |   [Expression]    equal =       = 1 + 2*3
 | 
| 567 |                   call          call mylist->append(42)
 | 
| 568 |   [Definitions]   proc          proc p (s, ...rest) {
 | 
| 569 |                                 typed proc p (; typed, ...rest; n=0; b) {
 | 
| 570 |                   func          func f(x; opt1, opt2) { return (x + 1) }
 | 
| 571 |                   ysh-return    return (myexpr)
 | 
| 572 | )zZXx");
 | 
| 573 | 
 | 
| 574 | GLOBAL_STR(gStr31, R"zZXx(# args.ysh
 | 
| 575 | #
 | 
| 576 | # Usage:
 | 
| 577 | #   source --builtin args.sh
 | 
| 578 | #
 | 
| 579 | # parser (&spec) {
 | 
| 580 | #   flag -v --verbose (help="Verbosely")  # default is Bool, false
 | 
| 581 | #
 | 
| 582 | #   flag -P --max-procs ('int', default=-1, doc='''
 | 
| 583 | #     Run at most P processes at a time
 | 
| 584 | #     ''')
 | 
| 585 | #
 | 
| 586 | #   flag -i --invert ('bool', default=true, doc='''
 | 
| 587 | #     Long multiline
 | 
| 588 | #     Description
 | 
| 589 | #     ''')
 | 
| 590 | #
 | 
| 591 | #   arg src (help='Source')
 | 
| 592 | #   arg dest (help='Dest')
 | 
| 593 | #   arg times (help='Foo')
 | 
| 594 | #
 | 
| 595 | #   rest files
 | 
| 596 | # }
 | 
| 597 | #
 | 
| 598 | # var args = parseArgs(spec, ARGV)
 | 
| 599 | #
 | 
| 600 | # echo "Verbose $[args.verbose]"
 | 
| 601 | 
 | 
| 602 | # TODO: See list
 | 
| 603 | # - It would be nice to keep `flag` and `arg` private, injecting them into the
 | 
| 604 | #   proc namespace only within `Args`
 | 
| 605 | # - We need "type object" to replace the strings 'int', 'bool', etc.
 | 
| 606 | # - flag builtin:
 | 
| 607 | #   - handle only long flag or only short flag
 | 
| 608 | #   - flag aliases
 | 
| 609 | 
 | 
| 610 | proc parser (; place ; ; block_def) {
 | 
| 611 |   ## Create an args spec which can be passed to parseArgs.
 | 
| 612 |   ##
 | 
| 613 |   ## Example:
 | 
| 614 |   ##
 | 
| 615 |   ##   # NOTE: &spec will create a variable named spec
 | 
| 616 |   ##   parser (&spec) {
 | 
| 617 |   ##     flag -v --verbose ('bool')
 | 
| 618 |   ##   }
 | 
| 619 |   ##
 | 
| 620 |   ##   var args = parseArgs(spec, ARGV)
 | 
| 621 | 
 | 
| 622 |   var p = {flags: [], args: []}
 | 
| 623 |   ctx push (p; ; block_def)
 | 
| 624 | 
 | 
| 625 |   # Validate that p.rest = [name] or null and reduce p.rest into name or null.
 | 
| 626 |   if ('rest' in p) {
 | 
| 627 |     if (len(p.rest) > 1) {
 | 
| 628 |       error '`rest` was called more than once' (code=3)
 | 
| 629 |     } else {
 | 
| 630 |       setvar p.rest = p.rest[0]
 | 
| 631 |     }
 | 
| 632 |   } else {
 | 
| 633 |     setvar p.rest = null
 | 
| 634 |   }
 | 
| 635 | 
 | 
| 636 |   var names = {}
 | 
| 637 |   for items in ([p.flags, p.args]) {
 | 
| 638 |     for x in (items) {
 | 
| 639 |       if (x.name in names) {
 | 
| 640 |         error "Duplicate flag/arg name $[x.name] in spec" (code=3)
 | 
| 641 |       }
 | 
| 642 | 
 | 
| 643 |       setvar names[x.name] = null
 | 
| 644 |     }
 | 
| 645 |   }
 | 
| 646 | 
 | 
| 647 |   # TODO: what about `flag --name` and then `arg name`?
 | 
| 648 | 
 | 
| 649 |   call place->setValue(p)
 | 
| 650 | }
 | 
| 651 | 
 | 
| 652 | proc flag (short, long ; type='bool' ; default=null, help=null) {
 | 
| 653 |   ## Declare a flag within an `arg-parse`.
 | 
| 654 |   ##
 | 
| 655 |   ## Examples:
 | 
| 656 |   ##
 | 
| 657 |   ##   arg-parse (&spec) {
 | 
| 658 |   ##     flag -v --verbose
 | 
| 659 |   ##     flag -n --count ('int', default=1)
 | 
| 660 |   ##     flag -f --file ('str', help="File to process")
 | 
| 661 |   ##   }
 | 
| 662 | 
 | 
| 663 |   # bool has a default of false, not null
 | 
| 664 |   if (type === 'bool' and default === null) {
 | 
| 665 |     setvar default = false
 | 
| 666 |   }
 | 
| 667 | 
 | 
| 668 |   # TODO: validate `type`
 | 
| 669 | 
 | 
| 670 |   # TODO: Should use "trimPrefix"
 | 
| 671 |   var name = long[2:]
 | 
| 672 | 
 | 
| 673 |   ctx emit flags ({short, long, name, type, default, help})
 | 
| 674 | }
 | 
| 675 | 
 | 
| 676 | proc arg (name ; ; help=null) {
 | 
| 677 |   ## Declare a positional argument within an `arg-parse`.
 | 
| 678 |   ##
 | 
| 679 |   ## Examples:
 | 
| 680 |   ##
 | 
| 681 |   ##   arg-parse (&spec) {
 | 
| 682 |   ##     arg name
 | 
| 683 |   ##     arg config (help="config file path")
 | 
| 684 |   ##   }
 | 
| 685 | 
 | 
| 686 |   ctx emit args ({name, help})
 | 
| 687 | }
 | 
| 688 | 
 | 
| 689 | proc rest (name) {
 | 
| 690 |   ## Take the remaining positional arguments within an `arg-parse`.
 | 
| 691 |   ##
 | 
| 692 |   ## Examples:
 | 
| 693 |   ##
 | 
| 694 |   ##   arg-parse (&grepSpec) {
 | 
| 695 |   ##     arg query
 | 
| 696 |   ##     rest files
 | 
| 697 |   ##   }
 | 
| 698 | 
 | 
| 699 |   # We emit instead of set to detect multiple invocations of "rest"
 | 
| 700 |   ctx emit rest (name)
 | 
| 701 | }
 | 
| 702 | 
 | 
| 703 | func parseArgs(spec, argv) {
 | 
| 704 |   ## Given a spec created by `parser`. Parse an array of strings `argv` per
 | 
| 705 |   ## that spec.
 | 
| 706 |   ##
 | 
| 707 |   ## See `parser` for examples of use.
 | 
| 708 | 
 | 
| 709 |   var i = 0
 | 
| 710 |   var positionalPos = 0
 | 
| 711 |   var argc = len(argv)
 | 
| 712 |   var args = {}
 | 
| 713 |   var rest = []
 | 
| 714 | 
 | 
| 715 |   var value
 | 
| 716 |   var found
 | 
| 717 |   while (i < argc) {
 | 
| 718 |     var arg = argv[i]
 | 
| 719 |     if (arg->startsWith('-')) {
 | 
| 720 |       setvar found = false
 | 
| 721 | 
 | 
| 722 |       for flag in (spec.flags) {
 | 
| 723 |         if ( (flag.short and flag.short === arg) or
 | 
| 724 |              (flag.long and flag.long === arg) ) {
 | 
| 725 |           case (flag.type) {
 | 
| 726 |             ('bool') | (null) { setvar value = true }
 | 
| 727 |             int {
 | 
| 728 |               setvar i += 1
 | 
| 729 |               if (i >= len(argv)) {
 | 
| 730 |                 error "Expected integer after '$arg'" (code=2)
 | 
| 731 |               }
 | 
| 732 | 
 | 
| 733 |               try { setvar value = int(argv[i]) }
 | 
| 734 |               if (_status !== 0) {
 | 
| 735 |                 error "Expected integer after '$arg', got '$[argv[i]]'" (code=2)
 | 
| 736 |               }
 | 
| 737 |             }
 | 
| 738 |           }
 | 
| 739 | 
 | 
| 740 |           setvar args[flag.name] = value
 | 
| 741 |           setvar found = true
 | 
| 742 |           break
 | 
| 743 |         }
 | 
| 744 |       }
 | 
| 745 | 
 | 
| 746 |       if (not found) {
 | 
| 747 |         error "Unknown flag '$arg'" (code=2)
 | 
| 748 |       }
 | 
| 749 |     } elif (positionalPos >= len(spec.args)) {
 | 
| 750 |       if (not spec.rest) {
 | 
| 751 |         error "Too many arguments, unexpected '$arg'" (code=2)
 | 
| 752 |       }
 | 
| 753 | 
 | 
| 754 |       call rest->append(arg)
 | 
| 755 |     } else {
 | 
| 756 |       var pos = spec.args[positionalPos]
 | 
| 757 |       setvar positionalPos += 1
 | 
| 758 |       setvar value = arg
 | 
| 759 |       setvar args[pos.name] = value
 | 
| 760 |     }
 | 
| 761 | 
 | 
| 762 |     setvar i += 1
 | 
| 763 |   }
 | 
| 764 | 
 | 
| 765 |   if (spec.rest) {
 | 
| 766 |     setvar args[spec.rest] = rest
 | 
| 767 |   }
 | 
| 768 | 
 | 
| 769 |   # Set defaults for flags
 | 
| 770 |   for flag in (spec.flags) {
 | 
| 771 |     if (flag.name not in args) {
 | 
| 772 |       setvar args[flag.name] = flag.default
 | 
| 773 |     }
 | 
| 774 |   }
 | 
| 775 | 
 | 
| 776 |   # Raise error on missing args
 | 
| 777 |   for arg in (spec.args) {
 | 
| 778 |     if (arg.name not in args) {
 | 
| 779 |       error "Usage Error: Missing required argument $[arg.name]" (code=2)
 | 
| 780 |     }
 | 
| 781 |   }
 | 
| 782 | 
 | 
| 783 |   return (args)
 | 
| 784 | }
 | 
| 785 | )zZXx");
 | 
| 786 | 
 | 
| 787 | GLOBAL_STR(gStr32, R"zZXx(#!/usr/bin/env ysh
 | 
| 788 | 
 | 
| 789 | module stdlib/synch || return 0
 | 
| 790 | 
 | 
| 791 | ############################
 | 
| 792 | ### FIFO File Desriptors ###
 | 
| 793 | ############################
 | 
| 794 | 
 | 
| 795 | proc fifo-fd-new(; out_fd) {
 | 
| 796 |   # WARN: this section should be critical but for now it's not
 | 
| 797 |   # A solution may be retry on fail.
 | 
| 798 |   #====================
 | 
| 799 |   var fifo = $(mktemp -u)
 | 
| 800 |   mkfifo $fifo
 | 
| 801 |   #====================
 | 
| 802 |   exec {fd}<>$fifo
 | 
| 803 |   call out_fd->setValue(fd)
 | 
| 804 | }
 | 
| 805 | 
 | 
| 806 | proc fifo-fd-destroy(; fd) {
 | 
| 807 |   var fifoFile = $(readlink /proc/$$/fd/$fd)
 | 
| 808 |   exec {fd}>&-
 | 
| 809 |   exec {fd}<&-
 | 
| 810 |   rm $fifoFile
 | 
| 811 | }
 | 
| 812 | 
 | 
| 813 | #################
 | 
| 814 | ### Semaphore ###
 | 
| 815 | #################
 | 
| 816 | 
 | 
| 817 | proc sema-new(; value, out_sema) {
 | 
| 818 |   fifo-fd-new (&sema)
 | 
| 819 |   sema-up (sema, value)
 | 
| 820 |   call out_sema->setValue(sema)
 | 
| 821 | }
 | 
| 822 | 
 | 
| 823 | proc sema-down(; sema) {
 | 
| 824 |   read <&$sema
 | 
| 825 | }
 | 
| 826 | 
 | 
| 827 | proc sema-up(; sema, delta = 1) {
 | 
| 828 |   fork {
 | 
| 829 |     for _ in (0 .. delta) {
 | 
| 830 |       echo >&$sema
 | 
| 831 |     }
 | 
| 832 |   }
 | 
| 833 | }
 | 
| 834 | 
 | 
| 835 | proc sema-destroy(; sema) {
 | 
| 836 |   fifo-fd-destroy (sema)
 | 
| 837 | }
 | 
| 838 | )zZXx");
 | 
| 839 | 
 | 
| 840 | GLOBAL_STR(gStr33, R"zZXx(func identity(x) {
 | 
| 841 |   ## The identity function. Returns its argument.
 | 
| 842 | 
 | 
| 843 |   return (x)
 | 
| 844 | }
 | 
| 845 | )zZXx");
 | 
| 846 | 
 | 
| 847 | GLOBAL_STR(gStr34, R"zZXx(func any(list) {
 | 
| 848 |   ## Returns true if any value in the list is truthy.
 | 
| 849 |   ##
 | 
| 850 |   ## If the list is empty, return false.
 | 
| 851 | 
 | 
| 852 |   for item in (list) {
 | 
| 853 |     if (item) {
 | 
| 854 |       return (true)
 | 
| 855 |     }
 | 
| 856 |   }
 | 
| 857 |   return (false)
 | 
| 858 | }
 | 
| 859 | 
 | 
| 860 | func all(list) {
 | 
| 861 |   ## Returns true if all values in the list are truthy.
 | 
| 862 |   ##
 | 
| 863 |   ## If the list is empty, return true.
 | 
| 864 | 
 | 
| 865 |   for item in (list) {
 | 
| 866 |     if (not item) {
 | 
| 867 |       return (false)
 | 
| 868 |     }
 | 
| 869 |   }
 | 
| 870 |   return (true)
 | 
| 871 | }
 | 
| 872 | 
 | 
| 873 | func sum(list; start=0) {
 | 
| 874 |   ## Computes the sum of all elements in the list.
 | 
| 875 |   ##
 | 
| 876 |   ## Returns 0 for an empty list.
 | 
| 877 | 
 | 
| 878 |   var sum = start
 | 
| 879 |   for item in (list) {
 | 
| 880 |     setvar sum += item
 | 
| 881 |   }
 | 
| 882 |   return (sum)
 | 
| 883 | }
 | 
| 884 | )zZXx");
 | 
| 885 | 
 | 
| 886 | GLOBAL_STR(gStr35, R"zZXx(func __math_select(list, cmp) {
 | 
| 887 |   ## Internal helper for `max` and `min`.
 | 
| 888 |   ##
 | 
| 889 |   ## NOTE: If `list` is empty, then an error is thrown.
 | 
| 890 | 
 | 
| 891 |   if (len(list) === 0) {
 | 
| 892 |     error "Unexpected empty list" (code=3)
 | 
| 893 |   }
 | 
| 894 | 
 | 
| 895 |   if (len(list) === 1) {
 | 
| 896 |     return (list[0])
 | 
| 897 |   }
 | 
| 898 | 
 | 
| 899 |   var match = list[0]
 | 
| 900 |   for i in (1 .. len(list)) {
 | 
| 901 |     setvar match = cmp(list[i], match)
 | 
| 902 |   }
 | 
| 903 |   return (match)
 | 
| 904 | }
 | 
| 905 | 
 | 
| 906 | func max(...args) {
 | 
| 907 |   ## Compute the maximum of 2 or more values.
 | 
| 908 |   ##
 | 
| 909 |   ## `max` takes two different signatures:
 | 
| 910 |   ##  - `max(a, b)` to return the maximum of `a`, `b`
 | 
| 911 |   ##  - `max(list)` to return the greatest item in the `list`
 | 
| 912 |   ##
 | 
| 913 |   ## So, for example:
 | 
| 914 |   ##
 | 
| 915 |   ##   max(1, 2)  # => 2
 | 
| 916 |   ##   max([1, 2, 3])  # => 3
 | 
| 917 | 
 | 
| 918 |   case (len(args)) {
 | 
| 919 |     (1) { return (__math_select(args[0], max)) }
 | 
| 920 |     (2) {
 | 
| 921 |       if (args[0] > args[1]) {
 | 
| 922 |         return (args[0])
 | 
| 923 |       } else {
 | 
| 924 |         return (args[1])
 | 
| 925 |       }
 | 
| 926 |     }
 | 
| 927 |     (else) { error "max expects 1 or 2 args" (code=3) }
 | 
| 928 |   }
 | 
| 929 | }
 | 
| 930 | 
 | 
| 931 | func min(...args) {
 | 
| 932 |   ## Compute the minimum of 2 or more values.
 | 
| 933 |   ##
 | 
| 934 |   ## `min` takes two different signatures:
 | 
| 935 |   ##  - `min(a, b)` to return the minimum of `a`, `b`
 | 
| 936 |   ##  - `min(list)` to return the least item in the `list`
 | 
| 937 |   ##
 | 
| 938 |   ## So, for example:
 | 
| 939 |   ##
 | 
| 940 |   ##   min(2, 3)  # => 2
 | 
| 941 |   ##   max([1, 2, 3])  # => 1
 | 
| 942 | 
 | 
| 943 |   case (len(args)) {
 | 
| 944 |     (1) { return (__math_select(args[0], min)) }
 | 
| 945 |     (2) {
 | 
| 946 |       if (args[0] < args[1]) {
 | 
| 947 |         return (args[0])
 | 
| 948 |       } else {
 | 
| 949 |         return (args[1])
 | 
| 950 |       }
 | 
| 951 |     }
 | 
| 952 |     (else) { error "min expects 1 or 2 args" (code=3) }
 | 
| 953 |   }
 | 
| 954 | }
 | 
| 955 | 
 | 
| 956 | func abs(x) {
 | 
| 957 |   ## Compute the absolute (positive) value of a number (float or int).
 | 
| 958 | 
 | 
| 959 |   if (x < 0) {
 | 
| 960 |     return (-x)
 | 
| 961 |   } else {
 | 
| 962 |     return (x)
 | 
| 963 |   }
 | 
| 964 | }
 | 
| 965 | )zZXx");
 | 
| 966 | 
 | 
| 967 | GLOBAL_STR(gStr36, R"zZXx(# Can we define methods in pure YSH?
 | 
| 968 | #
 | 
| 969 | # (mylist->find(42) !== -1)
 | 
| 970 | #
 | 
| 971 | #   instead of 
 | 
| 972 | #
 | 
| 973 | # ('42' in mylist)
 | 
| 974 | #
 | 
| 975 | # Because 'in' is for Dict
 | 
| 976 | 
 | 
| 977 | func find (haystack List, needle) {
 | 
| 978 |   for i, x in (haystack) {
 | 
| 979 |     if (x === needle) {
 | 
| 980 |       return (i)
 | 
| 981 |     }
 | 
| 982 |   }
 | 
| 983 |   return (-1)
 | 
| 984 | }
 | 
| 985 | )zZXx");
 | 
| 986 | 
 | 
| 987 | GLOBAL_STR(gStr37, R"zZXx(# These were helpful while implementing args.ysh
 | 
| 988 | # Maybe we will want to export them in a prelude so that others can use them too?
 | 
| 989 | #
 | 
| 990 | # Prior art: Rust has `todo!()` which is quite nice. Other languages allow
 | 
| 991 | # users to `raise NotImplmentedError()`.
 | 
| 992 | 
 | 
| 993 | # Andy comments:
 | 
| 994 | # - 'pass' can be : or true in shell.  It's a little obscure / confusing, but
 | 
| 995 | #   there is an argument for minimalism.  Although I prefer words like 'true',
 | 
| 996 | #   and that already means something.
 | 
| 997 | #   - UPDATE: we once took 'pass' as a keyword, but users complained because
 | 
| 998 | #     there is a command 'pass'.  So we probably can't have this by default.
 | 
| 999 | #     Need to discuss source --builtin.
 | 
| 1000 | 
 | 
| 1001 | # - todo could be more static?  Rust presumably does it at compile time
 | 
| 1002 | 
 | 
| 1003 | proc todo () {
 | 
| 1004 |   ## Raises a not implemented error when run.
 | 
| 1005 |   error ("TODO: not implemented")  # TODO: is error code 1 ok?
 | 
| 1006 | }
 | 
| 1007 | 
 | 
| 1008 | proc pass () {
 | 
| 1009 |   ## Use when you want to temporarily leave a block empty.
 | 
| 1010 |   _ null
 | 
| 1011 | }
 | 
| 1012 | )zZXx");
 | 
| 1013 | 
 | 
| 1014 | GLOBAL_STR(gStr38, R"zZXx(# stream.ysh
 | 
| 1015 | #
 | 
| 1016 | # Usage:
 | 
| 1017 | #   source --builtin stream.ysh
 | 
| 1018 | #
 | 
| 1019 | # For reading lines, decoding, extracting, splitting
 | 
| 1020 | 
 | 
| 1021 | # make this file a test server, bash/OSH lib is OK
 | 
| 1022 | source --builtin byo-server-lib.bash
 | 
| 1023 | 
 | 
| 1024 | source --builtin args.ysh
 | 
| 1025 | 
 | 
| 1026 | proc slurp-by (; num_lines) {
 | 
| 1027 |   # TODO: (stdin)
 | 
| 1028 |   for line in <> {
 | 
| 1029 |     echo TODO
 | 
| 1030 |   }
 | 
| 1031 | }
 | 
| 1032 | 
 | 
| 1033 | # Note:
 | 
| 1034 | # - these are all the same algorithm
 | 
| 1035 | # - also word, block, etc. are all optional
 | 
| 1036 | 
 | 
| 1037 | proc each-line (...words; template=null; ; block=null) {
 | 
| 1038 |   # TODO: 
 | 
| 1039 |   # parse --j8 --max-jobs flag
 | 
| 1040 | 
 | 
| 1041 |   # parse template_str as string
 | 
| 1042 |   # TODO: this is dangerous though ... because you can execute code
 | 
| 1043 |   # I think you need a SAFE version
 | 
| 1044 | 
 | 
| 1045 |   # evaluate template string expression - I guess that allows $(echo hi) and so
 | 
| 1046 |   # forth
 | 
| 1047 | 
 | 
| 1048 |   # evaluate block with _line binding
 | 
| 1049 |   # block: execute in parallel with --max-jobs
 | 
| 1050 | 
 | 
| 1051 |   for line in <> {
 | 
| 1052 |     echo TODO
 | 
| 1053 |   }
 | 
| 1054 | }
 | 
| 1055 | 
 | 
| 1056 | proc test-each-line {
 | 
| 1057 |   echo 'TODO: need basic test runner'
 | 
| 1058 | 
 | 
| 1059 |   # ysh-tool test stream.ysh
 | 
| 1060 |   # 
 | 
| 1061 |   # Col
 | 
| 1062 | 
 | 
| 1063 | 
 | 
| 1064 | }
 | 
| 1065 | 
 | 
| 1066 | proc each-row (; ; block) {
 | 
| 1067 |   echo TODO
 | 
| 1068 | }
 | 
| 1069 | 
 | 
| 1070 | proc split-by (; ifs=null; block) {
 | 
| 1071 |   echo TODO
 | 
| 1072 | }
 | 
| 1073 | 
 | 
| 1074 | proc if-split-by (; ifs=null; block) {
 | 
| 1075 |   echo TODO
 | 
| 1076 | }
 | 
| 1077 | 
 | 
| 1078 | proc chop () {
 | 
| 1079 |   ### alias for if-split-by
 | 
| 1080 |   echo TODO
 | 
| 1081 | }
 | 
| 1082 | 
 | 
| 1083 | proc must-match (; pattern; block) {
 | 
| 1084 |   echo TODO
 | 
| 1085 | }
 | 
| 1086 | 
 | 
| 1087 | proc if-match (; pattern; block) {
 | 
| 1088 |   echo TODO
 | 
| 1089 | }
 | 
| 1090 | 
 | 
| 1091 | # Protocol:
 | 
| 1092 | #
 | 
| 1093 | # - The file lists its tests the "actions"
 | 
| 1094 | # - Then the test harness runs them
 | 
| 1095 | # - But should it be ENV vars
 | 
| 1096 | #
 | 
| 1097 | # - BYO_LIST_TESTS=1
 | 
| 1098 | # - BYO_RUN_TEST=foo
 | 
| 1099 | # - $PWD is a CLEAN temp dir, the process doesn't have to do anything
 | 
| 1100 | 
 | 
| 1101 | #   - silent on success, but prints file on output
 | 
| 1102 | #   - OK this makes sense
 | 
| 1103 | #
 | 
| 1104 | # The trivial test in Python:
 | 
| 1105 | #   
 | 
| 1106 | # from test import byo
 | 
| 1107 | # byo.maybe_main()
 | 
| 1108 | #
 | 
| 1109 | # bash library:
 | 
| 1110 | #  source --builtin byo-server.sh
 | 
| 1111 | #
 | 
| 1112 | # byo-maybe-main   # reads env variables, and then exits
 | 
| 1113 | #
 | 
| 1114 | #  source --builtin assertions.ysh
 | 
| 1115 | #
 | 
| 1116 | # assert-ok 'echo hi'
 | 
| 1117 | # assert-stdout 'hi' 'echo -n hi'
 | 
| 1118 | #
 | 
| 1119 | # "$@"
 | 
| 1120 | #
 | 
| 1121 | # Run all tests
 | 
| 1122 | # util/byo-client.sh run-tests $YSH stdlib/table.ysh
 | 
| 1123 | # util/byo-client.sh run-tests -f x $YSH stdlib/table.ysh
 | 
| 1124 | 
 | 
| 1125 | # Clean process
 | 
| 1126 | # Clean working dir
 | 
| 1127 | 
 | 
| 1128 | #
 | 
| 1129 | # Stream Protocol:
 | 
| 1130 | #     #.byo - is this she-dot, that's for a file
 | 
| 1131 | # Do we need metadata?
 | 
| 1132 | #
 | 
| 1133 | 
 | 
| 1134 | # The harness
 | 
| 1135 | #
 | 
| 1136 | # It's process based testing.
 | 
| 1137 | #
 | 
| 1138 | # Test runner process: bash or OSH (unlike sharness!)
 | 
| 1139 | # Tested process: any language - bash, 
 | 
| 1140 | #
 | 
| 1141 | # Key point: you don't have to quote shell code?
 | 
| 1142 | 
 | 
| 1143 | list-byo-tests() {
 | 
| 1144 |   echo TODO
 | 
| 1145 | }
 | 
| 1146 | 
 | 
| 1147 | run-byo-tests() {
 | 
| 1148 |   # source it
 | 
| 1149 |   echo TODO
 | 
| 1150 | }
 | 
| 1151 | 
 | 
| 1152 | byo-maybe-main
 | 
| 1153 | )zZXx");
 | 
| 1154 | 
 | 
| 1155 | GLOBAL_STR(gStr39, R"zZXx(# table.ysh
 | 
| 1156 | #
 | 
| 1157 | # Usage:
 | 
| 1158 | #   source --builtin table.ysh
 | 
| 1159 | 
 | 
| 1160 | # make this file a test server, bash/OSH lib is OK
 | 
| 1161 | source --builtin byo-server-lib.bash
 | 
| 1162 | 
 | 
| 1163 | proc table (...words; place; ; block) {
 | 
| 1164 |   var n = len(words)
 | 
| 1165 | 
 | 
| 1166 |   # TODO: parse flags
 | 
| 1167 |   #
 | 
| 1168 |   # --by-row
 | 
| 1169 |   # --by-col
 | 
| 1170 |   #
 | 
| 1171 |   # Place is optional
 | 
| 1172 | 
 | 
| 1173 |   if (n === 0) {
 | 
| 1174 |     echo TODO
 | 
| 1175 |     return
 | 
| 1176 |   }
 | 
| 1177 | 
 | 
| 1178 |   var action = words[0]
 | 
| 1179 | 
 | 
| 1180 |   # textual operations
 | 
| 1181 |   case (action) {
 | 
| 1182 |     cat {
 | 
| 1183 |       echo todo
 | 
| 1184 |     }
 | 
| 1185 |     align {
 | 
| 1186 |       echo todo
 | 
| 1187 |     }
 | 
| 1188 |     tabify {
 | 
| 1189 |       echo todo
 | 
| 1190 |     }
 | 
| 1191 |     tabify {
 | 
| 1192 |       echo todo
 | 
| 1193 |     }
 | 
| 1194 |     header {
 | 
| 1195 |       echo todo
 | 
| 1196 |     }
 | 
| 1197 |     slice {
 | 
| 1198 |       # this has typed args
 | 
| 1199 |       # do we do some sort of splat?
 | 
| 1200 |       echo todo
 | 
| 1201 |     }
 | 
| 1202 |     to-tsv {
 | 
| 1203 |       echo todo
 | 
| 1204 |     }
 | 
| 1205 |   }
 | 
| 1206 | 
 | 
| 1207 |   echo TODO
 | 
| 1208 | }
 | 
| 1209 | 
 | 
| 1210 | proc test-table {
 | 
| 1211 |   table (&files1) {
 | 
| 1212 |     cols  num_bytes path
 | 
| 1213 |     type  Int       Str
 | 
| 1214 | 
 | 
| 1215 |     row   10        README.md
 | 
| 1216 |     row   12        main.py
 | 
| 1217 | 
 | 
| 1218 |     row   (12,      'lib.py')
 | 
| 1219 |     row   (num_bytes=12, path='util.py')
 | 
| 1220 |   }
 | 
| 1221 | 
 | 
| 1222 |   # 2 columns - The default is by column?
 | 
| 1223 |   assert ['Dict' === type(files1)]
 | 
| 1224 |   assert [2 === len(files1)]
 | 
| 1225 | 
 | 
| 1226 |   # Same table
 | 
| 1227 |   table --by-row (&files2) {
 | 
| 1228 |     cols  num_bytes path
 | 
| 1229 |     type  Int       Str
 | 
| 1230 | 
 | 
| 1231 |     row   10        README.md
 | 
| 1232 |     row   12        main.py
 | 
| 1233 | 
 | 
| 1234 |     row   (12,      'lib.py')
 | 
| 1235 |     row   (num_bytes=12, path='util.py')
 | 
| 1236 |   }
 | 
| 1237 | 
 | 
| 1238 |   # 4 rows
 | 
| 1239 |   assert ['List' === type(files2)]
 | 
| 1240 |   assert [4 === len(files2)]
 | 
| 1241 | }
 | 
| 1242 | 
 | 
| 1243 | # "subcommands" of the dialect
 | 
| 1244 | 
 | 
| 1245 | proc cols (...names) {
 | 
| 1246 |   # cols name age
 | 
| 1247 |   echo TODO
 | 
| 1248 | }
 | 
| 1249 | 
 | 
| 1250 | proc types (...types) {
 | 
| 1251 |   # types - Int? Str?
 | 
| 1252 |   echo TODO
 | 
| 1253 | }
 | 
| 1254 | 
 | 
| 1255 | proc attr (name; ...values) {
 | 
| 1256 |   # attr units ('-', 'secs')
 | 
| 1257 |   echo TODO
 | 
| 1258 | }
 | 
| 1259 | 
 | 
| 1260 | # is this allowed outside table {} blocks too?
 | 
| 1261 | proc row {
 | 
| 1262 |   echo TODO
 | 
| 1263 | }
 | 
| 1264 | 
 | 
| 1265 | #
 | 
| 1266 | # dplyr names
 | 
| 1267 | #
 | 
| 1268 | 
 | 
| 1269 | # TODO: can we parse select?
 | 
| 1270 | 
 | 
| 1271 | proc where {
 | 
| 1272 |   echo
 | 
| 1273 | }
 | 
| 1274 | 
 | 
| 1275 | # TODO: should be able to test argv[0] or something
 | 
| 1276 | # Or pass to _mutate-transmute
 | 
| 1277 | 
 | 
| 1278 | proc mutate {
 | 
| 1279 |   echo TODO
 | 
| 1280 | }
 | 
| 1281 | 
 | 
| 1282 | proc transmute {
 | 
| 1283 |   echo TODO
 | 
| 1284 | }
 | 
| 1285 | 
 | 
| 1286 | proc rename {
 | 
| 1287 |   echo TODO
 | 
| 1288 | }
 | 
| 1289 | 
 | 
| 1290 | proc group-by {
 | 
| 1291 |   echo TODO
 | 
| 1292 | }
 | 
| 1293 | 
 | 
| 1294 | proc sort-by {
 | 
| 1295 |   echo TODO
 | 
| 1296 | }
 | 
| 1297 | 
 | 
| 1298 | proc summary {
 | 
| 1299 |   echo TODO
 | 
| 1300 | }
 | 
| 1301 | 
 | 
| 1302 | byo-maybe-main
 | 
| 1303 | )zZXx");
 | 
| 1304 | 
 | 
| 1305 | GLOBAL_STR(gStr40, R"zZXx(# testing.ysh
 | 
| 1306 | #
 | 
| 1307 | # Usage:
 | 
| 1308 | #   source --builtin testing.sh
 | 
| 1309 | #
 | 
| 1310 | # func f(x) { return (x + 1) }
 | 
| 1311 | #
 | 
| 1312 | # describe foo {
 | 
| 1313 | #   assert (43 === f(42))
 | 
| 1314 | # }
 | 
| 1315 | #
 | 
| 1316 | # if is-main {
 | 
| 1317 | #   run-tests @ARGV   # --filter
 | 
| 1318 | # }
 | 
| 1319 | 
 | 
| 1320 | module stdlib/testing || return 0
 | 
| 1321 | 
 | 
| 1322 | source --builtin args.ysh
 | 
| 1323 | 
 | 
| 1324 | proc assert ( ; cond ; fail_message='default fail message') {
 | 
| 1325 |   echo 'hi from assert'
 | 
| 1326 | 
 | 
| 1327 |   = cond
 | 
| 1328 | 
 | 
| 1329 |   # I think this might be ready now?
 | 
| 1330 | 
 | 
| 1331 |   var val = evalExpr(cond) 
 | 
| 1332 | 
 | 
| 1333 |   echo
 | 
| 1334 |   echo 'value'
 | 
| 1335 |   = val
 | 
| 1336 |   pp line (val)
 | 
| 1337 | 
 | 
| 1338 |   = fail_message
 | 
| 1339 | 
 | 
| 1340 |   if (val) {
 | 
| 1341 |     echo 'OK'
 | 
| 1342 |   } else {
 | 
| 1343 |     var m = evalExpr(fail_message) 
 | 
| 1344 |     echo "FAIL - this is where we extract the string - $m"
 | 
| 1345 |   }
 | 
| 1346 | }
 | 
| 1347 | 
 | 
| 1348 | proc test-assert {
 | 
| 1349 |   var x = 42
 | 
| 1350 |   assert [42 === x]
 | 
| 1351 | }
 | 
| 1352 | 
 | 
| 1353 | proc test-expr ( ; expr ) {
 | 
| 1354 |   echo 'expr'
 | 
| 1355 |   pp line (expr)
 | 
| 1356 | }
 | 
| 1357 | 
 | 
| 1358 | proc test-named ( ; ; n=^[99] ) {
 | 
| 1359 |   echo 'n'
 | 
| 1360 |   pp line (n)
 | 
| 1361 | }
 | 
| 1362 | 
 | 
| 1363 | # What happens when there are duplicate test IDs?
 | 
| 1364 | #
 | 
| 1365 | # Also I think filter by "$test_id/$case_id"
 | 
| 1366 | 
 | 
| 1367 | proc __it (case_id ; ; ; block) {
 | 
| 1368 |   # This uses a clean directory
 | 
| 1369 |   echo TODO
 | 
| 1370 | }
 | 
| 1371 | 
 | 
| 1372 | # is this accessible to users?
 | 
| 1373 | # It can contain a global list of things to run
 | 
| 1374 | 
 | 
| 1375 | # Naming convention: a proc named 'describe' mutates a global named _describe?
 | 
| 1376 | # Or maybe _describe_list ?
 | 
| 1377 | 
 | 
| 1378 | var _describe_list = []
 | 
| 1379 | 
 | 
| 1380 | proc describe (test_id ; ; ; block) {
 | 
| 1381 |   echo describe
 | 
| 1382 |   #= desc
 | 
| 1383 | 
 | 
| 1384 |   # TODO:
 | 
| 1385 |   # - need append
 | 
| 1386 |   # - need ::
 | 
| 1387 |   # _ _describe->append(cmd)
 | 
| 1388 |   #
 | 
| 1389 |   # Need to clean this up
 | 
| 1390 |   # append (_describe, cmd)  # does NOT work!
 | 
| 1391 | 
 | 
| 1392 |   call _describe_list->append(block)
 | 
| 1393 | }
 | 
| 1394 | 
 | 
| 1395 | proc Args {
 | 
| 1396 |   echo TODO
 | 
| 1397 | }
 | 
| 1398 | 
 | 
| 1399 | # Problem: this creates a global variable?
 | 
| 1400 | Args (&spec) {
 | 
| 1401 |   flag --filter 'Regex of test descriptions'
 | 
| 1402 | }
 | 
| 1403 | 
 | 
| 1404 | proc run-tests {
 | 
| 1405 |   var opt, i = parseArgs(spec, ARGV)
 | 
| 1406 | 
 | 
| 1407 |   # TODO:
 | 
| 1408 |   # - parse --filter foo, which you can use eggex for!
 | 
| 1409 | 
 | 
| 1410 |   for cmd in (_describe) {
 | 
| 1411 |     # TODO: print filename and 'describe' name?
 | 
| 1412 |     try {
 | 
| 1413 |       eval (cmd)
 | 
| 1414 |     }
 | 
| 1415 |     if (_status !== 0) {
 | 
| 1416 |       echo 'failed'
 | 
| 1417 |     }
 | 
| 1418 |   }
 | 
| 1419 | }
 | 
| 1420 | )zZXx");
 | 
| 1421 | 
 | 
| 1422 | 
 | 
| 1423 | 
 | 
| 1424 | TextFile array[] = {
 | 
| 1425 |     {.rel_path = "_devbuild/help/data-errors", .contents = gStr0},
 | 
| 1426 |     {.rel_path = "_devbuild/help/data-front-end", .contents = gStr1},
 | 
| 1427 |     {.rel_path = "_devbuild/help/data-j8-notation", .contents = gStr2},
 | 
| 1428 |     {.rel_path = "_devbuild/help/help", .contents = gStr3},
 | 
| 1429 |     {.rel_path = "_devbuild/help/oils-usage", .contents = gStr4},
 | 
| 1430 |     {.rel_path = "_devbuild/help/osh-builtin-cmd", .contents = gStr5},
 | 
| 1431 |     {.rel_path = "_devbuild/help/osh-chapters", .contents = gStr6},
 | 
| 1432 |     {.rel_path = "_devbuild/help/osh-cmd-lang", .contents = gStr7},
 | 
| 1433 |     {.rel_path = "_devbuild/help/osh-front-end", .contents = gStr8},
 | 
| 1434 |     {.rel_path = "_devbuild/help/osh-mini-lang", .contents = gStr9},
 | 
| 1435 |     {.rel_path = "_devbuild/help/osh-option", .contents = gStr10},
 | 
| 1436 |     {.rel_path = "_devbuild/help/osh-osh-assign", .contents = gStr11},
 | 
| 1437 |     {.rel_path = "_devbuild/help/osh-plugin", .contents = gStr12},
 | 
| 1438 |     {.rel_path = "_devbuild/help/osh-special-var", .contents = gStr13},
 | 
| 1439 |     {.rel_path = "_devbuild/help/osh-type-method", .contents = gStr14},
 | 
| 1440 |     {.rel_path = "_devbuild/help/osh-usage", .contents = gStr15},
 | 
| 1441 |     {.rel_path = "_devbuild/help/osh-word-lang", .contents = gStr16},
 | 
| 1442 |     {.rel_path = "_devbuild/help/ysh-builtin-cmd", .contents = gStr17},
 | 
| 1443 |     {.rel_path = "_devbuild/help/ysh-builtin-func", .contents = gStr18},
 | 
| 1444 |     {.rel_path = "_devbuild/help/ysh-chapters", .contents = gStr19},
 | 
| 1445 |     {.rel_path = "_devbuild/help/ysh-cmd-lang", .contents = gStr20},
 | 
| 1446 |     {.rel_path = "_devbuild/help/ysh-expr-lang", .contents = gStr21},
 | 
| 1447 |     {.rel_path = "_devbuild/help/ysh-front-end", .contents = gStr22},
 | 
| 1448 |     {.rel_path = "_devbuild/help/ysh-mini-lang", .contents = gStr23},
 | 
| 1449 |     {.rel_path = "_devbuild/help/ysh-option", .contents = gStr24},
 | 
| 1450 |     {.rel_path = "_devbuild/help/ysh-plugin", .contents = gStr25},
 | 
| 1451 |     {.rel_path = "_devbuild/help/ysh-special-var", .contents = gStr26},
 | 
| 1452 |     {.rel_path = "_devbuild/help/ysh-type-method", .contents = gStr27},
 | 
| 1453 |     {.rel_path = "_devbuild/help/ysh-usage", .contents = gStr28},
 | 
| 1454 |     {.rel_path = "_devbuild/help/ysh-word-lang", .contents = gStr29},
 | 
| 1455 |     {.rel_path = "_devbuild/help/ysh-ysh-cmd", .contents = gStr30},
 | 
| 1456 |     {.rel_path = "stdlib/args.ysh", .contents = gStr31},
 | 
| 1457 |     {.rel_path = "stdlib/draft-synch.ysh", .contents = gStr32},
 | 
| 1458 |     {.rel_path = "stdlib/funcs.ysh", .contents = gStr33},
 | 
| 1459 |     {.rel_path = "stdlib/list.ysh", .contents = gStr34},
 | 
| 1460 |     {.rel_path = "stdlib/math.ysh", .contents = gStr35},
 | 
| 1461 |     {.rel_path = "stdlib/methods.ysh", .contents = gStr36},
 | 
| 1462 |     {.rel_path = "stdlib/prelude.ysh", .contents = gStr37},
 | 
| 1463 |     {.rel_path = "stdlib/stream.ysh", .contents = gStr38},
 | 
| 1464 |     {.rel_path = "stdlib/table.ysh", .contents = gStr39},
 | 
| 1465 |     {.rel_path = "stdlib/testing.ysh", .contents = gStr40},
 | 
| 1466 | 
 | 
| 1467 |     {.rel_path = nullptr, .contents = nullptr},
 | 
| 1468 | };
 | 
| 1469 | 
 | 
| 1470 | }  // namespace embedded_file
 | 
| 1471 | 
 | 
| 1472 | TextFile* gEmbeddedFiles = embedded_file::array;  // turn array into pointer
 |