| 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      [[ -z '' ]]
 | 
| 157 |                   bool-other    [[ -o errexit ]]
 | 
| 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
 | 
| 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 [TSV8]          rows                   pick rows; dplyr filter()
 | 
| 307 |                   cols                   pick columns ('select' already taken)
 | 
| 308 |                   group-by               add a column with a group ID [ext]
 | 
| 309 |                   sort-by                sort by columns; dplyr arrange() [ext]
 | 
| 310 |                   summary                count, sum, histogram, etc. [ext]
 | 
| 311 |   [Args Parser]   parser                 Parse command line arguments
 | 
| 312 |                   flag
 | 
| 313 |                   arg
 | 
| 314 |                   rest
 | 
| 315 |                   parseArgs()
 | 
| 316 | X [Testing]       describe               Test harness
 | 
| 317 |                   assert                 takes an expression
 | 
| 318 | )zZXx");
 | 
| 319 | 
 | 
| 320 | GLOBAL_STR(gStr18, R"zZXx(
 | 
| 321 |   Builtin Functions <a class="group-link" href="chap-builtin-func.html">builtin-func</a>
 | 
| 322 | 
 | 
| 323 | 
 | 
| 324 |   [Values]        len()        func/type()   X repeat()
 | 
| 325 |   [Conversions]   bool()       int()           float()   str()   list()   dict()
 | 
| 326 |                 X runes()    X encodeRunes()
 | 
| 327 |                 X bytes()    X encodeBytes()
 | 
| 328 |   [Str]         X strcmp()   X split()         shSplit()
 | 
| 329 |   [List]          join()       any()           all()
 | 
| 330 |   [Collections] X copy()     X deepCopy()
 | 
| 331 |   [Word]          glob()       maybe()
 | 
| 332 |   [Math]          abs()        max()           min()   X round()   sum()
 | 
| 333 |   [Serialize]     toJson()     fromJson()
 | 
| 334 |                   toJson8()    fromJson8()
 | 
| 335 | X [J8 Decode]     J8.Bool()    J8.Int()        ...
 | 
| 336 |   [Pattern]       _group()     _start()        _end()
 | 
| 337 |   [Introspection] shvarGet()   getVar()        evalExpr()
 | 
| 338 |   [Hay Config]    parseHay()   evalHay()
 | 
| 339 | X [Hashing]       sha1dc()     sha256()
 | 
| 340 | )zZXx");
 | 
| 341 | 
 | 
| 342 | GLOBAL_STR(gStr19, R"zZXx(The reference is divided in to "chapters", each of which has its own table of
 | 
| 343 | contents.  Type:
 | 
| 344 | 
 | 
| 345 |     help ysh-$CHAPTER
 | 
| 346 | 
 | 
| 347 | Where $CHAPTER is one of:
 | 
| 348 | 
 | 
| 349 |     front-end
 | 
| 350 |     command-lang
 | 
| 351 |     expr-lang
 | 
| 352 |     word-lang
 | 
| 353 |     builtin-cmd
 | 
| 354 |     option
 | 
| 355 |     special-var
 | 
| 356 |     type-method
 | 
| 357 |     builtin-func
 | 
| 358 | 
 | 
| 359 | Example:
 | 
| 360 | 
 | 
| 361 |     help ysh-expr-lang
 | 
| 362 | )zZXx");
 | 
| 363 | 
 | 
| 364 | GLOBAL_STR(gStr20, R"zZXx(
 | 
| 365 |   Command Language <a class="group-link" href="chap-cmd-lang.html">cmd-lang</a>
 | 
| 366 | 
 | 
| 367 | 
 | 
| 368 |   [YSH Simple]    typed-arg     json write (x)
 | 
| 369 |                   lazy-expr-arg assert [42 === x]
 | 
| 370 |                   block-arg     cd /tmp { echo $PWD }; cd /tmp (; ; blockexpr)
 | 
| 371 |   [YSH Cond]      ysh-case      case (x) { *.py { echo 'python' } }
 | 
| 372 |                   ysh-if        if (x > 0) { echo }
 | 
| 373 |   [YSH Iter]      ysh-while     while (x > 0) { echo }
 | 
| 374 |                   ysh-for       for i, item in (mylist) { echo }
 | 
| 375 | )zZXx");
 | 
| 376 | 
 | 
