Elvish = Expressive Programming Language + Versatile Interactive Shell

Elvish: Expressive Programming Language + Versatile Interactive Shell

CI status FreeBSD test status gccgo test status Test Coverage Go Report Card GoDoc Twitter

Elvish is an expressive programming language and a versatile interactive shell, combined into one seamless package. It runs on Linux, BSDs, macOS and Windows.

Despite its pre-1.0 status, it is already suitable for most daily interactive use.

Visit the official website https://elv.sh for prebuilt binaries, blog posts, documentation and other resources.

User groups (all connected thanks to Matrix): Gitter Telegram Group #elvish on freenode #users:elves.sh

Building Elvish

Most users do not need to build Elvish from source. Prebuilt binaries for the latest commit are provided for Linux amd64, macOS amd64, Windows amd64, and many other platforms.

To build Elvish from source, you need

  • A supported OS: Linux, {Free,Net,Open}BSD, macOS, or Windows.

    NOTE: Windows support is experimental, and only Windows 10 is supported.

  • Go >= 1.15.

To build Elvish from source, follow these steps:

# 1. Start from any directory you want to store Elvish's source code
# 2. Clone the Git repository
git clone https://github.com/elves/elvish
# 3. Change into the repository
cd elvish
# 4. Build and install Elvish
make get

This will install Elvish to ~/go/bin; you might want to add it to your PATH.

To install it elsewhere, override GOBIN in the make command:

make get GOBIN=$PWD # Install to the repo root (use $pwd if running in Elvish)
make get GOBIN=/usr/local/bin # Install to /usr/local/bin

Note that GOBIN must be an absolute path.

Packaging Elvish

See PACKAGING.md for notes for packagers.

Contributing to Elvish

See CONTRIBUTING.md for notes for contributors.

