jammy (7) elvish-language.7.gz

Provided by: elvish_0.17.0-1ubuntu0.1_amd64 bug

Introduction

       This  document  describes  the  Elvish  programming language.  It is both a specification and an advanced
       tutorial.  The parts of this document marked with either  notes  or  called  out  as  examples  are  non-
       normative, and only serve to help you understand the more formal descriptions.

       Examples  in  this  document  might use constructs that have not yet been introduced, so some familiarity
       with the language is assumed.  If you are new to Elvish, start with the learning materials.

Source code encoding

       Elvish source code must be Unicode text encoded in UTF-8.

       In this document, character is a synonym of Unicode codepoint  (https://en.wikipedia.org/wiki/Code_point)
       or its UTF-8 encoding.

Lexical elements

   Whitespace
       In this document, an inline whitespace is any of the following:

       • A space (U+0020);

       • A tab (U+0009);

       • A  comment:  starting with # and ending before (but not including) the next carriage return, newline or
         end of file;

       • A line continuation: a ^ followed by a newline ("\n"), or a carriage return and newline ("\r\n").

       A whitespace is any of the following:

       • An inline whitespace;

       • A carriage return (U+000D);

       • A newline (U+000A).

   Metacharacters
       The following metacharacters serve to introduce or delimit syntax constructs:

       Metacharacter   Use
       ──────────────────────────────────────────────────────
       $               Referencing variables
       * and ?         Forming wildcard
       |               Separating forms in a pipeline
       &               Marking     background     pipelines;
                       introducing key-value pairs
       ;               Separating pipelines
       < and >         Introducing IO redirections
       ( and )         Enclosing output captures
       [ and ]         Enclosing list literals, map literals
                       or function signature
       { and }         Enclosing lambda  literals  or  brace
                       expressions

       The following characters are parsed as metacharacters under certain conditions:

       • ~  is  a  metacharacter  if  it  appears at the beginning of a compound expression, in which case it is
         subject to tilde expansion;

       • = is a metacharacter when used for terminating map keys or option keys, or denoting  legacy  assignment
         form or temporary assignments.

   Single-quoted string
       A  single-quoted  string consists of zero or more characters enclosed in single quotes (').  All enclosed
       characters represent themselves, except the single quote.

       Two consecutive single quotes are handled as a special case: they represent one single quote, instead  of
       terminating a single-quoted string and starting another.

       Examples: '*\' evaluates to *\, and 'it''s' evaluates to it's.

   Double-quoted string
       A  double-quoted  string consists of zero or more characters enclosed in double quotes (").  All enclosed
       characters represent themselves, except backslashes  (\),  which  introduces  escape  sequences.   Double
       quotes are not allowed inside double-quoted strings, except after backslashes.

       The following escape sequences are supported:

       • \cX, where X is a character with codepoint between 0x40 and 0x5F, represents the codepoint that is 0x40
         lower than X.  For example, \cI is the tab character: 0x49 (I) - 0x40  =  0x09  (tab).   There  is  one
         special case: A question-mark is converted to del; i.e., \c? or \^? is equivalent to \x7F.

       • \^X is the same as \cX.

       • \[0..7][0..7][0..7]  is  a  byte written as an octal value.  There must be three octal digits following
         the backslash.  For example, \000 is the nul character, and \101 is the same as A, but \0 is an invalid
         escape sequence (too few digits).

       • \x.. is a Unicode code point represented by two hexadecimal digits.

       • \u.... is a Unicode code point represented by four hexadecimal digits.

       • \U...... is a Unicode code point represented by eight hexadecimal digits.

       • The following single character escape sequences:

         • \a is the “bell” character, equivalent to \007 or \x07.

         • \b is the “backspace” character, equivalent to \010 or \x08.

         • \f is the “form feed” character, equivalent to \014 or \x0c.

         • \n is the “new line” character, equivalent to \012 or \x0a.

         • \r is the “carriage return” character, equivalent to \015 or \x0d.

         • \t is the “tab” character, equivalent to \011 or \x09.

         • \v is the “vertical tab” character, equivalent to \013 or \x0b.

         • \\ is the “backslash” character, equivalent to \134 or \x5c.

         • \" is the “double-quote” character, equivalent to \042 or \x22.

       An unsupported escape sequence results in a parse error.

       Note:  Unlike  most  other  shells,  double-quoted  strings  in Elvish do not support interpolation.  For
       instance, "$name" simply evaluates to a string  containing  $name.   To  get  a  similar  effect,  simply
       concatenate  strings:  instead of "my name is $name", write "my name is "$name.  Under the hood this is a
       compounding operation.

   Bareword
       A string can be written without quoting – a bareword,  if  it  only  includes  the  characters  from  the
       following set:

       • ASCII letters (a-z and A-Z) and numbers (0-9);

       • The symbols !%+,-./:@\_;

       • Non-ASCII      codepoints     that     are     printable,     as     defined     by     unicode.IsPrint
         (https://godoc.org/unicode#IsPrint) in Go’s standard library.

       Examples: a.txt, long-bareword, elf@elv.sh, /usr/local/bin, 你好世界.

       Moreover, ~ and = are allowed to appear without quoting when they are not parsed as metacharacters.

       Note: since the backslash (\) is a valid bareword character in  Elvish,  it  cannot  be  used  to  escape
       metacharacter.  Use quotes instead: for example, to echo a star, write echo "*" or echo '*', not echo \*.
       The last command just writes out \*.

Value types

   String
       A string is a (possibly empty) sequence of bytes.

       Single-quoted string literals, double-quoted string literals and barewords all evaluate to string values.
       Unless  otherwise noted, different syntaxes of string literals are equivalent in the code.  For instance,
       xyz, 'xyz' and "xyz" are different syntaxes for the same string with content xyz.

       Strings that contain UTF-8 encoded text can be indexed with a byte index where a codepoint starts,  which
       results in the codepoint that starts there.  The index can be given as either a typed number, or a string
       that parses to a number.  Examples:

       • In the string elv, every codepoint is encoded with only one byte, so 0, 1, 2 are all valid indices:

                ~> put elv[0]
                ▶ e
                ~> put elv[1]
                ▶ l
                ~> put elv[2]
                ▶ v

       • In the string 世界, each codepoint is encoded with three bytes.  The first codepoint  occupies  byte  0
         through 2, and the second occupies byte 3 through 5.  Hence valid indices are 0 and 3:

                ~> put 世界[0]
                ▶ 世
                ~> put 世界[3]
                ▶ 界

       Such  strings  may  also be indexed with a slice (see documentation of list for slice syntax).  The range
       determined by the slice is also interpreted as byte  indices,  and  the  range  must  begin  and  end  at
       codepoint boundaries.

       The behavior of indexing a string that does not contain valid UTF-8-encoded Unicode text is unspecified.

       Note: String indexing will likely change.

   Number
       Elvish  supports  several  types  of numbers.  There is no literal syntax, but they can be constructed by
       passing their string representation to the num builtin command:

       • Integers are written in decimal (e.g.  10), hexadecimal (e.g.  0xA), octal (e.g.  0o12) or binary (e.g.
         0b1010).

         NOTE:  Integers  with  leading zeros are now parsed as octal (e.g.  010 is the same as 0o10, or 8), but
         this is subject to change (#1372 (https://b.elv.sh/1371)).

       • Rationals are written as two exact integers joined by /, e.g.  1/2 or 0x10/100 (16/100).

       • Floating-point numbers are written with a decimal point (e.g.  10.0) or using scientific notation (e.g.
         1e1 or 1.0e1).  There are also three additional special floating-point values: +Inf, -Inf and NaN.

       Digits may be separated by underscores, which are ignored; this permits separating the digits into groups
       to improve readability.  For example, 1000000  and  1_000_000  are  equivalent,  so  are  1.234_56e3  and
       1.23456e3, or 1_2_3 and 123.

       The string representation is case-insensitive.

   Strings and numbers
       Strings and numbers are distinct types; for example, 2 and (num 2) are distinct values.

       However,  by  convention,  all  language  constructs that expect numbers (e.g.  list indices) also accept
       strings that can be converted to numbers.  This means that most of the time, you can just use the  string
       representation  of  numbers,  instead of explicitly constructing number values.  Builtin numeric commands
       follow the same convention.

       When the word number appears unqualified  in  other  sections  of  this  document,  it  means  either  an
       explicitly number-typed value (typed number), or its string representation.

       When  a typed number is converted to a string (e.g.  with to-string), the result is guaranteed to convert
       back to the original number.  In other words, eq $x (num (to-string $x)) always outputs $true if $x is  a
       typed number.

   Exactness
       Integers  and  rationals  are exact numbers; their precision is only limited by the available memory, and
       many (but not all) operations on them are guaranteed to produce mathematically correct results.

       Floating-point numbers are IEEE  754  (https://en.wikipedia.org/wiki/IEEE_754)  double-precision.   Since
       operations  on  floating-point  numbers  in  general  are  not  guaranteed to be precise, they are always
       considered inexact.

       This distinction is important for some builtin commands; see exactness-preserving commands.

   List
       A list is a value containing a sequence of values.  Values in a  list  are  called  its  elements.   Each
       element has an index, starting from zero.

       List literals are surrounded by square brackets [ ], with elements separated by whitespace.  Examples:

              ~> put [lorem ipsum]
              ▶ [lorem ipsum]
              ~> put [lorem
                      ipsum
                      foo
                      bar]
              ▶ [lorem ipsum foo bar]

       Note:  In Elvish, commas have no special meanings and are valid bareword characters, so don’t use them to
       separate elements:

              ~> li = [a, b]
              ~> put $li
              ▶ [a, b]
              ~> put $li[0]
              ▶ a,

       A list can be indexed with the index of an element to obtain the element,  which  can  take  one  of  two
       forms:

       • A  non-negative integer, an offset counting from the beginning of the list.  For example, $li[0] is the
         first element of $li.

       • A negative integer, an offset counting from the back of the list.  For instance, $li[-1]  is  the  last
         element $li.

       In both cases, the index can be given either as a typed number or a number-like string.

       A list can also be indexed with a slice to obtain a sublist, which can take one of two forms:

       • A  slice  $a..$b,  where  both $a and $b are integers.  The result is sublist of $li[$a] up to, but not
         including, $li[$b].  For instance, $li[4..7] equals [$li[4] $li[5] $li[6]], while  $li[1..-1]  contains
         all elements from $li except the first and last one.

         Both  integers  may  be  omitted;  $a  defaults  to 0 while $b defaults to the length of the list.  For
         instance, $li[..2] is equivalent to $li[0..2], $li[2..]  is  equivalent  to  $li[2..(count  $li)],  and
         $li[..] makes a copy of $li.  The last form is rarely useful, as lists are immutable.

         Note  that  the slice needs to be a single string, so there cannot be any spaces within the slice.  For
         instance, $li[2..10] cannot be written  as  $li[2..  10];  the  latter  contains  two  indices  and  is
         equivalent to $li[2..] $li[10] (see Indexing).

       • A slice $a..=$b, which is similar to $a..$b, but includes $li[$b].

       Examples:

              ~> li = [lorem ipsum foo bar]
              ~> put $li[0]
              ▶ lorem
              ~> put $li[-1]
              ▶ bar
              ~> put $li[0..2]
              ▶ [lorem ipsum]

   Map
       A map is a value containing unordered key-value pairs.

       Map  literals  are  surrounded by square brackets; a key/value pair is written &key=value (reminiscent to
       HTTP query parameters), and pairs are separated by whitespaces.  Whitespaces are allowed after =, but not
       before =.  Examples:

              ~> put [&foo=bar &lorem=ipsum]
              ▶ [&foo=bar &lorem=ipsum]
              ~> put [&a=   10
                      &b=   23
                      &sum= (+ 10 23)]
              ▶ [&a=10 &b=23 &sum=33]

       The literal of an empty map is [&].

       Specifying  a  key  without  =  or  a  value following it is equivalent to specifying $true as the value.
       Specifying a key with = but no value following it is equivalent to specifying the  empty  string  as  the
       value.  Example:

              ~> echo [&a &b=]
              [&a=$true &b='']

       A  map  can be indexed by any of its keys.  Unlike strings and lists, there is no support for slices, and
       .. and ..= have no special meanings.  Examples:

              ~> map = [&a=lorem &b=ipsum &a..b=haha]
              ~> echo $map[a]
              lorem
              ~> echo $map[a..b]
              haha

       You can test if a key is present using has-key and enumerate the keys using the keys builtins.

       Note: Since & is a metacharacter, key-value pairs do not have to follow  whitespaces;  [&a=lorem&b=ipsum]
       is equivalent to [&a=lorem &b=ipsum], just less readable.  This might change in future.

   Pseudo-map
       A  pseudo-map is not a single concrete data type.  It refers to concrete types that behave like maps with
       some restrictions.

       A pseudo-map has a fixed set of keys whose values can be accessed  by  indexing  like  you  would  for  a
       regular map.  Similarly, you can use commands like keys and has-key on such objects.

       Unlike a normal map, it is currently not possible to create a modified version of an existing pseudo-map:
       it is not possible to create a pseudo-map with new keys, without existing keys, or with a different value
       for a given key.

       The  pseudo-map  mechanism  is  often  used  for  introspection.   For  example, exceptions, user-defined
       functions, and $buildinfo are pseudo-maps.

   Nil
       The value $nil serves as the initial value of variables that are declared but not assigned.

   Boolean
       There are two boolean values, $true and $false.

       When converting non-boolean values to the boolean type, $nil  and  exceptions  convert  to  $false;  such
       values  and  $false  itself are booleanly false.  All the other non-boolean values convert to $true; such
       values and $true itself are booleanly true.

   Exception
       An exception carries information about errors during the execution of code.

       There is no literal syntax for exceptions.  See the discussion of exception and flow  commands  for  more
       information about this data type.

       An  exception  is a pseudo-map with a reason field, which is in turn a pseudo-map.  The reason pseudo-map
       has has a type field identifying how the exception was raised, and further fields depending on the type:

       • If the type field is fail, the exception was raised by the fail command.

         In this case, the content field contains the argument to fail.

       • If the type field is flow, the exception was raised by one of the flow commands.

         In this case, the name field contains the name of the flow command.

       • If the type field is pipeline, the exception was a result of multiple commands  in  the  same  pipeline
         raising exceptions.

         In this case, the exceptions field contains the exceptions from the individual commands.

       • If  the  type field starts with external-cmd/, the exception was caused by one of several conditions of
         an external command.  In this case, the following fields are available:

         • The cmd-name field contains the name of the command.

         • The pid field contains the PID of the command.

       • If the type field is external-cmd/exited, the external command exited with a non-zero status code.   In
         this case, the exit-status field contains the exit status.

       • If the type field is external-cmd/signaled, the external command was killed by a signal.  In this case,
         the following extra fields are available:

         • The signal-name field contains the name of the signal.

         • The signal-number field contains the numerical value of the signal, as a string.

         • The core-dumped field is a boolean reflecting whether a core dump was generated.

       • If the type field is external-cmd/stopped, the  external  command  was  stopped.   In  this  case,  the
         following extra fields are available:

         • The signal-name field contains the name of the signal.

         • The signal-number field contains the numerical value of the signal, as a string.

         • The trap-cause field contains the number indicating the trap cause.

       Examples:

              ~> put ?(fail foo)[reason]
              ▶ [&content=foo &type=fail]
              ~> put ?(return)[reason]
              ▶ [&name=return &type=flow]
              ~> put ?(false)[reason]
              ▶ [&cmd-name=false &exit-status=1 &pid=953421 &type=external-cmd/exited]

   File
       There  is  no  literal syntax for the file type.  This type is returned by commands such as file:open and
       path:temp-file.  It can be used as the target of a redirection rather than a filename.

       A file object is a pseudo-map with fields fd (an int) and name (a string).  If the file is closed the  fd
       will be -1.

   Function
       A  function  encapsulates  a  piece  of  code  that can be executed in an ordinary command, and takes its
       arguments and options.  Functions are first-class  values;  they  can  be  kept  in  variables,  used  as
       arguments, output on the value channel and embedded in other data structures.  Elvish comes with a set of
       builtin functions, and Elvish code can also create user-defined functions.

       Note: Unlike most programming languages, functions in Elvish do not have return  values.   Instead,  they
       can output values, which can be captured later.

       A  function literal, or alternatively a lambda, evaluates to a user-defined function.  The literal syntax
       consists of an optional signature list, followed by a code chunk that defines the body of the function.

       Here is an example without a signature:

              ~> f = { echo "Inside a lambda" }
              ~> put $f
              ▶ <closure 0x18a1a340>

       One or more whitespace characters after { is required: Elvish relies on the  presence  of  whitespace  to
       disambiguate function literals and braced lists.

       Note: It is good style to put some whitespace before the closing } for symmetry, but this is not required
       by the syntax.

       Functions defined without a signature list do not accept any arguments or options.  To  do  so,  write  a
       signature list.  Here is an example:

              ~> f = [a b]{ put $b $a }
              ~> $f lorem ipsum
              ▶ ipsum
              ▶ lorem

       There  must be no space between ] and {; otherwise Elvish will parse the signature as a list, followed by
       a lambda without signature:

              ~> put [a]{ nop }
              ▶ <closure 0xc420153d80>
              ~> put [a] { nop }
              ▶ [a]
              ▶ <closure 0xc42004a480>

       Like in the left hand of assignments, if you prefix one of the  arguments  with  @,  it  becomes  a  rest
       argument, and its value is a list containing all the remaining arguments:

              ~> f = [a @rest]{ put $a $rest }
              ~> $f lorem
              ▶ lorem
              ▶ []
              ~> $f lorem ipsum dolar sit
              ▶ lorem
              ▶ [ipsum dolar sit]
              ~> f = [a @rest b]{ put $a $rest $b }
              ~> $f lorem ipsum dolar sit
              ▶ lorem
              ▶ [ipsum dolar]
              ▶ sit

       You  can  also  declare  options  in the signature.  The syntax is &name=default (like a map pair), where
       default is the default value for the option; the value of the option will be kept in  a  variable  called
       name:

              ~> f = [&opt=default]{ echo "Value of $opt is "$opt }
              ~> $f
              Value of $opt is default
              ~> $f &opt=foobar
              Value of $opt is foobar

       Options must have default values: Options should be optional.

       If  you  call  a  function with too few arguments, too many arguments or unknown options, an exception is
       thrown:

              ~> [a]{ echo $a } foo bar
              Exception: need 1 arguments, got 2
              [tty], line 1: [a]{ echo $a } foo bar
              ~> [a b]{ echo $a $b } foo
              Exception: need 2 arguments, got 1
              [tty], line 1: [a b]{ echo $a $b } foo
              ~> [a b @rest]{ echo $a $b $rest } foo
              Exception: need 2 or more arguments, got 1
              [tty], line 1: [a b @rest]{ echo $a $b $rest } foo
              ~> [&k=v]{ echo $k } &k2=v2
              Exception: unknown option k2
              [tty], line 1: [&k=v]{ echo $k } &k2=v2

       A user-defined function is a pseudo-map.  If $f is a user-defined function, it has the following fields:

       • $f[arg-names] is a list containing the names of the arguments.

       • $f[rest-arg] is the index of the rest argument.  If there is no rest argument, it is -1.

       • $f[opt-names] is a list containing the names of the options.

       • $f[opt-defaults] is a list containing the default values of the options, in the same order  as  $f[opt-
         names].

       • $f[def] is a string containing the definition of the function, including the signature and the body.

       • $f[body] is a string containing the body of the function, without the enclosing brackets.

       • $f[src]  is a map-like data structure containing information about the source code that the function is
         defined in.  It contains the same value that the src function would output if called from the function.

Variable

       A variable is a named storage location for holding a value.  The following  characters  can  be  used  in
       variable names (a subset of bareword characters) without quoting:

       A  variable  exist  after  it  is  declared  (either  explicitly using var or implicitly using the legacy
       assignment form), and its value may be mutated by further assignments.  It can be used as  an  expression
       or part of an expression.

       Note:  In  most other shells, variables can map directly to environmental variables: $PATH is the same as
       the PATH environment variable.  This is not the case in Elvish.  Instead, environment variables  are  put
       in  a  dedicated E: namespace; the environment variable PATH is known as $E:PATH.  The $PATH variable, on
       the other hand, does not exist initially, and if you have defined it, only lives  in  a  certain  lexical
       scope within the Elvish interpreter.

       You  will  notice  that variables sometimes have a leading dollar $, and sometimes not.  The tradition is
       that they do when they are used for their values, and do not otherwise (e.g.  in  assignment).   This  is
       consistent with most other shells.

   Variable suffix
       There are two characters that have special meanings and extra type constraints when used as the suffix of
       a variable name:

       • If a variable name ends with ~, it can only take callable values,  which  are  functions  and  external
         commands.   Such  variables  are  consulted when resolving ordinary commands.  The default value is the
         builtin nop command.

       • If a variable name ends with :, it can only take namespaces as values.  They  are  used  for  accessing
         namespaced variables.

   Scoping rule
       Elvish  has  lexical  scoping.   A  file  or  an  interactive prompt starts with a top-level scope, and a
       function literal introduce new lexical scopes.

       When you use a variable, Elvish looks for it in the current lexical scope, then its parent lexical  scope
       and so forth, until the outermost scope:

              ~> x = 12
              ~> { echo $x } # $x is in the global scope
              12
              ~> { y = bar; { echo $y } } # $y is in the outer scope
              bar

       If  a variable is not in any of the lexical scopes, Elvish tries to resolve it in the builtin: namespace,
       and if that also fails, fails with an error:

              ~> echo $pid # builtin
              36613
              ~> echo $nonexistent
              Compilation error: variable $nonexistent not found
                [interactive], line 1:
                  echo $nonexistent

       Note that Elvish resolves all variables in a code chunk before starting to execute any of it; that is why
       the  error  message  above  says  compilation  error.  This can be more clearly observed in the following
       example:

              ~> echo pre-error; echo $nonexistent
              Compilation error: variable $nonexistent not found
              [tty], line 1: echo pre-error; echo $nonexistent

       When you assign a variable, Elvish does a similar searching.  If the variable cannot be found, instead of
       causing an error, it will be created in the current scope:

              ~> x = 12
              ~> { x = 13 } # assigns to x in the global scope
              ~> echo $x
              13
              ~> { z = foo } # creates z in the inner scope
              ~> echo $z
              Compilation error: variable $z not found
              [tty], line 1: echo $z

       One implication of this behavior is that Elvish will not shadow your variable in outer scopes.

       There  is  a  local: namespace that always refers to the current scope, and by using it it is possible to
       force Elvish to shadow variables:

              ~> x = 12
              ~> { local:x = 13; echo $x } # force shadowing
              13
              ~> echo $x
              12

       After force shadowing, you can still access the variable in the outer  scope  using  the  up:  namespace,
       which always skips the innermost scope:

              ~> x = 12
              ~> { local:x = 14; echo $x $up:x }
              14 12

       The  local:  and up: namespaces can also be used on unshadowed variables, although they are not useful in
       those cases:

              ~> foo = a
              ~> { echo $up:foo } # $up:foo is the same as $foo
              a
              ~> { bar = b; echo $local:bar } # $local:bar is the same as $bar
              b

       It is not possible to refer to a specific outer scope.

       You cannot create new variables in the builtin: namespace, although  existing  variables  in  it  can  be
       assigned new values.

   Closure semantics
       When  a  function  literal  refers  to a variable in an outer scope, the function will keep that variable
       alive, even if that variable is the local variable of an outer function that that function has  returned.
       This  is called closure semantics (https://en.wikipedia.org/wiki/Closure_(computer_programming)), because
       the function literal “closes” over the environment it is defined in.

       In the following example, the make-adder function outputs  two  functions,  both  referring  to  a  local
       variable $n.  Closure semantics means that:

       1. Both functions can continue to refer to the $n variable after make-adder has returned.

       2. Multiple calls to the make-adder function generates distinct instances of the $n variables.

          ~> fn make-adder {
               n = 0
               put { put $n } { n = (+ $n 1) }
             }
          ~> getter adder = (make-adder)
          ~> $getter # $getter outputs $n
          ▶ 0
          ~> $adder # $adder increments $n
          ~> $getter # $getter and $setter refer to the same $n
          ▶ 1
          ~> getter2 adder2 = (make-adder)
          ~> $getter2 # $getter2 and $getter refer to different $n
          ▶ 0
          ~> $getter
          ▶ 1

       Variables  that  get  “captured”  in  closures  are called upvalues; this is why the pseudo-namespace for
       variables in outer scopes is called up:.  When capturing upvalues, Elvish  only  captures  the  variables
       that are used.  In the following example, $m is not an upvalue of $g because it is not used:

              ~> fn f { m = 2; n = 3; put { put $n } }
              ~> g = (f)

       This  effect  is  not  currently  observable,  but  will  become so when namespaces become introspectable
       (https://github.com/elves/elvish/issues/492).

Expressions

       Elvish has a few types of expressions.  Some of those are new compared to most other languages, but  some
       are very similar.

       Unlike  most other languages, expressions in Elvish may evaluate to any number of values.  The concept of
       multiple values is distinct from a list of multiple elements.

   Literal
       Literals of strings, lists, maps and functions all evaluate to one value of  their  corresponding  types.
       They are described in their respective sections.

   Variable use
       A variable use expression is formed by a $ followed by the name of the variable.  Examples:

              ~> foo = bar
              ~> x y = 3 4
              ~> put $foo
              ▶ bar
              ~> put $x
              ▶ 3

       If  the  variable name only contains the following characters (a subset of bareword characters), the name
       can appear unquoted after $ and the variable use expression extends  to  the  longest  sequence  of  such
       characters:

       • ASCII letters (a-z and A-Z) and numbers (0-9);

       • The  symbols  -_:~.   The colon : is special; it is normally used for separating namespaces or denoting
         namespace variables;

       • Non-ASCII     codepoints     that     are     printable,     as     defined     by      unicode.IsPrint
         (https://godoc.org/unicode#IsPrint) in Go’s standard library.

       Alternatively,     $     may     be     followed     immediately     by     a     single-quoted    string
       (https://elv.sh/ref/language.html#single-quoted-string)       or       a       double-quoted       string
       (https://elv.sh/ref/language.html#double-quoted-string), in which cases the value of the string specifies
       the name of the variable.  Examples:

              ~> "\n" = foo
              ~> put $"\n"
              ▶ foo
              ~> '!!!' = bar
              ~> put $'!!!'
              ▶ bar

       Unlike other shells and other dynamic languages, local namespaces in Elvish are statically checked.  This
       means  that  referencing a nonexistent variable results in a compilation error, which is triggered before
       any code is actually evaluated:

              ~> echo $x
              Compilation error: variable $x not found
              [tty], line 1: echo $x
              ~> f = { echo $x }
              compilation error: variable $x not found
              [tty 1], line 1: f = { echo $x }

       If a variable contains a list value, you can add @ before the variable name; this evaluates  to  all  the
       elements within the list.  This is called exploding the variable:

              ~> li = [lorem ipsum foo bar]
              ~> put $li
              ▶ [lorem ipsum foo bar]
              ~> put $@li
              ▶ lorem
              ▶ ipsum
              ▶ foo
              ▶ bar

       Note:  Since  variable uses have higher precedence than indexing, this does not work for exploding a list
       that is an element of another list.  For doing that, and exploding the result of other expressions  (such
       as an output capture), use the builtin all command.)

   Output capture
       An  output  capture expression is formed by putting parentheses () around a code chunk.  It redirects the
       output of the chunk into an internal pipe, and evaluates to all the values that have been output.

              ~> + 1 10 100
              ▶ 111
              ~> x = (+ 1 10 100)
              ~> put $x
              ▶ 111
              ~> put lorem ipsum
              ▶ lorem
              ▶ ipsum
              ~> x y = (put lorem ipsum)
              ~> put $x
              ▶ lorem
              ~> put $y
              ▶ ipsum

       If the chunk outputs bytes, Elvish strips the last newline (if any), and  split  them  by  newlines,  and
       consider each line to be one string value:

              ~> put (echo "a\nb")
              ▶ a
              ▶ b

       Trailing  carriage returns are also stripped from each line, which effectively makes \r\n also valid line
       separators:

              ~> put (echo "a\r\nb")
              ▶ a
              ▶ b

       Note 1.  Only the last newline is ever removed, so empty lines are preserved; (echo "a\n")  evaluates  to
       two values, "a" and "".

       Note  2.   One consequence of this mechanism is that you can not distinguish outputs that lack a trailing
       newline from outputs that have one; (echo what) evaluates to the same value as (print what).  If  such  a
       distinction is needed, use slurp to preserve the original bytes output.

       If  the chunk outputs both values and bytes, the values of output capture will contain both value outputs
       and lines.  However, the ordering between value output and byte output might not agree with the order  in
       which they happened:

              ~> put (put a; echo b) # value order need not be the same as output order
              ▶ b
              ▶ a

       Note:  If  you  want  to  capture  the  stdout and stderr byte streams independent of each other, see the
       example in the run-parallel documentation.

   Exception capture
       An exception capture expression is formed by putting ?() around a code chunk.   It  runs  the  chunk  and
       evaluates to the exception it throws.

              ~> fail bad
              Exception: bad
              Traceback:
                [interactive], line 1:
                  fail bad
              ~> put ?(fail bad)
              ▶ ?(fail bad)

       If there was no error, it evaluates to the special value $ok:

              ~> nop
              ~> put ?(nop)
              ▶ $ok

       Exceptions are booleanly false and $ok is booleanly true.  This is useful in if (introduced later):

              if ?(test -d ./a) {
                # ./a is a directory
              }

       Note:  Exception captures do not affect the output of the code chunk.  You can combine output capture and
       exception capture:

              output = (error = ?(commands-that-may-fail))

   Braced list
       A braced list consists of multiple expressions separated by whitespaces and surrounded  by  braces  ({}).
       There  must  be  no  space  after the opening brace.  A braced list evaluates to whatever the expressions
       inside it evaluate to.  Its most typical use is  grouping  multiple  values  in  a  compound  expression.
       Example:

              ~> put {a b}-{1 2}
              ▶ a-1
              ▶ a-2
              ▶ b-1
              ▶ b-2

       It can also be used to affect the order of evaluation.  Examples:

              ~> put *
              ▶ foo
              ▶ bar
              ~> put *o
              ▶ foo
              ~> put {*}o
              ▶ fooo
              ▶ baro

       Note: When used to affect the order of evaluation, braced lists are very similar to parentheses in C-like
       languages.

       Note: A braced list is an expression.  It is a syntactical construct and not a separate data structure.

       Elvish currently also supports using commas to separate items in a braced  list.   This  will  likely  be
       removed in future, but it also means that literal commas must be quoted right now.

   Indexing
       An  indexing  expression  is formed by appending one or more indices inside a pair of brackets ([]) after
       another expression (the indexee).  Examples:

              ~> li = [foo bar]
              ~> put $li[0]
              ▶ foo
              ~> li = [[foo bar] quux]
              ~> put $li[0][0]
              ▶ foo
              ~> put [[foo bar]][0][0]
              ▶ foo

       If the expression being indexed evaluates to multiple values, the indexing operation is applied  on  each
       value.  Example:

              ~> put (put [foo bar] [lorem ipsum])[0]
              ▶ foo
              ▶ lorem
              ~> put {[foo bar] [lorem ipsum]}[0]
              ▶ foo
              ▶ lorem

       If  there  are  multiple  index  expressions,  or  the index expression evaluates to multiple values, the
       indexee is indexed once for each of the index value.  Examples:

              ~> put elv[0 2 0..2]
              ▶ e
              ▶ v
              ▶ el
              ~> put [lorem ipsum foo bar][0 2 0..2]
              ▶ lorem
              ▶ foo
              ▶ [lorem ipsum]
              ~> put [&a=lorem &b=ipsum &a..b=haha][a a..b]
              ▶ lorem
              ▶ haha

       If both the indexee and index evaluate to multiple values, the results generated from the  first  indexee
       appear first.  Example:

              ~> put {[foo bar] [lorem ipsum]}[0 1]
              ▶ foo
              ▶ bar
              ▶ lorem
              ▶ ipsum

   Compounding
       A  compound  expression  is  formed  by writing several expressions together with no space in between.  A
       compound expression evaluates to a string concatenation of all the constituent expressions.  Examples:

              ~> put 'a'b"c" # compounding three string literals
              ▶ abc
              ~> v = value
              ~> put '$v is '$v # compounding one string literal with one string variable
              ▶ '$v is value'

       When one or more of the constituent expressions evaluate to multiple values, the result is  all  possible
       combinations:

              ~> li = [foo bar]
              ~> put {a b}-$li[0 1]
              ▶ a-foo
              ▶ a-bar
              ▶ b-foo
              ▶ b-bar

       The  order  of  the combinations is determined by first taking the first value in the leftmost expression
       that generates multiple values, and then taking the second value, and so on.

   Tilde expansion
       An unquoted tilde at the beginning of a compound expression triggers tilde expansion.  The  remainder  of
       this  expression  must  be a string.  The part from the beginning of the string up to the first / (or the
       end of the word if the string does not contain /), is taken as a user name; and they together evaluate to
       the home directory of that user.  If the user name is empty, the current user is assumed.

       In  the  following  example, the home directory of the current user is /home/xiaq, while that of the root
       user is /root:

              ~> put ~
              ▶ /home/xiaq
              ~> put ~root
              ▶ /root
              ~> put ~/xxx
              ▶ /home/xiaq/xxx
              ~> put ~root/xxx
              ▶ /root/xxx

       Note that tildes are not special when they appear elsewhere in a word:

              ~> put a~root
              ▶ a~root

       If you need them to be, use a braced list:

              ~> put a{~root}
              ▶ a/root

   Wildcard expansion
       Wildcard patterns are expressions that contain wildcards.  Wildcard patterns evaluate  to  all  filenames
       they match.

       In examples in this section, we will assume that the current directory has the following structure:

              .x.conf
              a.cc
              ax.conf
              foo.cc
              d/
              |__ .x.conf
              |__ ax.conf
              |__ y.cc
              .d2/
              |__ .x.conf
              |__ ax.conf

       Elvish supports the following wildcards:

       • ? matches one arbitrary character except /.  For example, ?.cc matches a.cc;

       • * matches any number of arbitrary characters except /.  For example, *.cc matches a.cc and foo.cc;

       • ** matches any number of arbitrary characters including /.  For example, **.cc matches a.cc, foo.cc and
         b/y.cc.

       The following behaviors are default, although they can be altered by modifiers:

       • When the entire wildcard pattern has no match, an error is thrown.

       • None of the wildcards matches . at the beginning of filenames.  For example:

         • ?x.conf does not match .x.conf;

         • d/*.conf does not match d/.x.conf;

         • **.conf does not match d/.x.conf.

       Wildcards can be modified using the same syntax as indexing.  For  instance,  in  *[match-hidden]  the  *
       wildcard   is   modified  with  the  match-hidden  modifier.   Multiple  matchers  can  be  chained  like
       *[set:abc][range:0-9].  In which case they are OR’ed together.

       There are two kinds of modifiers:

       Global modifiers apply to the whole pattern and can be placed after any wildcard:

       • nomatch-ok tells Elvish not to throw an error when there is no match for the pattern.  For instance, in
         the example directory put bad* will be an error, but put bad*[nomatch-ok] does exactly nothing.

       • but:xxx (where xxx is any filename) excludes the filename from the final result.

       • type:xxx (where xxx is a recognized file type from the list below).  Only one type modifier is allowed.
         For example, to find the directories at any level below the current working directory: **[type:dir].

         • dir will match if the path is a directory.

         • regular will match if the path is a regular file.

       Although global modifiers affect the entire wildcard pattern, you can add it after any wildcard, and  the
       effect  is the same.  For example, put */*[nomatch-ok].cpp and put *[nomatch-ok]/*.cpp do the same thing.
       On the other hand, you must  add  it  after  a  wildcard,  instead  of  after  the  entire  pattern:  put
       */*.cpp[nomatch-ok] unfortunately does not do the correct thing.  (This will probably be fixed.)

       Local modifiers only apply to the wildcard it immediately follows:

       • match-hidden  tells  the  wildcard to match . at the beginning of filenames, e.g.  *[match-hidden].conf
         matches .x.conf and ax.conf.

         Being a local modifier, it only applies to the wildcard it immediately follows.  For instance, *[match-
         hidden]/*.conf matches d/ax.conf and .d2/ax.conf, but not d/.x.conf or .d2/.x.conf.

       • Character matchers restrict the characters to match:

         • Character sets, like set:aeoiu;

         • Character ranges like range:a-z (including z) or range:a~z (excluding z);

         • Character classes: control, digit, graphic, letter, lower, mark, number, print, punct, space, symbol,
           title, and upper.  See the Is* functions here (https://godoc.org/unicode) for their definitions.

       Note the following caveats:

       • Local matchers chained together in separate modifiers are  OR’ed.   For  instance,  ?[set:aeoiu][digit]
         matches all files with the chars aeoiu or containing a digit.

       • Local  matchers  combined in the same modifier, such as ?[set:aeoiu digit], behave in a hard to explain
         manner.  Do not use this form as the behavior is likely to change in the future.

       • Dots at the beginning of filenames always  require  an  explicit  match-hidden,  even  if  the  matcher
         includes  ..   For  example,  ?[set:.a]x.conf  does  not  match  .x.conf;  you  have to ?[set:.a match-
         hidden]x.conf.

       • Likewise, you always need to use ** to match slashes, even if the  matcher  includes  /.   For  example
         *[set:abc/] is the same as *[set:abc].

   Order of evaluation
       An expression can use a combination of indexing, tilde expansion, wildcard and compounding.  The order of
       evaluation is as follows:

       1. Literals, variable uses, output captures and exception captures and  braced  lists  have  the  highest
          precedence and are evaluated first.

       2. Indexing has the next highest precedence and is then evaluated first.

       3. Expression compounding then happens.  Tildes and wildcards are kept unevaluated.

       4. If  the  expression  starts  with  a  tilde,  tilde  expansion happens.  If the tilde is followed by a
          wildcard, an exception is raised.

       5. If the expression contains any wildcard, wildcard expansion happens.

       Here an example: in ~/$li[0 1]/* (where $li is a list [foo bar]), the expression is evaluated as follows:

       1. The variable use $li evaluates to the list [foo bar].

       2. The indexing expression $li[0] evaluates to two strings foo and bar.

       3. Compounding the expression, the result is ~/foo/* and ~/bar/*.

       4. Tilde expansion happens; assuming that the user’s home directory is  /home/elf,  the  values  are  now
          /home/elf/foo/* and /home/elf/bar/*.

       5. Wildcard  expansion  happens,  evaluating the expression to all the filenames within /home/elf/foo and
          /home/elf/bar.  If any directory is empty or nonexistent, an exception is thrown.

       To force a particular order of evaluation, group expressions using a braced list.

Command forms

       A command form is either an ordinary command, a special command or an legacy  assignment  form.   All  of
       three different types have access to IO ports, which can be modified via redirections.

       When Elvish parses a command form, it applies the following process to decide its type:

       • If the command form contains an unquoted equal sign surrounded by inline whitespaces, it is an ordinary
         assignment.

       • If the first expression in the command form contains a single string  literal,  and  the  string  value
         matches one of the special commands, it is a special command.

       • Otherwise, it is an ordinary command.

   Ordinary command
       An ordinary command form consists of a command head, and any number of arguments and options.

       The first expression in an ordinary command is the command head.  If the head is a single string literal,
       it is subject to static resolution:

       • If a variable with name head~ (where head is the value of the head) exists, the head will  evaluate  as
         if it is $head~; i.e., a function invocation.

       • If  the  head  contains  at least one slash, it is treated as an external command with the value as its
         path relative to the current directory.

       • Otherwise, the head is considered “unknown”, and the behavior  is  controlled  by  the  unknown-command
         pragma:

         • If the unknown-command pragma is set to external (the default), the head is treated as the name of an
           external command, to be searched in the $E:PATH during runtime.

         • If the unknown-command pragma is set to disallow, such command heads trigger a compilation error.

       If the head is not a single string literal, it is evaluated as a normal expression.  The expression  must
       evaluate to one value, and the value must be one of the following:

       • A callable value: a function or external command.

       • A  string  containing at least one slash, in which case it is treated like an external command with the
         string value as its path.

       Examples of commands using static resolution:

              ~> put x # resolves to builtin function $put~
              ▶ x
              ~> f~ = { put 'this is f' }
              ~> f # resolves to user-defined function $f~
              ▶ 'this is f'
              ~> whoami # resolves to external command whoami
              elf

       Examples of commands using a dynamic callable head:

              ~> $put~ x
              ▶ x
              ~> (external whoami)
              elf
              ~> { put 'this is a lambda' }
              ▶ 'this is a lambda'

       Note: The last command resembles a code block in C-like languages in syntax, but is quite different under
       the hood: it works by defining a function on the fly and calling it immediately.

       Examples of commands using a dynamic string head:

              ~> x = /bin/whoami
              ~> $x
              elf
              ~> x = whoami
              ~> $x # dynamic strings can only used when containing slash
              Exception: bad value: command must be callable or string containing slash, but is string
              [tty 10], line 1: $x

       The  definition  of  barewords is relaxed when parsing the head, and includes <, >, and *.  These are all
       names of numeric builtins:

              ~> < 3 5 # less-than
              ▶ $true
              ~> > 3 5 # greater-than
              ▶ $false
              ~> * 3 5 # multiplication
              ▶ 15

       Arguments and options can be supplied to commands.  Arguments are arbitrary  words,  while  options  have
       exactly the same syntax as key-value pairs in map literals.  They are separated by inline whitespaces and
       may be intermixed:

              ~> echo &sep=, a b c # &seq=, is an option; a b c are arguments
              a,b,c
              ~> echo a b &sep=, c # same, with the option mixed within arguments
              a,b,c

       Note: Since options have the same syntax as key-value pairs in maps, &key is equivalent to &key=$true:

              ~> fn f [&opt=$false]{ put $opt }
              ~> f &opt
              ▶ $true

       Note: Since & is a metacharacter, it can be used to start an option immediately after the  command  name;
       echo&sep=, a b is equivalent to echo &sep=, a b, just less readable.  This might change in future.

   Special command
       A  special  command  form has the same syntax with an ordinary command, but how it is executed depends on
       the command head.  See special commands.

   Legacy assignment form
       If any argument in a command form is an unquoted equal sign (=),  the  command  form  is  treated  as  an
       assignment  form:  the  arguments  to  the left of =, including the head, are treated as lvalues, and the
       arguments to the right of = are treated as values to assign to those lvalues.

       If any lvalue refers to a variable that doesn’t yet exist, it is created first.

       This is a legacy syntax that will be deprecated in future.   Use  the  var  special  command  to  declare
       variables, and the set special command set the values of variables.

   Temporary assignment
       You  can  prepend  any  command form with temporary assignments, which gives variables temporarily values
       during the execution of that command.

       In the following example, $x and $y are temporarily assigned 100 and 200:

              ~> x y = 1 2
              ~> x=100 y=200 + $x $y
              ▶ 300
              ~> echo $x $y
              1 2

       In contrary to normal assignments, there should be no whitespaces around  the  equal  sign  =.   To  have
       multiple variables in the left-hand side, use braces:

              ~> x y = 1 2
              ~> fn f { put 100 200 }
              ~> {x,y}=(f) + $x $y
              ▶ 300

       If  you  use  a  previously undefined variable in a temporary assignment, its value will become the empty
       string after the command finishes.  This behavior will likely change; don’t rely on it.

       Since ordinary assignments are also command forms, they can also be prepended with temporary assignments:

              ~> x=1
              ~> x=100 y = (+ 133 $x)
              ~> put $x $y
              ▶ 1
              ▶ 233

       Temporary assignments must all appear at the beginning of the command form.  As soon as something that is
       not  a  temporary assignments is parsed, Elvish no longer parses temporary assignments.  For instance, in
       x=1 echo x=1, the second x=1 is not a temporary assignment, but a bareword.

       Note: Elvish’s behavior differs  from  bash  (or  zsh)  in  one  important  place.   In  bash,  temporary
       assignments to variables do not affect their direct appearance in the command:

              bash-4.4$ x=1
              bash-4.4$ x=100 echo $x
              1

       Note:  Elvish currently supports using the syntax of temporary assignments for ordinary assignments, when
       they are not followed by a command form; for example, a=x behaves like an  ordinary  assignment  a  =  x.
       This will likely go away; don’t rely on it.

   IO ports
       A  command  have access to a number of IO ports.  Each IO port is identified by a number starting from 0,
       and combines a traditional file object, which conveys bytes, and a value channel, which conveys values.

       Elvish starts with 3 IO ports at the top level with special significance for commands:

       • Port 0, known as standard input or stdin, and is used as the default input port by builtin commands.

       • Port 1, known as standard output or stdout, and is used as the default output port by builtin commands.

       • Port 2, known as standard error or stderr, is currently not special for builtin commands,  but  usually
         has special significance for external commands.

       Value  channels are typically created by a pipeline, and used to pass values between commands in the same
       pipeline.  At the top level, they are initialized with special values:

       • The value channel for port 0 never produces any values when read.

       • The value channels for port 1 and 2 are special channels that forward the values  written  to  them  to
         their file counterparts.  Each value is put on a separate line, with a prefix controlled by $value-out-
         indicator.  The default prefix is ▶ followed by a space.

       When running an external command, the file object from each port is used to create  its  file  descriptor
       table.  Value channels only work inside the Elvish process, and are not accessible to external commands.

       IO ports can be modified with redirections or by pipelines.

   Redirection
       A redirection modifies the IO ports a command operate with.  There are several variants.

       A  file  redirection  opens a file and associates it with an IO port.  The syntax consists of an optional
       destination IO port (like 2), a redirection operator (like >) and a filename (like error.log):

       • The destination IO port determines which IO port to modify.  It can be given either as  the  number  of
         the IO port, or one of stdin, stdout and stderr, which are equivalent to 0, 1 and 2 respectively.

         The destination IO port can be omitted, in which case it is inferred from the redirection operator.

         When  the  destination  IO  port  is  given, it must precede the redirection operator directly, without
         whitespaces in between; if there are whitespaces,  otherwise  Elvish  will  parse  it  as  an  argument
         instead.

       • The redirection operator determines the mode to open the file, and the destination IO port if it is not
         explicitly specified.

       • The filename names the file to open.

       Possible redirection operators and their default FDs are:

       • < for reading.  The default IO port is 0 (stdin).

       • > for writing.  The default IO port is 1 (stdout).

       • >> for appending.  The default IO port is 1 (stdout).

       • <> for reading and writing.  The default IO port is 1 (stdout).

       Examples:

              ~> echo haha > log
              ~> cat log
              haha
              ~> cat < log
              haha
              ~> ls --bad-arg 2> error
              Exception: ls exited with 2
              Traceback:
                [interactive], line 1:
                  ls --bad-arg 2> error
              ~> cat error
              /bin/ls: unrecognized option '--bad-arg'
              Try '/bin/ls --help' for more information.

       IO ports modified by file redirections do not support value channels.  To be more exact:

       • A file redirection using < sets the value channel to one that never produces any values.

       • A file redirection using >, >> or <> sets the value channel  to  one  that  throws  an  exception  when
         written to.

       Examples:

              ~> put foo > file # will truncate file if it exists
              Exception: port has no value output
              [tty 2], line 1: put foo > file
              ~> echo content > file
              ~> only-values < file
              ~> # previous command produced nothing

       Redirections  can  also  be used for closing or duplicating IO ports.  Instead of writing a filename, use
       &fd (where fd is a number, or any of stdin, stdout and stderr) for duplicating, or &-  for  closing.   In
       this case, the redirection operator only determines the default destination FD (and is totally irrevelant
       if a destination IO port is specified).  Examples:

              ~> date >&-
              date: stdout: Bad file descriptor
              Exception: date exited with 1
              [tty 3], line 1: date >&-
              ~> put foo >&-
              Exception: port has no value output
              [tty 37], line 1: put foo >&-

       If you have multiple related redirections, they are applied in the order they appear.  For instance:

              ~> fn f { echo out; echo err >&2 } # echoes "out" on stdout, "err" on stderr
              ~> f >log 2>&1 # use file "log" for stdout, then use (changed) stdout for stderr
              ~> cat log
              out
              err

       Redirections may appear anywhere in the command, except at the beginning,  (this  may  be  restricted  in
       future).  It’s usually good style to write redirections at the end of command forms.

Special commands

       Special commands obey the same syntax rules as normal commands, but have evaluation rules that are custom
       to each command.  Consider the following example:

              ~> or ?(echo x) ?(echo y) ?(echo z)
              x
              ▶ $ok

       In the example, the or command first evaluates its first argument, which has  the  value  $ok  (a  truish
       value)  and  the  side  effect of outputting x.  Due to the custom evaluation rule of or, the rest of the
       arguments are not evaluated.

       If or were a normal command, the code above is still syntactically correct.  However, Elvish  would  then
       evaluate all its arguments, with the side effect of outputting x, y and z, before calling or.

   Declaring variables: var {#var}
       The  var  special  command  declares  local variables.  It takes any number of unqualified variable names
       (without the leading $).  The variables will start out having value $nil.  Examples:

              ~> var a
              ~> put $a
              ▶ $nil
              ~> var foo bar
              ~> put $foo $bar
              ▶ $nil
              ▶ $nil

       To set alternative initial values, add an unquoted = and the initial values.  Examples:

              ~> var a b = foo bar
              ~> put $a $b
              ▶ foo
              ▶ bar

       Similar to set, at most one of variables may be prefixed with @ to function as a rest variable.

       When declaring a variable that already exists, the existing variable is shadowed.  The shadowed  variable
       may still be accessed indirectly if it is referenced by a function.  Example:

              ~> var x = old
              ~> fn f { put $x }
              ~> var x = new
              ~> put $x
              ▶ new
              ~> f
              ▶ old

   Setting the value of variables or elements: set {#set}
       The set special command sets the value of variables or elements.

       It  takes  any number of lvalues (which refer to either variables or elements), followed by an equal sign
       (=) and any number of expressions.  The equal sign must appear unquoted, as a single argument.

       An lvalue is one of the following:

       • A variable name (without $).

       • A variable name prefixed with @, for packing a variable number of values into a list and  assigning  to
         the variable.

         This variant is called a rest variable.  There could be at most one rest variable.

         Note:  Schematically  this is the reverse operation of exploding a variable when using it, which is why
         they share the @ sign.

       • A variable name followed by one or more indices in brackets ([]), for assigning to an element.

       The number of values the expressions evaluate to and lvalues must be compatible.  To be more exact:

       • If there is no rest variable, the number of values and lvalues must match exactly.

       • If there is a rest variable, the number of values should be at least the number of lvalues minus one.

       All the variables to set must already exist; use the var special command to declare new variables.

       Examples:

              ~> var x y z
              ~> set x = foo
              ~> put $x
              ▶ foo
              ~> x y = lorem ipsum
              ~> put $x $y
              ▶ lorem
              ▶ ipsum
              ~> set x @y z = a b
              ~> put $x $y $z
              ▶ a
              ▶ []
              ▶ b
              ~> set x @y z = a b c d
              ~> put $x $y $z
              ▶ a
              ▶ [b c]
              ▶ d
              ~> set y[0] = foo
              ~> put $y
              ▶ [foo c]

       If the variable name contains any character that may not appear unquoted in variable use expressions,  it
       must be quoted even if it is otherwise a valid bareword:

              ~> var 'a/b'
              ~> set a/b = foo
              compilation error: lvalue must be valid literal variable names
              [tty 23], line 1: a/b = foo
              ~> set 'a/b' = foo
              ~> put $'a/b'
              ▶ foo

       Lists  and  maps  in Elvish are immutable.  As a result, when assigning to the element of a variable that
       contains a list or map, Elvish does not mutate the underlying list or map.  Instead, Elvish creates a new
       list or map with the mutation applied, and assigns it to the variable.  Example:

              ~> var li = [foo bar]
              ~> var li2 = $li
              ~> set li[0] = lorem
              ~> put $li $li2
              ▶ [lorem bar]
              ▶ [foo bar]

   Deleting variables or elements: del {#del}
       The  del  special  command can be used to delete variables or map elements.  Operands should be specified
       without a leading dollar sign, like the left-hand side of assignments.

       Example of deleting variable:

              ~> x = 2
              ~> echo $x
              2
              ~> del x
              ~> echo $x
              Compilation error: variable $x not found
              [tty], line 1: echo $x

       If the variable name contains any character that cannot appear unquoted after $, it must be quoted,  even
       if it is otherwise a valid bareword:

              ~> 'a/b' = foo
              ~> del 'a/b'

       Deleting  a  variable  does  not affect closures that have already captured it; it only removes the name.
       Example:

              ~> x = value
              ~> fn f { put $x }
              ~> del x
              ~> f
              ▶ value

       Example of deleting map element:

              ~> m = [&k=v &k2=v2]
              ~> del m[k2]
              ~> put $m
              ▶ [&k=v]
              ~> l = [[&k=v &k2=v2]]
              ~> del l[0][k2]
              ~> put $l
              ▶ [[&k=v]]

   Logics: and, or, coalesce {#and-or-coalesce}
       The and special command outputs the first booleanly false value the arguments evaluate to, or $true  when
       given no value.  Examples:

              ~> and $true $false
              ▶ $false
              ~> and a b c
              ▶ c
              ~> and a $false
              ▶ $false

       The  or  special command outputs the first booleanly true value the arguments evaluate to, or $false when
       given no value.  Examples:

              ~> or $true $false
              ▶ $true
              ~> or a b c
              ▶ a
              ~> or $false a b
              ▶ a

       The coalesce special command outputs the first non-nil value the arguments  evaluate  to,  or  $nil  when
       given no value.  Examples:

              ~> coalesce $nil a b
              ▶ a
              ~> coalesce $nil $nil
              ▶ $nil
              ~> coalesce $nil $nil a
              ▶ a
              ~> coalesce a b
              ▶ a

       All three commands use short-circuit evaluation, and stop evaluating arguments as soon as it sees a value
       satisfying the termination condition.  For example, none of the following throws an exception:

              ~> and $false (fail foo)
              ▶ $false
              ~> or $true (fail foo)
              ▶ $true
              ~> coalesce a (fail foo)
              ▶ a

   Condition: if {#if}
       TODO: Document the syntax notation, and add more examples.

       Syntax:

              if <condition> {
                  <body>
              } elif <condition> {
                  <body>
              } else {
                  <else-body>
              }

       The if special command goes through the conditions one by one: as soon as one evaluates  to  a  booleanly
       true  value,  its  corresponding  body is executed.  If none of conditions are booleanly true and an else
       body is supplied, it is executed.

       The condition part is an expression, not a command like in other shells.  Example:

              fn tell-language [fname]{
                  if (has-suffix $fname .go) {
                      echo $fname" is a Go file!"
                  } elif (has-suffix $fname .c) {
                      echo $fname" is a C file!"
                  } else {
                      echo $fname" is a mysterious file!"
                  }
              }

       The condition part must be syntactically a single expression, but it can evaluate to multiple values,  in
       which case they are and’ed:

              if (put $true $false) {
                  echo "will not be executed"
              }

       If the expression evaluates to 0 values, it is considered true, consistent with how and works.

       Tip: a combination of if and ?() gives you a semantics close to other shells:

              if ?(test -d .git) {
                  # do something
              }

       However,  for  Elvish’s  builtin  predicates  that  output values instead of throw exceptions, the output
       capture construct () should be used.

   Conditional loop: while {#while}
       Syntax:

              while <condition> {
                  <body>
              } else {
                  <else-body>
              }

       Execute the body as long as the condition evaluates to a booleanly true value.

       The else body, if present, is executed if the body has never been executed (i.e.  the condition evaluates
       to a booleanly false value in the very beginning).

   Iterative loop: for {#for}
       Syntax:

              for <var> <container> {
                  <body>
              } else {
                  <body>
              }

       Iterate  the  container  (e.g.   a  list).   In  each iteration, assign the variable to an element of the
       container and execute the body.

       The else body, if present, is executed if the body has never been executed (i.e.  the iteration value has
       no elements).

   Exception control: try {#try}
       (If  you just want to capture the exception, you can use the more concise exception capture construct ?()
       instead.)

       Syntax:

              try {
                  <try-block>
              } except except-varname {
                  <except-block>
              } else {
                  <else-block>
              } finally {
                  <finally-block>
              }

       Only try and try-block are required.  This control structure behaves as follows:

       1. The try-block is always executed first.

       2. If except is present and an exception occurs in try-block, it is caught and stored in  except-varname,
          and except-block is then executed.  Example:

                  ~> try { fail bad } except e { put $e }
                  ▶ ?(fail bad)

           Note  that  if  except is not present, exceptions thrown from try are not caught: for instance, try {
           fail bad } throws bad; it is equivalent to a plain fail bad.

           Note that the word after except names a variable, not a matching condition.   Exception  matching  is
           not  supported  yet.  For instance, you may want to only match exceptions that were created with fail
           bad with except bad, but in fact this creates a variable $bad that contains  whatever  exception  was
           thrown.

       3. If no exception occurs and else is present, else-block is executed.  Example:

                  ~> try { nop } else { echo well }
                  well

       4. If finally-block is present, it is executed.  Examples:

                  ~> try { fail bad } finally { echo final }
                  final
                  Exception: bad
                  Traceback:
                    [tty], line 1:
                      try { fail bad } finally { echo final }
                  ~> try { echo good } finally { echo final }
                  good
                  final

       5. If the exception was not caught (i.e.  except is not present), it is rethrown.

       Exceptions  thrown  in blocks other than try-block are not caught.  If an exception was thrown and either
       except-block or finally-block throws another exception, the original exception is lost.  Examples:

              ~> try { fail bad } except e { fail worse }
              Exception: worse
              Traceback:
                [tty], line 1:
                  try { fail bad } except e { fail worse }
              ~> try { fail bad } except e { fail worse } finally { fail worst }
              Exception: worst
              Traceback:
                [tty], line 1:
                  try { fail bad } except e { fail worse } finally { fail worst }

   Function definition: fn {#fn}
       Syntax:

              fn <name> <lambda>

       Define a function with a given name.  The function behaves in the same way to the lambda used  to  define
       it,  except that it “captures” return.  In other words, return will fall through lambdas not defined with
       fn, and continues until it exits a function defined with fn:

              ~> fn f {
                   { echo a; return }
                   echo b # will not execute
                 }
              ~> f
              a
              ~> {
                   f
                   echo c # executed, because f "captures" the return
                 }
              a
              c

       TODO: Find a better way to describe this.  Hopefully the example is illustrative enough, though.

       The lambda may refer to the function being defined.  This makes it easy to define recursive functions:

              ~> fn f [n]{ if (== $n 0) { put 1 } else { * $n (f (- $n 1)) } }
              ~> f 3
              ▶ (float64 6)

       Under the hood, fn defines a variable with the given name plus ~ (see variable suffix).  Example:

              ~> fn f { echo hello from f }
              ~> var v = $f~
              ~> $v
              hello from f

   Language pragmas: pragma {#pragma}
       The pragma special command can be used to set pragmas that affect the behavior of  the  Elvish  language.
       The syntax looks like:

              pragma <name> = <value>

       The name must appear literally.  The value must also appear literally, unless otherwise specified.

       Pragmas  apply  from  the  point  it  appears,  to  the end of the lexical scope it appears in, including
       subscopes.

       The following pragmas are available:

       • The unknown-command pragma affects the resolution of command heads, and can take  one  of  two  values,
         external (the default) and disallow.  See ordinary command for details.

         Note:  pragma  unknown-command  =  disallow  enables  a  style  where uses of external commands must be
         explicitly via the e: namespace.  You can also explicitly declare a set of  external  commands  to  use
         directly, like the following:

                pragma unknown-command = disallow
                var ls = $e:ls~
                var cat = $e:cat~
                # ls and cat can be used directly;
                # other external commands must be prefixed with e:

Pipeline

       A pipeline is formed by joining one or more commands together with the pipe sign (|).

       For  each  pair of adjacent commands a | b, the standard output of the left-hand command a (IO port 1) is
       connected to the standard input (IO port 0) of the right-hand command b.  Both the  file  and  the  value
       channel are connected, even if one of them is not used.

       Elvish  may  have  internal  buffering for both the file and the value channel, so a may be able to write
       bytes or values even if b is not reading them.  The exact buffer size is not specified.

       Command redirections are applied before the connection happens.  For instance, the following  writes  foo
       to a.txt instead of the output:

              ~> echo foo > a.txt | cat
              ~> cat a.txt
              foo

       A pipeline runs all of its command in parallel, and terminates when all of the commands have terminated.

   Pipeline exception
       If  one or more command in a pipeline throws an exception, the other commands will continue to execute as
       normal.  After all commands finish execution, an exception is thrown, the value of which depends  on  the
       number of commands that have thrown an exception:

       • If only one command has thrown an exception, that exception is rethrown.

       • If  more  than one commands have thrown exceptions, a “composite exception”, containing information all
         exceptions involved, is thrown.

       If a command threw an exception because it tried to write output when the next  command  has  terminated,
       that exception is suppressed when it is propagated to the pipeline.

       For  example, the put command throws an exception when trying to write to a closed pipe, so the following
       loop will terminate with an exception:

              ~> while $true { put foo } > &-
              Exception: port has no value output
              [tty 9], line 1: while $true { put foo } > &-

       However, if it appears in a pipeline before nop, the entire pipeline will not throw an exception:

              ~> while $true { put foo } | nop
              ~> # no exception thrown from previous line

       Internally, the put foo command still threw an exception, but since that exception was trying to write to
       output when nop already terminated, that exception was suppressed by the pipeline.

       This can be more clearly observed with the following code:

              ~> var r = $false
              ~> { while $true { put foo }; set r = $true } | nop
              ~> put $r
              ▶ $false

       The same mechanism works for builtin commands that write to the byte output:

              ~> var r = $false
              ~> { while $true { echo foo }; set r = $true } | nop
              ~> put $r
              ▶ $false

       On  UNIX,  if an external command was terminated by SIGPIPE, and Elvish detected that it terminated after
       the next command in the pipeline, such exceptions will also be suppressed by the pipeline.  For  example,
       the following pipeline does not throw an exception, despite the yes command being killed by SIGPIPE:

              ~> yes | head -n1
              y

   Background pipeline
       Adding  an  ampersand & to the end of a pipeline will cause it to be executed in the background.  In this
       case, the rest of the code chunk will continue to execute without waiting for  the  pipeline  to  finish.
       Exceptions thrown from the background pipeline do not affect the code chunk that contains it.

       When a background pipeline finishes, a message is printed to the terminal if the shell is interactive.

Code Chunk

       A  code  chunk is formed by joining zero or more pipelines together, separating them with either newlines
       or semicolons.

       Pipelines in a code chunk are executed in sequence.  If any pipeline throws an exception,  the  execution
       of the whole code chunk stops, propagating that exception.

Exception and Flow Commands

       Exceptions  have  similar semantics to those in Python or Java.  They can be thrown with the fail command
       and caught with either exception capture ?() or the try special command.

       If an external command exits with a non-zero status, Elvish treats that as an exception.

       Flow commands – break, continue and return – are ordinary  builtin  commands  that  raise  special  “flow
       control”  exceptions.   The  for, while, and peach commands capture break and continue, while fn modifies
       its closure to capture return.

       One interesting implication is that since  flow  commands  are  just  ordinary  commands  you  can  build
       functions on top of them.  For instance, this function breaks randomly:

              fn random-break {
                if eq (randint 2) 0 {
                  break
                }
              }

       The function random-break can then be used in for-loops and while-loops.

       Note  that  the  return  flow  control exception is only captured by functions defined with fn.  It falls
       through ordinary lambdas:

              fn f {
                {
                  # returns f, falling through the innermost lambda
                  return
                }
              }

Namespaces and Modules

       Like other modern programming languages, but unlike traditional shells, Elvish has a namespace  mechanism
       for preventing name collisions.

   Syntax
       Prepend namespace: to command names and variable names to specify the namespace.  The following code

              e:echo $E:PATH

       uses  the  echo  command from the e: namespace and the PATH variable from the E: namespace.  The colon is
       considered part of the namespace name.

       Namespaces may be nested; for example, calling edit:location:start first finds the edit:  namespace,  and
       then the location: namespace inside it, and then call the start function within the nested namespace.

   Special namespaces
       The following namespaces have special meanings to the language:

       • local: and up: refer to lexical scopes, and have been documented above.

       • e: refers to externals.  For instance, e:ls refers to the external command ls.

         Most  of  the  time you can rely on static resolution rules of ordinary commands and do not need to use
         this explicitly, unless a function defined by you (or an Elvish builtin) shadows an external command.

       • E: refers to environment variables.  For instance, $E:USER is the environment variable USER.

         This is always needed, because unlike command resolution, variable resolution does not fall  back  onto
         environment variables.

       • builtin: refers to builtin functions and variables.

         You don’t need to use this explicitly unless you have defined names that shadows builtin counterparts.

   Modules
       Apart  from the special namespaces, the most common usage of namespaces is to reference modules, reusable
       pieces of code that are either shipped with Elvish itself or defined by the user.

   Importing modules with use
       Modules are imported using the use special command.  It requires a module spec  and  allows  a  namespace
       alias:

              use $spec $alias?

       The  module  spec and the alias must both be a simple string literal.  Compound strings such as 'a'/b are
       not allowed.

       The module spec specifies which module to import.  The alias, if given, specifies the namespace to import
       the module under.  By default, the namespace is derived from the module spec by taking the part after the
       last slash.

       Module specs fall into three categories that are resolved in the following order:

       1. Relative: These are relative to the file containing the use command.

       2. User defined: These match a user defined module in a module search directory.

       3. Pre-defined: These match the name of a pre-defined module, such as math or str.

       If a module spec doesn’t match any of the above a “no such module” exception is raised.

       Examples:

              use str # imports the "str" module as "str:"
              use a/b/c # imports the "a/b/c" module as "c:"
              use a/b/c foo # imports the "a/b/c" module as "foo:"

   Pre-defined modules
       Elvish’s standard library provides the following pre-defined modules that can  be  imported  by  the  use
       command:

       • edit  is only available in interactive mode.  As a special case it does not need importing via use, but
         this may change in the future.

       • epm

       • math

       • path

       • platform

       • re

       • readline-binding

       • store

       • str

       • unix is only available on UNIX-like platforms (see $platform:is-unix)

   User-defined modules
       You can define your own modules in Elvish by putting them under one of the module search directories  and
       giving  them  a  .elv extension (but see relative imports for an alternative).  For instance, to define a
       module named a, you can put the following in ~/.config/elvish/lib/a.elv (on  Windows,  replace  ~/.config
       with ~\AppData\Roaming):

              ~> cat ~/.config/elvish/lib/a.elv
              echo "mod a loading"
              fn f {
                echo "f from mod a"
              }

       This module can now be imported by use a:

              ~> use a
              mod a loading
              ~> a:f
              f from mod a

       Similarly, a module defined in ~/.config/elvish/lib/x/y/z.elv can be imported by use x/y/z:

              ~> cat .config/elvish/lib/x/y/z.elv
              fn f {
                echo "f from x/y/z"
              }
              ~> use x/y/z
              ~> z:f
              f from x/y/z

       In general, a module defined in namespace will be the same as the file name (without the .elv extension).

       There  is  experimental  support  for  importing  modules  written  in  Go.   See  the project repository
       (https://github.com/elves/elvish) for details.

   Circular dependencies
       Circular dependencies are allowed but has an important restriction.  If a module a  contains  use  b  and
       module  b contains use a, the top-level statements in module b will only be able to access variables that
       are defined before the use b in module a; other variables will be $nil.

       On the other hand, functions in module b will have access to bindings in  module  a  after  it  is  fully
       evaluated.

       Examples:

              ~> cat a.elv
              var before = before
              use ./b
              var after = after
              ~> cat b.elv
              use ./a
              put $a:before $a:after
              fn f { put $a:before $a:after }
              ~> use ./a
              ▶ before
              ▶ $nil
              ~> use ./b
              ~> b:f
              ▶ before
              ▶ after

       Note  that  this  behavior  can  be different depending on whether the REPL imports a or b first.  In the
       previous example, if the REPL imports b first, it will have access to all the variables in a:

              ~> use ./b
              ▶ before
              ▶ after

       Note: Elvish caches imported modules.  If you are trying this locally, run a fresh Elvish  instance  with
       exec first.

       When  you  do need to have circular dependencies, it is best to avoid using variables from the modules in
       top-level statements, and only use them in functions.

   Relative imports
       The module spec may begin with ./ or ../ to introduce a relative import.  When use is invoked from a file
       this  will import the file relative to the location of the file.  When use is invoked from an interactive
       prompt, this will import the file relative to the current working directory.

   Scoping of imports
       Namespace imports are lexically scoped.  For instance, if you use a module within an inner scope,  it  is
       not available outside that scope:

              {
                  use some-mod
                  some-mod:some-func
              }
              some-mod:some-func # not valid

       The  imported  modules  themselves are also evaluated in a separate scope.  That means that functions and
       variables defined in the module does not pollute the default namespace, and vice versa.  For instance, if
       you define ls as a wrapper function in rc.elv:

              fn ls [@a]{
                  e:ls --color=auto $@a
              }

       That  definition  is  not visible in module files: ls will still refer to the external command ls, unless
       you shadow it in the very same module.

   Re-importing
       Modules are cached after one import.  Subsequent imports do not re-execute the module;  they  only  serve
       the  bring  it  into  the current scope.  Moreover, the cache is keyed by the path of the module, not the
       name   under   which   it   is   imported.    For   instance,   if   you   have    the    following    in
       ~/.config/elvish/lib/a/b.elv:

              echo importing

       The following code only prints one importing:

              { use a/b }
              use a/b # only brings mod into the lexical scope

       As does the following:

              use a/b
              use a/b alias