| 377 | GLOBAL_STR(gStr21, R"zZXx(
 | 
| 378 |   Expression Language and Assignments <a class="group-link" href="chap-expr-lang.html">expr-lang</a>
 | 
| 379 | 
 | 
| 380 | 
 | 
| 381 |   [Assignment]    assign        =
 | 
| 382 |                   aug-assign    +=   -=   *=   /=   **=   //=   %=
 | 
| 383 |                                 &=   |=   ^=   <<=   >>=
 | 
| 384 |   [Literals]      atom-literal  true   false   null
 | 
| 385 |                   int-literal   42  65_536  0xFF  0o755  0b10
 | 
| 386 |                   float-lit     3.14  1.5e-10
 | 
| 387 |                 X num-suffix    42 K Ki M Mi G Gi T Ti / ms us
 | 
| 388 |                   ysh-string    "x is $x"  $"x is $x"   r'[a-z]\n'
 | 
| 389 |                                 u'line\n'  b'byte \yff'
 | 
| 390 |                   triple-quoted """  $"""  r'''  u'''  b'''
 | 
| 391 |                   str-template  ^"$a and $b" for Str::replace()
 | 
| 392 |                   list-literal  ['one', 'two', 3]  :| unquoted words |
 | 
| 393 |                   dict-literal  {name: 'bob'}  {a, b}
 | 
| 394 |                   range         1 .. n+1
 | 
| 395 |                   block-expr    ^(echo $PWD)
 | 
| 396 |                   expr-literal  ^[1 + 2*3]
 | 
| 397 |                 X expr-sub      $[myobj]
 | 
| 398 |                 X expr-splice   @[myobj]
 | 
| 399 |   [Operators]     op-precedence Like Python
 | 
| 400 |                   concat        s1 ++ s2,  L1 ++ L2
 | 
| 401 |                   ysh-equals    ===   !==   ~==   is, is not
 | 
| 402 |                   ysh-in        in, not in
 | 
| 403 |                   ysh-compare   <  <=  >  >=  (numbers only)
 | 
| 404 |                   ysh-logical   not  and  or
 | 
| 405 |                   ysh-arith     +  -  *  /  //  %   ** 
 | 
| 406 |                   ysh-bitwise   ~  &  |  ^  <<  >>
 | 
| 407 |                   ysh-ternary   '+' if x >= 0 else '-'
 | 
| 408 |                   ysh-index     s[0]  mylist[3]  mydict['key']
 | 
| 409 |                   ysh-attr      mydict.key
 | 
| 410 |                   ysh-slice     a[1:-1]  s[1:-1]
 | 
| 411 |                   func-call     f(x, y; ...named)
 | 
| 412 |                   thin-arrow    mylist->pop()
 | 
| 413 |                   fat-arrow     mystr => startsWith('prefix')
 | 
| 414 |                   match-ops     ~   !~   ~~   !~~
 | 
| 415 |   [Eggex]         re-literal    / d+ ; re-flags ; ERE /
 | 
| 416 |                   re-primitive  %zero    'sq'
 | 
| 417 |                   class-literal [c a-z 'abc' @str_var \\ \xFF \u0100]
 | 
| 418 |                   named-class    dot   digit   space   word   d  s  w
 | 
| 419 |                   re-repeat     d?   d*   d+   d{3}   d{2,4}
 | 
| 420 |                   re-compound    seq1 seq2   alt1|alt2   (expr1 expr2)
 | 
| 421 |                   re-capture    <capture d+ as name: int>
 | 
| 422 |                   re-splice     Subpattern   @subpattern
 | 
| 423 |                   re-flags      reg_icase   reg_newline
 | 
| 424 |                 X re-multiline  ///
 | 
| 425 | )zZXx");
 | 
| 426 | 
 | 
| 427 | GLOBAL_STR(gStr22, R"zZXx(
 | 
| 428 |   Front End <a class="group-link" href="chap-front-end.html">front-end</a>
 | 
| 429 | 
 | 
| 430 | 
 | 
| 431 |   [Usage]         oils-usage                   ysh-usage
 | 
| 432 |   [Lexing]        ascii-whitespace [ \t\r\n]
 | 
| 433 |                   doc-comment ###              multiline-command ...
 | 
| 434 |   [Tools]         cat-em
 | 
| 435 | )zZXx");
 | 
| 436 | 
 | 
| 437 | GLOBAL_STR(gStr23, R"zZXx(
 | 
| 438 |   Other Mini Languages <a class="group-link" href="chap-mini-lang.html">mini-lang</a>
 | 
| 439 | 
 | 
| 440 | 
 | 
| 441 |   [Patterns]      glob-pat      *.py
 | 
| 442 |   [Other Sublang] braces        {alice,bob}@example.com
 | 
| 443 | )zZXx");
 | 
| 444 | 
 | 
| 445 | GLOBAL_STR(gStr24, R"zZXx(
 | 
| 446 |   Global Shell Options <a class="group-link" href="chap-option.html">option</a>
 | 
| 447 | 
 | 
| 448 | 
 | 
| 449 |   [Groups]       strict:all      ysh:upgrade     ysh:all
 | 
| 450 |   [YSH Details]  opts-redefine   opts-internal
 | 
| 451 | )zZXx");
 | 
| 452 | 
 | 
| 453 | GLOBAL_STR(gStr25, R"zZXx(
 | 
| 454 |   Plugins and Hooks <a class="group-link" href="chap-plugin.html">plugin</a>
 | 
| 455 | 
 | 
| 456 | 
 | 
| 457 |   [YSH]   renderPrompt()
 | 
| 458 | )zZXx");
 | 
| 459 | 
 | 
| 460 | GLOBAL_STR(gStr26, R"zZXx(
 | 
| 461 |   Special Variables <a class="group-link" href="chap-special-var.html">special-var</a>
 | 
| 462 | 
 | 
| 463 | 
 | 
| 464 |   [YSH Vars]      ARGV              X ENV                 X _ESCAPE
 | 
| 465 |                   _this_dir
 | 
| 466 |   [YSH Status]    _error
 | 
| 467 |                   _pipeline_status    _process_sub_status
 | 
| 468 |   [YSH Tracing]   SHX_indent          SHX_punct             SHX_pid_str
 | 
| 469 |   [YSH read]      _reply
 | 
| 470 |   [History]       YSH_HISTFILE
 | 
| 471 |   [Oils VM]       OILS_VERSION
 | 
| 472 |                   OILS_GC_THRESHOLD   OILS_GC_ON_EXIT
 | 
| 473 |                   OILS_GC_STATS       OILS_GC_STATS_FD
 | 
| 474 | )zZXx");
 | 
| 475 | 
 | 
| 476 | GLOBAL_STR(gStr27, R"zZXx(
 | 
| 477 |   Types and Methods <a class="group-link" href="chap-type-method.html">type-method</a>
 | 
| 478 | 
 | 
| 479 | 
 | 
| 480 |   [Atom Types]     Null           Bool
 | 
| 481 |   [Number Types]   Int            Float
 | 
| 482 |   [Str]          X find()         replace()
 | 
| 483 |                    trim()         trimStart()   trimEnd()
 | 
| 484 |                    startsWith()   endsWith()
 | 
| 485 |                    upper()        lower()
 | 
| 486 |                    search()       leftMatch()
 | 
| 487 |   [List]           List/append()  pop()         extend()    indexOf()
 | 
| 488 |                  X insert()     X remove()      reverse()
 | 
| 489 |   [Dict]           keys()         values()    X get()     X erase()
 | 
| 490 |                  X inc()        X accum()
 | 
| 491 |   [Range] 
 | 
| 492 |   [Eggex] 
 | 
| 493 |   [Match]          group()        start()       end()
 | 
| 494 |                  X groups()     X groupDict()
 | 
| 495 |   [Place]          setValue()
 | 
| 496 |   [Code Types]     Expr           Command
 | 
| 497 |                    BuiltinFunc    BoundFunc
 | 
| 498 | X [Func]           name()         location()    toJson()
 | 
| 499 | X [Proc]           name()         location()    toJson()
 | 
| 500 | X [Module]         name()         filename()
 | 
| 501 |   [IO]           X eval()       X captureStdout()
 | 
| 502 |                    promptVal()
 | 
| 503 |                  X time()       X strftime()
 | 
| 504 |                  X glob()
 | 
| 505 | X [Guts]           heapId()
 | 
| 506 | )zZXx");
 | 
| 507 | 
 | 
| 508 | GLOBAL_STR(gStr28, R"zZXx(bin/ysh is the shell with data tYpes, influenced by pYthon, JavaScript, ...
 | 
| 509 | 
 | 
| 510 | Usage: ysh FLAG* SCRIPT ARG*
 | 
| 511 |        ysh FLAG* -c COMMAND ARG*
 | 
| 512 |        ysh FLAG*
 | 
| 513 | 
 | 
| 514 | `bin/ysh` is the same as `bin/osh` with a the `ysh:all` option group set.  So
 | 
| 515 | `bin/ysh` also accepts shell flags.
 | 
| 516 | 
 | 
| 517 |     ysh -c 'echo hi'
 | 
| 518 |     ysh myscript.ysh
 | 
| 519 |     echo 'echo hi' | ysh
 | 
| 520 | )zZXx");
 | 
| 521 | 
 | 
| 522 | GLOBAL_STR(gStr29, R"zZXx(
 | 
| 523 |   Word Language <a class="group-link" href="chap-word-lang.html">word-lang</a>
 | 
| 524 | 
 | 
| 525 | 
 | 
| 526 |   [Quotes]        ysh-string    "x is $x"  $"x is $x"  r'[a-z]\n'
 | 
| 527 |                                 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 | 
 | 
| 538 | GLOBAL_STR(gStr30, R"zZXx(
 | 
| 539 |   YSH Command Language Keywords <a class="group-link" href="chap-ysh-cmd.html">ysh-cmd</a>
 | 
| 540 | 
 | 
| 541 | 
 | 
| 542 |   [Assignment]    const   var   Declare variables
 | 
| 543 |                   setvar        setvar a[i] = 42
 | 
| 544 |                   setglobal     setglobal d.key = 'foo'
 | 
| 545 |   [Expression]    equal =       = 1 + 2*3
 | 
| 546 |                   call          call mylist->append(42)
 | 
| 547 |   [Definitions]   proc          proc p (s, ...rest) {
 | 
| 548 |                                 typed proc p (; typed, ...rest; n=0; b) {
 | 
| 549 |                   func          func f(x; opt1, opt2) { return (x + 1) }
 | 
| 550 |                   ysh-return    return (myexpr)
 | 
| 551 | )zZXx");
 | 
| 552 | 
 | 
| 553 | GLOBAL_STR(gStr31, R"zZXx(# args.ysh
 | 
| 554 | #
 | 
| 555 | # Usage:
 | 
| 556 | #   source --builtin args.sh
 | 
| 557 | #
 | 
| 558 | # parser (&spec) {
 | 
| 559 | #   flag -v --verbose (help="Verbosely")  # default is Bool, false
 | 
| 560 | #
 | 
| 561 | #   flag -P --max-procs ('int', default=-1, doc='''
 | 
| 562 | #     Run at most P processes at a time
 | 
| 563 | #     ''')
 | 
| 564 | #
 | 
| 565 | #   flag -i --invert ('bool', default=true, doc='''
 | 
| 566 | #     Long multiline
 | 
| 567 | #     Description
 | 
| 568 | #     ''')
 | 
| 569 | #
 | 
| 570 | #   arg src (help='Source')
 | 
| 571 | #   arg dest (help='Dest')
 | 
| 572 | #   arg times (help='Foo')
 | 
| 573 | #
 | 
| 574 | #   rest files
 | 
| 575 | # }
 | 
| 576 | #
 | 
| 577 | # var args = parseArgs(spec, ARGV)
 | 
| 578 | #
 | 
| 579 | # echo "Verbose $[args.verbose]"
 | 
| 580 | 
 | 
| 581 | # TODO: See list
 | 
| 582 | # - It would be nice to keep `flag` and `arg` private, injecting them into the
 | 
| 583 | #   proc namespace only within `Args`
 | 
| 584 | # - We need "type object" to replace the strings 'int', 'bool', etc.
 | 
| 585 | # - flag builtin:
 | 
| 586 | #   - handle only long flag or only short flag
 | 
| 587 | #   - flag aliases
 | 
| 588 | 
 | 
| 589 | proc parser (; place ; ; block_def) {
 | 
| 590 |   ## Create an args spec which can be passed to parseArgs.
 | 
| 591 |   ##
 | 
| 592 |   ## Example:
 | 
| 593 |   ##
 | 
| 594 |   ##   # NOTE: &spec will create a variable named spec
 | 
| 595 |   ##   parser (&spec) {
 | 
| 596 |   ##     flag -v --verbose ('bool')
 | 
| 597 |   ##   }
 | 
| 598 |   ##
 | 
| 599 |   ##   var args = parseArgs(spec, ARGV)
 | 
| 600 | 
 | 
| 601 |   var p = {flags: [], args: []}
 | 
| 602 |   ctx push (p; ; block_def)
 | 
| 603 | 
 | 
| 604 |   # Validate that p.rest = [name] or null and reduce p.rest into name or null.
 | 
| 605 |   if ('rest' in p) {
 | 
| 606 |     if (len(p.rest) > 1) {
 | 
| 607 |       error '`rest` was called more than once' (code=3)
 | 
| 608 |     } else {
 | 
| 609 |       setvar p.rest = p.rest[0]
 | 
| 610 |     }
 | 
| 611 |   } else {
 | 
| 612 |     setvar p.rest = null
 | 
| 613 |   }
 | 
| 614 | 
 | 
| 615 |   var names = {}
 | 
| 616 |   for items in ([p.flags, p.args]) {
 | 
| 617 |     for x in (items) {
 | 
| 618 |       if (x.name in names) {
 | 
| 619 |         error "Duplicate flag/arg name $[x.name] in spec" (code=3)
 | 
| 620 |       }
 | 
| 621 | 
 | 
| 622 |       setvar names[x.name] = null
 | 
| 623 |     }
 | 
| 624 |   }
 | 
| 625 | 
 | 
| 626 |   # TODO: what about `flag --name` and then `arg name`?
 | 
| 627 | 
 | 
| 628 |   call place->setValue(p)
 | 
| 629 | }
 | 
| 630 | 
 | 
| 631 | proc flag (short, long ; type='bool' ; default=null, help=null) {
 | 
| 632 |   ## Declare a flag within an `arg-parse`.
 | 
| 633 |   ##
 | 
| 634 |   ## Examples:
 | 
| 635 |   ##
 | 
| 636 |   ##   arg-parse (&spec) {
 | 
| 637 |   ##     flag -v --verbose
 | 
| 638 |   ##     flag -n --count ('int', default=1)
 | 
| 639 |   ##     flag -f --file ('str', help="File to process")
 | 
| 640 |   ##   }
 | 
| 641 | 
 | 
| 642 |   # bool has a default of false, not null
 | 
| 643 |   if (type === 'bool' and default === null) {
 | 
| 644 |     setvar default = false
 | 
| 645 |   }
 | 
| 646 | 
 | 
| 647 |   # TODO: validate `type`
 | 
| 648 | 
 | 
| 649 |   # TODO: Should use "trimPrefix"
 | 
| 650 |   var name = long[2:]
 | 
| 651 | 
 | 
| 652 |   ctx emit flags ({short, long, name, type, default, help})
 | 
| 653 | }
 | 
| 654 | 
 | 
| 655 | proc arg (name ; ; help=null) {
 | 
| 656 |   ## Declare a positional argument within an `arg-parse`.
 | 
| 657 |   ##
 | 
| 658 |   ## Examples:
 | 
| 659 |   ##
 | 
| 660 |   ##   arg-parse (&spec) {
 | 
| 661 |   ##     arg name
 | 
| 662 |   ##     arg config (help="config file path")
 | 
| 663 |   ##   }
 | 
| 664 | 
 | 
| 665 |   ctx emit args ({name, help})
 | 
| 666 | }
 | 
| 667 | 
 | 
| 668 | proc rest (name) {
 | 
| 669 |   ## Take the remaining positional arguments within an `arg-parse`.
 | 
| 670 |   ##
 | 
| 671 |   ## Examples:
 | 
| 672 |   ##
 | 
| 673 |   ##   arg-parse (&grepSpec) {
 | 
| 674 |   ##     arg query
 | 
| 675 |   ##     rest files
 | 
| 676 |   ##   }
 | 
| 677 | 
 | 
| 678 |   # We emit instead of set to detect multiple invocations of "rest"
 | 
| 679 |   ctx emit rest (name)
 | 
| 680 | }
 | 
| 681 | 
 | 
| 682 | func parseArgs(spec, argv) {
 | 
| 683 |   ## Given a spec created by `parser`. Parse an array of strings `argv` per
 | 
| 684 |   ## that spec.
 | 
| 685 |   ##
 | 
| 686 |   ## See `parser` for examples of use.
 | 
| 687 | 
 | 
| 688 |   var i = 0
 | 
| 689 |   var positionalPos = 0
 | 
| 690 |   var argc = len(argv)
 | 
| 691 |   var args = {}
 | 
| 692 |   var rest = []
 | 
| 693 | 
 | 
| 694 |   var value
 | 
| 695 |   var found
 | 
| 696 |   while (i < argc) {
 | 
| 697 |     var arg = argv[i]
 | 
| 698 |     if (arg->startsWith('-')) {
 | 
| 699 |       setvar found = false
 | 
| 700 | 
 | 
| 701 |       for flag in (spec.flags) {
 | 
| 702 |         if ( (flag.short and flag.short === arg) or
 | 
| 703 |              (flag.long and flag.long === arg) ) {
 | 
| 704 |           case (flag.type) {
 | 
| 705 |             ('bool') | (null) { setvar value = true }
 | 
| 706 |             int {
 | 
| 707 |               setvar i += 1
 | 
| 708 |               if (i >= len(argv)) {
 | 
| 709 |                 error "Expected integer after '$arg'" (code=2)
 | 
| 710 |               }
 | 
| 711 | 
 | 
| 712 |               try { setvar value = int(argv[i]) }
 | 
| 713 |               if (_status !== 0) {
 | 
| 714 |                 error "Expected integer after '$arg', got '$[argv[i]]'" (code=2)
 | 
| 715 |               }
 | 
| 716 |             }
 | 
| 717 |           }
 | 
| 718 | 
 | 
| 719 |           setvar args[flag.name] = value
 | 
| 720 |           setvar found = true
 | 
| 721 |           break
 | 
| 722 |         }
 | 
| 723 |       }
 | 
| 724 | 
 | 
| 725 |       if (not found) {
 | 
| 726 |         error "Unknown flag '$arg'" (code=2)
 | 
| 727 |       }
 | 
| 728 |     } elif (positionalPos >= len(spec.args)) {
 | 
| 729 |       if (not spec.rest) {
 | 
| 730 |         error "Too many arguments, unexpected '$arg'" (code=2)
 | 
| 731 |       }
 | 
| 732 | 
 | 
| 733 |       call rest->append(arg)
 | 
| 734 |     } else {
 | 
| 735 |       var pos = spec.args[positionalPos]
 | 
| 736 |       setvar positionalPos += 1
 | 
| 737 |       setvar value = arg
 | 
| 738 |       setvar args[pos.name] = value
 | 
| 739 |     }
 | 
| 740 | 
 | 
| 741 |     setvar i += 1
 | 
| 742 |   }
 | 
| 743 | 
 | 
| 744 |   if (spec.rest) {
 | 
| 745 |     setvar args[spec.rest] = rest
 | 
| 746 |   }
 | 
| 747 | 
 | 
| 748 |   # Set defaults for flags
 | 
| 749 |   for flag in (spec.flags) {
 | 
| 750 |     if (flag.name not in args) {
 | 
| 751 |       setvar args[flag.name] = flag.default
 | 
| 752 |     }
 | 
| 753 |   }
 | 
| 754 | 
 | 
| 755 |   # Raise error on missing args
 | 
| 756 |   for arg in (spec.args) {
 | 
| 757 |     if (arg.name not in args) {
 | 
| 758 |       error "Usage Error: Missing required argument $[arg.name]" (code=2)
 | 
| 759 |     }
 | 
| 760 |   }
 | 
| 761 | 
 | 
| 762 |   return (args)
 | 
| 763 | }
 | 
| 764 | )zZXx");
 | 