Comments
  • SIGPIPE should not be considered a failure for data-producers in a pipeline

    SIGPIPE should not be considered a failure for data-producers in a pipeline

    This is debatable perhaps, and one could argue that it's a bug in most Unix commands that currently exist: But I think SIGPIPE should not be considered an error.

    The rationale is this: It's not uncommon to create pipelines that will terminate one or more of their commands with SIGPIPE - and typically this does not mean that anything has failed, but rather that one of the processes in the pipeline has stopped consuming values, and the program that was producing values for that process terminated as a result. I think it's fair to argue that these producers should not return an error status in this case, but the usual (default, in fact!) behavior is to terminate on an unhandled SIGPIPE, or catch the signal and terminate with the equivalent error code.

    So for instance, this produces a SIGPIPE: e:sort --random-sort /usr/share/dict/american-english | e:head -n 10 (Produce a list of random words)

    "head" reads the first 10 lines of inputs and then terminates, breaking the pipe. "sort" then receives SIGPIPE (or possibly, equivalent information via another means, depending on implementation) next time it writes to its output. Being unable to write out more data, it terminates. This is not an "exception"al condition, but rather a fundamental part of how stream processing works in shell pipelines.

    On the flip side of this argument: a "graceful" shutdown of a pipeline is not the only condition that can produce a SIGPIPE. A program could fail with SIGPIPE due to a purely internal error, or due to a connection loss, etc. This is why I consider my argument "debatable" and say "it could be considered a bug in the programs called by the shell" - If the SIGPIPE occurs in a scenario where it should not be treated as an error, then arguably "e:sort" and so on should not terminate with a non-zero exit code. I think it's a fair argument that people should simply recognize this and capture errors or use try/catch when running a pipeline that could reasonably be expected to SIGPIPE. But it's very typical for SIGPIPE to simply indicate that a pipeline has shut down. I don't think there is a set of criteria that can be applied to reliably distinguish between a "pipeline SIGPIPE" and an "internal error SIGPIPE" - the sequence in which processes terminate isn't a reliable indicator because SIGPIPE is triggered by the consumer closing its input, which could happen before termination - and if we said "SIGPIPEs aren't exceptions if they're generated by producers in a pipeline" there's always the chance that we're suppressing some true internal failure.

    (I think treating process exit codes as exceptions is a good idea, though a challenging one to resolve against a tradition in which exit codes mostly don't matter...)

  • A help system for the built-in commands

    A help system for the built-in commands

    As rasied on the user group, I asked about the possibility of having the documentation for each command available via the command line, so we could type e.g. > help randint and get the documentation that is already present in the go source code, e.g. https://github.com/elves/elvish/blob/master/pkg/eval/builtin_fn_num.go#L576

    Currently this documentation is in markdown. The simplest solution would be to convert from markdown to plain text, resulting in something like (for this I used pandoc -t plain):

    elvdoc:fn randint
    
        randint $low $high
    
    Output a pseudo-random integer in the half-open interval [$low, $high).
    Example:
    
        ~> # Emulate dice
        randint 1 7
    

    This would already be a big advance. Of course for cherries on top it would be nice if links could be preserved and code could get syntax highlighting. I do not know anything about go and how feasible this would be, I assume there are many markdown packages available...

  • Consider following XDG base directory spec

    Consider following XDG base directory spec

    The docs show the default config location is ~/.elvish/rc.elv. Please consider following the XDG base directory spec. The default location would then be ~/.config/elvish/rc.elv.

    Moving configs into a folder helps reduce clutter. In the last few years many tools have slowly been adding support: XDG Base Directory support. For comparison, fish shell uses ~/.config/fish/config.fish as its startup file, and lazy-loaded functions go in ~/.config/fish/functions/.

    On macOS most tools generally continue using ~/.config as the default location. However, should you choose to follow Apple's guidelines (macOS Library Directory Details), you would use ~/Library/Application Support/elvish/ to place any configs, data, and files. Two other commonly used folders are Caches (~/Library/Caches/elvish/) and Logs (~/Library/Logs/elvish/).

  • Support for 'cd -'

    Support for 'cd -'

    In bash, cd - expands to cd $OLDPWD, where $OLDPWD holds the previous working directory. It would be nice to have this in elvish. zsh extends on this by providing cd -N (where N is in integer) to access arbitrary 'directory history' items, which may also be worth adding.

  • `except` must be in the same line as `}`

    `except` must be in the same line as `}`

    This code is ok:

    try { 
        
        fail bad 
    
    } except e {            # <= ok!
    
        put $e 
    }
    

    But if you move except to the next line

    try { 
        
        fail bad 
    }
    except e {              # <= here
    
        put $e 
    }
    

    you get this very misterious error:

    # compilation error: variable $e not found
    # /home/tfga/sbin/exceptBug.elv, line 11:     put $e
    

    Would it be possible to lift this restriction?

    In any case, the error message is very puzzling. It took me a long time to figured out what exactly I had done wrong.

  • Require explicit variable declarations with

    Require explicit variable declarations with "var"

    Currently, variables do not require explicit declarations; a variable is created when they get assigned for the first time. One drawback of this approach is that you can accidentally assign variables in outer scopes when you intend to make a new variable, like

    i = 10
    {
      ...
      # in a deeply-nested scope
      {
        i = 100
      }
      ...
    }
    

    This can be a nuisance but most of the time it is not too problematic.

    What is problematic, though, is that this makes introducing new builtin variables hard. For instance, today there is no builtin variable called foo, so foo = lorem always creates a new variable. But if a builtin variable foo is to be introduced, the semantics of foo = lorem changes to modifying the builtin variable, which likely has some unintended side effect.

    Hence I would like to make variable declarations explicit: use let for readonly variables and var for read-write variables. The syntax will simply be:

    let x = foo # creates readonly variable x
    var y = bar # creates read-write variable y
    

    Since this is a far-reaching and mechanical change, a script should be provided for rewriting code to use the new syntax. Timeline:

    1. Before release of 0.12, new syntax is supported and an automatic rewrite tool is provided.
    2. Before release of 0.13, old syntax is removed;

    Edit: as of 2020-08-17, the plan has been changed to support the new syntax in 0.15.0 and remove the old syntax in 0.16.0.

    The proposed declarator for immutable variables has also been changed to val, instead of let.

    Edit: as of 2021-10-12, support for val is tracked separately in #1407.

  • RFC: Add a simpler control struct for executing a loop N times?

    RFC: Add a simpler control struct for executing a loop N times?

    The only aspect of Elvish that still annoys me is writing simple loops to be executed N times. Go has a C like construct for this case:

    for i := 0; i < 10; i++ {
    	f(i)
    }
    

    While in Elvish that would be written thusly:

    for i [(range 10)] {
        f(i)
    }
    

    The Elvish formulation is more succinct. But it's also considerably less efficient (especially for large values of N) since it requires instantiating a list then ranging over it. I'm not suggesting adding the Go syntax but it would be nice if there was an even simpler, more efficient, way to perform this common operation. The simplest, most Elvish, solution I can think of is to augment the builtin range command to accept an optional argument that takes a lambda. Thus allowing the above to be written like this:

    range 10 {|i|
        f(i)
    }
    
  • Use XDG runtime directory on Unix when present

    Use XDG runtime directory on Unix when present

    This pull-request uses $XDG_RUNTIME_DIR on Unix to store the runtime files. If $XDG_RUNTIME_DIR is not set it falls back to the old location (e.g.: /tmp/elvish-$uid).

    This is a small first step towards XDG compliance on Unix (#383).

  • Recognize Shift-Alt-arrow and Cmd-Alt-arrow on iTerm2

    Recognize Shift-Alt-arrow and Cmd-Alt-arrow on iTerm2

    If I hit Shift-Alt-Up, I get this error:

    error when reading terminal: bad CSI: "\x1b[1;10A"
    

    similar error messages appear with the other arrow keys (with the final A replaced by B, C or D).

    Something similar happens with Command-Alt arrow combinations (with 10 replaced by 9).

    This is in iTerm2 on a Mac. I assume the resulting codes are more or less standard ones. It would be good if they were added to elvish's repertoire of recognized byte sequences, so we can bind to these keystrokes.

  • sort function

    sort function

    It would be nice to have a sorting function in Elvish (maybe named something else, to avoid conflicting with the standard Unix sort command). Ideally it would support structured data, and allow specifying a sorting function (like Clojure's sort-by).

  • Daemon connectivity problems

    Daemon connectivity problems

    after installing elvish on bash/windows subsystem for linux I am greeted with this warning:

    warning: socket exists but not responding version RPC: dial unix /tmp/elvish-1000/sock: connect: connection refused
    

    followed by this error:

    Failed to initialize command history. Disabled.
    

    this question is did I do something incorrectly, or does this stem from the wsl?

  • WIP pkg/edit: implement edit:history:accept

    WIP pkg/edit: implement edit:history:accept

    It's api to and update codebuffer with current entry in histwalk mode.

    Resolves #1636

    With this new api, I was able to switch to command-mode directly from histwalk mode.

    set edit:history:binding["Ctrl-["] =  { edit:history:accept; edit:close-mode; edit:command:start }
    

    I'm not familiar with elvish code base. Please let me know it this api itself and it's implementation is correct. I couldn't find a way to get codebuffer in the test case. Wish to get some help.

  • Expand the description of setting environment variables

    Expand the description of setting environment variables

    Elvish used to allow the foo=bar cmd syntax similar to other shells. This has changed and as it is a common motif I thought it would be good to mention it in the elvish<->bash comparison table (at least me as a generic end-user often goes there to work out how to do things). I added both the { tmp ... } option and also using env command as a shortcut, although I know this is not strictly "elvish" syntax...

    I also thought that as environment variable are often important for many shell tasks, expanding the Setting variables section to detail the use of builtins like set-env or the E: namespace will help new users orient themselves.

  • Way to stop history mode and start command mode without clearing line.

    Way to stop history mode and start command mode without clearing line.

    I wanted to close history navigation and start command(vi) mode to edit command in the history.

    Up -> ESC

    But it clears the line. So I tried this but it doesn't work properly.

    set edit:history:binding["Ctrl-["] =  { edit:command:start }
    
    image

    And this doesn't work as edit:close-mode clears the line.

    set edit:history:binding["Ctrl-["] =  { edit:close-mode; edit:command:start }
    

    I am searching for some api to preserve current line in history mode. Or let me know if anyone knows the trick. I'm not sure some new api should be introduced for this.

  • The `eq` command fails to correctly compare exception objects

    The `eq` command fails to correctly compare exception objects

    There was a recent discussion on the IM channels about how to deal with the exception raised by builtins like break, continue, and return. That caused me to notice that this fails to produce the expected, true, result:

    elvish> var e = ?(break)
    elvish> eq ?(break) $e
    ▶ $false
    

    That is, obviously, a contrived and not particularly interesting example in isolation. But it illustrates that the eq command fails to correctly compare exception objects such as raised by the control flow builtins. Which makes it impossible for examples like this (again, contrived and simplified) to work as expected:

    elvish> try { break } catch e { if (eq ?(break) $e) { put "break captured" } }
    
  • Clarify the order of `$f[opt-names]` and `$f[opt-values]`

    Clarify the order of `$f[opt-names]` and `$f[opt-values]`

    Currently those values in the function pseudo-map contain lists in the order exactly as defined - in contrast to make-map, for example, which seems to order its keys alphabetically:

    ~> put [c 3] [a 1] [b 2] | make-map
    ▶ [&a=1 &b=2 &c=3]
    ~> put {|&c=3 &a=1 &b=2|}[opt-names]
    ▶ [c a b]
    

    I feel that this should be clarified in the documentation. Map is defined as "a value containing unordered key-value pairs", so the first result is to be (not) expected. But since the "mapping" of option values and names is supplied in the pseudo-map as two lists, it feels like it should match the definition order. Either way, clarification would be much appreciated.

    For context, my current use-case are with-statements (as in Python). One example:

     fn with-temp-dir { |&parent='' f|
        use path
        use util
    
        var @args = (each { |name|
            path:temp-dir &dir=$parent $name'-*'
        } $f[arg-names])
        var @opt_values = (each { |name|
            path:temp-dir &dir=$parent $name'-*'
        } $f[opt-defaults])
    
        defer {
            { all $args; all $opt_values } | each { |dir|
                rm -rf $dir
            }
        }
    
        var opts = (util:zip $f[opt-names] $opt_values | make-map)
        call $f $args $opts
    }
    
    ~> with-temp-dir {|cyan magenta| put $cyan $magenta}
    ▶ /tmp/cyan-3550046558
    ▶ /tmp/magenta-93444558
    ~> with-temp-dir {|yellow &dark=black| put $yellow $dark}
    ▶ /tmp/yellow-3399318214
    ▶ /tmp/black-2816232334
    

    (by the way, any critique/suggestions regarding this are much appreciated, but having possibility of defining things like this feels really nice)

    I'm sorry for ruining 256 open issues for something this trivial. :-)

  • Exploding an expression: interpretation of the ‘@’ modifier

    Exploding an expression: interpretation of the ‘@’ modifier

    To set the stage, for a variable v, the meaning of $@v and set @v = value … is clear:

    ⬥ var @v = a b c
    ⬥ put $@v
    ⮕ a
    ⮕ b
    ⮕ c
    

    Note that $@v returns what we gave to set @v.

    But involve some array references, and things are not as clear:

    ⬥ var @v = [a b c] [d e f] [g h i]
    ⬥ set @v[1] = x y z
    ⬥ put $v     # produces expected result:
    ⮕ [[a b c] [x y z] [g h i]]
    ⬥ put $@v[1] # surprise (to me at least):
    ⮕ b
    ⮕ y
    ⮕ h
    

    This breaks two reasonable expectations, IMO:

    • Expanding $⟨something⟩ should reflect the RHS of a previous set ⟨something⟩ = …
    • The construct $@⟨something⟩ acts like syntactic sugar for (all $⟨something⟩)

    Of course, this depends on what you see as the ⟨something⟩ in a compound expression. What is most jarring is the lack of symmetry between the assignment and the expansion.

    So this is my suggestion:

    Change the meaning of $@variable[⟨index-expression⟩]… to evaluate the whole expression without the @, then explode the result(s).

    Of course this is breaking change, so it needs to considered carefully. But I doubt there is much code out there that relies on the current behaviour.

    • After such a change, replacing any $@variable[⟨index-expression⟩]… by {$@variable}[⟨index-expression⟩]… will result in the old behaviour. This should be fairly easy to automate. Also, since the result of such an expression is a bit tricky to figure out, I think the extra curly braces will help to make clear that something funny is going on.
A compiler for the ReCT programming language written in Golang

ReCT-Go-Compiler A compiler for the ReCT programming language written in Golang

Nov 30, 2022
Starlark in Go: the Starlark configuration language, implemented in Go

Starlark in Go This is the home of the Starlark in Go project. Starlark in Go is an interpreter for Starlark, implemented in Go. Starlark was formerly

Jan 2, 2023
A fast script language for Go
A fast script language for Go

The Tengo Language Tengo is a small, dynamic, fast, secure script language for Go. Tengo is fast and secure because it's compiled/executed as bytecode

Dec 30, 2022
Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. https://vlang.io
Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. https://vlang.io

The V Programming Language vlang.io | Docs | Changelog | Speed | Contributing & compiler design Key Features of V Simplicity: the language can be lear

Jan 4, 2023
Compiler for a small language into x86-64 Assembly

Compiler This project is a small compiler, that compiles my own little language into X86-64 Assembly. It then uses yasm and ld to assemble and link in

Dec 13, 2022
Oak is an expressive, dynamically typed programming language

Oak ?? Oak is an expressive, dynamically typed programming language. It takes the best parts of my experience with Ink, and adds what I missed and rem

Dec 30, 2022
Sand is the next, versatile, high-level compiled or interpreted language that's easy to learn and performant to run.

Sand is the newest, dynamically typed, interpreted programming language. Table of Contents History Project Stats History Sand was created as part of @

Mar 13, 2022
Floppa programming language inspired by the brainf*ck programming language. Created just for fun and you can convert your brainf*ck code to floppa code.

Floppa Programming Language Created just for fun. But if you want to contribute, why not? Floppa p.l. inspired by the brainf*ck programming language.

Oct 20, 2022
T# Programming Language. Something like Porth, Forth but written in Go. Stack-oriented programming language.

The T# Programming Language WARNING! THIS LANGUAGE IS A WORK IN PROGRESS! ANYTHING CAN CHANGE AT ANY MOMENT WITHOUT ANY NOTICE! Something like Forth a

Jun 29, 2022
Yayx programming language is begginer friendly programming language.
Yayx programming language is begginer friendly programming language.

Yayx Yayx programming language is begginer friendly programming language. What have yayx: Easy syntax Dynamic types Can be compiled to outhers program

Dec 27, 2021
Yayx programming language is begginer friendly programming language.

Yayx Yayx programming language is begginer friendly programming language. What have yayx: Easy syntax Dynamic types Can be compiled to outhers program

May 20, 2022
A versatile library for building CLI applications in Go

mow.cli Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation placed o

Dec 28, 2022
Powerful and versatile MIME sniffing package using pre-compiled glob patterns, magic number signatures, XML document namespaces, and tree magic for mounted volumes, generated from the XDG shared-mime-info database.

mimemagic Powerful and versatile MIME sniffing package using pre-compiled glob patterns, magic number signatures, xml document namespaces, and tree ma

Nov 3, 2022
Versatile Go code generator.
Versatile Go code generator.

Generis Versatile Go code generator. Description Generis is a lightweight code preprocessor adding the following features to the Go language : Generic

Nov 30, 2022
Sabakan is a versatile network boot server designed for large on-premise data centers.
Sabakan is a versatile network boot server designed for large on-premise data centers.

Sabakan is a versatile network boot server designed for large on-premise data centers. Currently, it is made only for Flatcar Container Linux.

Jan 2, 2023
Automatically spawn a reverse shell fully interactive for Linux or Windows victim
Automatically spawn a reverse shell fully interactive for Linux or Windows victim

Girsh (Golang Interactive Reverse SHell) Who didn't get bored of manually typing the few lines to upgrade a reverse shell to a full interactive revers

Dec 14, 2022
Generate an interactive, autocompleting shell for any Cobra CLI
Generate an interactive, autocompleting shell for any Cobra CLI

cobra-shell Description Leverages the Cobra completion API to generate an interactive shell for any Cobra CLI, powered by go-prompt. On-the-fly autoco

Dec 19, 2022
An interactive shell for go application

goshell An interactive shell for go application in normal mode ctrl-c break exec

Dec 15, 2022
A simple CLI based rock-paper-scissors game created in GO with interactive shell prompt.

rock-paper-scissors A simple CLI (Command Line Interface) based rock-paper-scissors game with interactive shell prompt. Language Download Grab a binar

Oct 9, 2022
painless task queue manager for shell commands with an intuitive cli interface (execute shell commands in distributed cloud-native queue manager).

EXEQ DOCS STILL IN PROGRESS. Execute shell commands in queues via cli or http interface. Features Simple intuitive tiny cli app. Modular queue backend

Dec 14, 2022