| 765 | 
 | 
| 766 | GLOBAL_STR(gStr32, R"zZXx(#!/usr/bin/env ysh
 | 
| 767 | 
 | 
| 768 | module stdlib/synch || return 0
 | 
| 769 | 
 | 
| 770 | ############################
 | 
| 771 | ### FIFO File Desriptors ###
 | 
| 772 | ############################
 | 
| 773 | 
 | 
| 774 | proc fifo-fd-new(; out_fd) {
 | 
| 775 |   # WARN: this section should be critical but for now it's not
 | 
| 776 |   # A solution may be retry on fail.
 | 
| 777 |   #====================
 | 
| 778 |   var fifo = $(mktemp -u)
 | 
| 779 |   mkfifo $fifo
 | 
| 780 |   #====================
 | 
| 781 |   exec {fd}<>$fifo
 | 
| 782 |   call out_fd->setValue(fd)
 | 
| 783 | }
 | 
| 784 | 
 | 
| 785 | proc fifo-fd-destroy(; fd) {
 | 
| 786 |   var fifoFile = $(readlink /proc/$$/fd/$fd)
 | 
| 787 |   exec {fd}>&-
 | 
| 788 |   exec {fd}<&-
 | 
| 789 |   rm $fifoFile
 | 
| 790 | }
 | 
| 791 | 
 | 
| 792 | #################
 | 
| 793 | ### Semaphore ###
 | 
| 794 | #################
 | 
| 795 | 
 | 
| 796 | proc sema-new(; value, out_sema) {
 | 
| 797 |   fifo-fd-new (&sema)
 | 
| 798 |   sema-up (sema, value)
 | 
| 799 |   call out_sema->setValue(sema)
 | 
| 800 | }
 | 
| 801 | 
 | 
| 802 | proc sema-down(; sema) {
 | 
| 803 |   read <&$sema
 | 
| 804 | }
 | 
| 805 | 
 | 
| 806 | proc sema-up(; sema, delta = 1) {
 | 
| 807 |   fork {
 | 
| 808 |     for _ in (0 .. delta) {
 | 
| 809 |       echo >&$sema
 | 
| 810 |     }
 | 
| 811 |   }
 | 
| 812 | }
 | 
| 813 | 
 | 
| 814 | proc sema-destroy(; sema) {
 | 
| 815 |   fifo-fd-destroy (sema)
 | 
| 816 | }
 | 
| 817 | )zZXx");
 | 
| 818 | 
 | 
| 819 | GLOBAL_STR(gStr33, R"zZXx(func identity(x) {
 | 
| 820 |   ## The identity function. Returns its argument.
 | 
| 821 | 
 | 
| 822 |   return (x)
 | 
| 823 | }
 | 
| 824 | )zZXx");
 | 
| 825 | 
 | 
| 826 | GLOBAL_STR(gStr34, R"zZXx(func any(list) {
 | 
| 827 |   ## Returns true if any value in the list is truthy.
 | 
| 828 |   ##
 | 
| 829 |   ## If the list is empty, return false.
 | 
| 830 | 
 | 
| 831 |   for item in (list) {
 | 
| 832 |     if (item) {
 | 
| 833 |       return (true)
 | 
| 834 |     }
 | 
| 835 |   }
 | 
| 836 |   return (false)
 | 
| 837 | }
 | 
| 838 | 
 | 
| 839 | func all(list) {
 | 
| 840 |   ## Returns true if all values in the list are truthy.
 | 
| 841 |   ##
 | 
| 842 |   ## If the list is empty, return true.
 | 
| 843 | 
 | 
| 844 |   for item in (list) {
 | 
| 845 |     if (not item) {
 | 
| 846 |       return (false)
 | 
| 847 |     }
 | 
| 848 |   }
 | 
| 849 |   return (true)
 | 
| 850 | }
 | 
| 851 | 
 | 
| 852 | func sum(list; start=0) {
 | 
| 853 |   ## Computes the sum of all elements in the list.
 | 
| 854 |   ##
 | 
| 855 |   ## Returns 0 for an empty list.
 | 
| 856 | 
 | 
| 857 |   var sum = start
 | 
| 858 |   for item in (list) {
 | 
| 859 |     setvar sum += item
 | 
| 860 |   }
 | 
| 861 |   return (sum)
 | 
| 862 | }
 | 
| 863 | )zZXx");
 | 
| 864 | 
 | 
| 865 | GLOBAL_STR(gStr35, R"zZXx(func __math_select(list, cmp) {
 | 
| 866 |   ## Internal helper for `max` and `min`.
 | 
| 867 |   ##
 | 
| 868 |   ## NOTE: If `list` is empty, then an error is thrown.
 | 
| 869 | 
 | 
| 870 |   if (len(list) === 0) {
 | 
| 871 |     error "Unexpected empty list" (code=3)
 | 
| 872 |   }
 | 
| 873 | 
 | 
| 874 |   if (len(list) === 1) {
 | 
| 875 |     return (list[0])
 | 
| 876 |   }
 | 
| 877 | 
 | 
| 878 |   var match = list[0]
 | 
| 879 |   for i in (1 .. len(list)) {
 | 
| 880 |     setvar match = cmp(list[i], match)
 | 
| 881 |   }
 | 
| 882 |   return (match)
 | 
| 883 | }
 | 
| 884 | 
 | 
| 885 | func max(...args) {
 | 
| 886 |   ## Compute the maximum of 2 or more values.
 | 
| 887 |   ##
 | 
| 888 |   ## `max` takes two different signatures:
 | 
| 889 |   ##  - `max(a, b)` to return the maximum of `a`, `b`
 | 
| 890 |   ##  - `max(list)` to return the greatest item in the `list`
 | 
| 891 |   ##
 | 
| 892 |   ## So, for example:
 | 
| 893 |   ##
 | 
| 894 |   ##   max(1, 2)  # => 2
 | 
| 895 |   ##   max([1, 2, 3])  # => 3
 | 
| 896 | 
 | 
| 897 |   case (len(args)) {
 | 
| 898 |     (1) { return (__math_select(args[0], max)) }
 | 
| 899 |     (2) {
 | 
| 900 |       if (args[0] > args[1]) {
 | 
| 901 |         return (args[0])
 | 
| 902 |       } else {
 | 
| 903 |         return (args[1])
 | 
| 904 |       }
 | 
| 905 |     }
 | 
| 906 |     (else) { error "max expects 1 or 2 args" (code=3) }
 | 
| 907 |   }
 | 
| 908 | }
 | 
| 909 | 
 | 
| 910 | func min(...args) {
 | 
| 911 |   ## Compute the minimum of 2 or more values.
 | 
| 912 |   ##
 | 
| 913 |   ## `min` takes two different signatures:
 | 
| 914 |   ##  - `min(a, b)` to return the minimum of `a`, `b`
 | 
| 915 |   ##  - `min(list)` to return the least item in the `list`
 | 
| 916 |   ##
 | 
| 917 |   ## So, for example:
 | 
| 918 |   ##
 | 
| 919 |   ##   min(2, 3)  # => 2
 | 
| 920 |   ##   max([1, 2, 3])  # => 1
 | 
| 921 | 
 | 
| 922 |   case (len(args)) {
 | 
| 923 |     (1) { return (__math_select(args[0], min)) }
 | 
| 924 |     (2) {
 | 
| 925 |       if (args[0] < args[1]) {
 | 
| 926 |         return (args[0])
 | 
| 927 |       } else {
 | 
| 928 |         return (args[1])
 | 
| 929 |       }
 | 
| 930 |     }
 | 
| 931 |     (else) { error "min expects 1 or 2 args" (code=3) }
 | 
| 932 |   }
 | 
| 933 | }
 | 
| 934 | 
 | 
| 935 | func abs(x) {
 | 
| 936 |   ## Compute the absolute (positive) value of a number (float or int).
 | 
| 937 | 
 | 
| 938 |   if (x < 0) {
 | 
| 939 |     return (-x)
 | 
| 940 |   } else {
 | 
| 941 |     return (x)
 | 
| 942 |   }
 | 
| 943 | }
 | 
| 944 | )zZXx");
 | 
| 945 | 
 | 
| 946 | GLOBAL_STR(gStr36, R"zZXx(# Can we define methods in pure YSH?
 | 
| 947 | #
 | 
| 948 | # (mylist->find(42) !== -1)
 | 
| 949 | #
 | 
| 950 | #   instead of 
 | 
| 951 | #
 | 
| 952 | # ('42' in mylist)
 | 
| 953 | #
 | 
| 954 | # Because 'in' is for Dict
 | 
| 955 | 
 | 
| 956 | func find (haystack List, needle) {
 | 
| 957 |   for i, x in (haystack) {
 | 
| 958 |     if (x === needle) {
 | 
| 959 |       return (i)
 | 
| 960 |     }
 | 
| 961 |   }
 | 
| 962 |   return (-1)
 | 
| 963 | }
 | 
| 964 | )zZXx");
 | 
| 965 | 
 | 
| 966 | GLOBAL_STR(gStr37, R"zZXx(# These were helpful while implementing args.ysh
 | 
| 967 | # Maybe we will want to export them in a prelude so that others can use them too?
 | 
| 968 | #
 | 
| 969 | # Prior art: Rust has `todo!()` which is quite nice. Other languages allow
 | 
| 970 | # users to `raise NotImplmentedError()`.
 | 
| 971 | 
 | 
| 972 | # Andy comments:
 | 
| 973 | # - 'pass' can be : or true in shell.  It's a little obscure / confusing, but
 | 
| 974 | #   there is an argument for minimalism.  Although I prefer words like 'true',
 | 
| 975 | #   and that already means something.
 | 
| 976 | #   - UPDATE: we once took 'pass' as a keyword, but users complained because
 | 
| 977 | #     there is a command 'pass'.  So we probably can't have this by default.
 | 
| 978 | #     Need to discuss source --builtin.
 | 
| 979 | 
 | 
| 980 | # - todo could be more static?  Rust presumably does it at compile time
 | 
| 981 | 
 | 
| 982 | proc todo () {
 | 
| 983 |   ## Raises a not implemented error when run.
 | 
| 984 |   error ("TODO: not implemented")  # TODO: is error code 1 ok?
 | 
| 985 | }
 | 
| 986 | 
 | 
| 987 | proc pass () {
 | 
| 988 |   ## Use when you want to temporarily leave a block empty.
 | 
| 989 |   _ null
 | 
| 990 | }
 | 
| 991 | )zZXx");
 | 
| 992 | 
 | 
| 993 | GLOBAL_STR(gStr38, R"zZXx(# testing.ysh
 | 
| 994 | #
 | 
| 995 | # Usage:
 | 
| 996 | #   source --builtin testing.sh
 | 
| 997 | #
 | 
| 998 | # func f(x) { return (x + 1) }
 | 
| 999 | #
 | 
| 1000 | # describe foo {
 | 
| 1001 | #   assert (43 === f(42))
 | 
| 1002 | # }
 | 
| 1003 | #
 | 
| 1004 | # if is-main {
 | 
| 1005 | #   run-tests @ARGV   # --filter
 | 
| 1006 | # }
 | 
| 1007 | 
 | 
| 1008 | module stdlib/testing || return 0
 | 
| 1009 | 
 | 
| 1010 | source --builtin args.ysh
 | 
| 1011 | 
 | 
| 1012 | proc assert ( ; cond ; fail_message='default fail message') {
 | 
| 1013 |   echo 'hi from assert'
 | 
| 1014 | 
 | 
| 1015 |   = cond
 | 
| 1016 | 
 | 
| 1017 |   # I think this might be ready now?
 | 
| 1018 | 
 | 
| 1019 |   var val = evalExpr(cond) 
 | 
| 1020 | 
 | 
| 1021 |   echo
 | 
| 1022 |   echo 'value'
 | 
| 1023 |   = val
 | 
| 1024 |   pp line (val)
 | 
| 1025 | 
 | 
| 1026 |   = fail_message
 | 
| 1027 | 
 | 
| 1028 |   if (val) {
 | 
| 1029 |     echo 'OK'
 | 
| 1030 |   } else {
 | 
| 1031 |     var m = evalExpr(fail_message) 
 | 
| 1032 |     echo "FAIL - this is where we extract the string - $m"
 | 
| 1033 |   }
 | 
| 1034 | }
 | 
| 1035 | 
 | 
| 1036 | proc test-assert {
 | 
| 1037 |   var x = 42
 | 
| 1038 |   assert [42 === x]
 | 
| 1039 | }
 | 
| 1040 | 
 | 
| 1041 | proc test-expr ( ; expr ) {
 | 
| 1042 |   echo 'expr'
 | 
| 1043 |   pp line (expr)
 | 
| 1044 | }
 | 
| 1045 | 
 | 
| 1046 | proc test-named ( ; ; n=^[99] ) {
 | 
| 1047 |   echo 'n'
 | 
| 1048 |   pp line (n)
 | 
| 1049 | }
 | 
| 1050 | 
 | 
| 1051 | # What happens when there are duplicate test IDs?
 | 
| 1052 | #
 | 
| 1053 | # Also I think filter by "$test_id/$case_id"
 | 
| 1054 | 
 | 
| 1055 | proc __it (case_id ; ; ; block) {
 | 
| 1056 |   # This uses a clean directory
 | 
| 1057 |   echo TODO
 | 
| 1058 | }
 | 
| 1059 | 
 | 
| 1060 | # is this accessible to users?
 | 
| 1061 | # It can contain a global list of things to run
 | 
| 1062 | 
 | 
| 1063 | # Naming convention: a proc named 'describe' mutates a global named _describe?
 | 
| 1064 | # Or maybe _describe_list ?
 | 
| 1065 | 
 | 
| 1066 | var _describe_list = []
 | 
| 1067 | 
 | 
| 1068 | proc describe (test_id ; ; ; block) {
 | 
| 1069 |   echo describe
 | 
| 1070 |   #= desc
 | 
| 1071 | 
 | 
| 1072 |   # TODO:
 | 
| 1073 |   # - need append
 | 
| 1074 |   # - need ::
 | 
| 1075 |   # _ _describe->append(cmd)
 | 
| 1076 |   #
 | 
| 1077 |   # Need to clean this up
 | 
| 1078 |   # append (_describe, cmd)  # does NOT work!
 | 
| 1079 | 
 | 
| 1080 |   call _describe_list->append(block)
 | 
| 1081 | }
 | 
| 1082 | 
 | 
| 1083 | proc Args {
 | 
| 1084 |   echo TODO
 | 
| 1085 | }
 | 
| 1086 | 
 | 
| 1087 | # Problem: this creates a global variable?
 | 
| 1088 | Args (&spec) {
 | 
| 1089 |   flag --filter 'Regex of test descriptions'
 | 
| 1090 | }
 | 
| 1091 | 
 | 
| 1092 | proc run-tests {
 | 
| 1093 |   var opt, i = parseArgs(spec, ARGV)
 | 
| 1094 | 
 | 
| 1095 |   # TODO:
 | 
| 1096 |   # - parse --filter foo, which you can use eggex for!
 | 
| 1097 | 
 | 
| 1098 |   for cmd in (_describe) {
 | 
| 1099 |     # TODO: print filename and 'describe' name?
 | 
| 1100 |     try {
 | 
| 1101 |       eval (cmd)
 | 
| 1102 |     }
 | 
| 1103 |     if (_status !== 0) {
 | 
| 1104 |       echo 'failed'
 | 
| 1105 |     }
 | 
| 1106 |   }
 | 
| 1107 | }
 | 
| 1108 | )zZXx");
 | 
| 1109 | 
 | 
| 1110 | 
 | 
| 1111 | 
 | 
| 1112 | TextFile array[] = {
 | 
| 1113 |     {.rel_path = "_devbuild/help/data-errors", .contents = gStr0},
 | 
| 1114 |     {.rel_path = "_devbuild/help/data-front-end", .contents = gStr1},
 | 
| 1115 |     {.rel_path = "_devbuild/help/data-j8-notation", .contents = gStr2},
 | 
| 1116 |     {.rel_path = "_devbuild/help/help", .contents = gStr3},
 | 
| 1117 |     {.rel_path = "_devbuild/help/oils-usage", .contents = gStr4},
 | 
| 1118 |     {.rel_path = "_devbuild/help/osh-builtin-cmd", .contents = gStr5},
 | 
| 1119 |     {.rel_path = "_devbuild/help/osh-chapters", .contents = gStr6},
 | 
| 1120 |     {.rel_path = "_devbuild/help/osh-cmd-lang", .contents = gStr7},
 | 
| 1121 |     {.rel_path = "_devbuild/help/osh-front-end", .contents = gStr8},
 | 
| 1122 |     {.rel_path = "_devbuild/help/osh-mini-lang", .contents = gStr9},
 | 
| 1123 |     {.rel_path = "_devbuild/help/osh-option", .contents = gStr10},
 | 
| 1124 |     {.rel_path = "_devbuild/help/osh-osh-assign", .contents = gStr11},
 | 
| 1125 |     {.rel_path = "_devbuild/help/osh-plugin", .contents = gStr12},
 | 
| 1126 |     {.rel_path = "_devbuild/help/osh-special-var", .contents = gStr13},
 | 
| 1127 |     {.rel_path = "_devbuild/help/osh-type-method", .contents = gStr14},
 | 
| 1128 |     {.rel_path = "_devbuild/help/osh-usage", .contents = gStr15},
 | 
| 1129 |     {.rel_path = "_devbuild/help/osh-word-lang", .contents = gStr16},
 | 
| 1130 |     {.rel_path = "_devbuild/help/ysh-builtin-cmd", .contents = gStr17},
 | 
| 1131 |     {.rel_path = "_devbuild/help/ysh-builtin-func", .contents = gStr18},
 | 
| 1132 |     {.rel_path = "_devbuild/help/ysh-chapters", .contents = gStr19},
 | 
| 1133 |     {.rel_path = "_devbuild/help/ysh-cmd-lang", .contents = gStr20},
 | 
| 1134 |     {.rel_path = "_devbuild/help/ysh-expr-lang", .contents = gStr21},
 | 
| 1135 |     {.rel_path = "_devbuild/help/ysh-front-end", .contents = gStr22},
 | 
| 1136 |     {.rel_path = "_devbuild/help/ysh-mini-lang", .contents = gStr23},
 | 
| 1137 |     {.rel_path = "_devbuild/help/ysh-option", .contents = gStr24},
 | 
| 1138 |     {.rel_path = "_devbuild/help/ysh-plugin", .contents = gStr25},
 | 
| 1139 |     {.rel_path = "_devbuild/help/ysh-special-var", .contents = gStr26},
 | 
| 1140 |     {.rel_path = "_devbuild/help/ysh-type-method", .contents = gStr27},
 | 
| 1141 |     {.rel_path = "_devbuild/help/ysh-usage", .contents = gStr28},
 | 
| 1142 |     {.rel_path = "_devbuild/help/ysh-word-lang", .contents = gStr29},
 | 
| 1143 |     {.rel_path = "_devbuild/help/ysh-ysh-cmd", .contents = gStr30},
 | 
| 1144 |     {.rel_path = "stdlib/args.ysh", .contents = gStr31},
 | 
| 1145 |     {.rel_path = "stdlib/draft-synch.ysh", .contents = gStr32},
 | 
| 1146 |     {.rel_path = "stdlib/funcs.ysh", .contents = gStr33},
 | 
| 1147 |     {.rel_path = "stdlib/list.ysh", .contents = gStr34},
 | 
| 1148 |     {.rel_path = "stdlib/math.ysh", .contents = gStr35},
 | 
| 1149 |     {.rel_path = "stdlib/methods.ysh", .contents = gStr36},
 | 
| 1150 |     {.rel_path = "stdlib/prelude.ysh", .contents = gStr37},
 | 
| 1151 |     {.rel_path = "stdlib/testing.ysh", .contents = gStr38},
 | 
| 1152 | 
 | 
| 1153 |     {.rel_path = nullptr, .contents = nullptr},
 | 
| 1154 | };
 | 
| 1155 | 
 | 
| 1156 | }  // namespace embedded_file
 | 
| 1157 | 
 | 
| 1158 | TextFile* gEmbeddedFiles = embedded_file::array;  // turn array into pointer
 |