Powerful scripting language & versatile interactive shell add sylixos support.
Go to file
xofyarg deb83e2f8a Ignore OK when printing PipelineError (#361)
The program crashes when trying to print PipelineError if there's an
OK inside since its content is barely empty. Simple ignore the OK
value will fix it.

Or maybe we should print that out as well to better align with the
pipeline?
2017-06-19 22:57:51 +02:00
daemon store: Store.AddCmd returns sequence of added command. 2017-06-07 01:10:40 +01:00
edit Fix crash when display invalid history (#360) 2017-06-18 17:03:32 +02:00
eval Ignore OK when printing PipelineError (#361) 2017-06-19 22:57:51 +02:00
getopt Fix go-vet errors. 2017-05-21 23:20:55 +01:00
glob Add a helper function for testing in a tempdir. 2017-05-23 05:40:49 +01:00
parse parse: Expose Parser. 2017-05-31 22:46:26 +01:00
shell Add empty tests to get accurate coverage. 2017-06-01 00:17:04 +01:00
store store: Fix test case. 2017-06-07 11:07:04 +01:00
sys Reorganize to prepare for adding web interface. 2017-05-28 17:59:50 +01:00
util Experimental support for subseq matcher in compl mode. 2017-05-24 01:25:10 +01:00
vendor Use persistent list as the underlying data structure for lists. 2017-06-14 01:46:19 +01:00
web web: Autoscroll to bottom of page. 2017-06-07 02:28:39 +01:00
.gitattributes Use .gitattributes to filter go sources through goimports 2014-02-10 12:41:16 +08:00
.gitignore Updated .gitignore (#303) 2017-01-12 00:17:28 +00:00
.travis.yml Let Travis build with go 1.8. 2017-05-23 23:43:38 +01:00
CONTRIBUTING.md Move the "contributing" section to a shiny CONTRIBUTING.md file 2016-02-19 00:13:35 +01:00
Dockerfile update Dockerfile 2016-02-09 16:43:58 +08:00
Gopkg.lock Use persistent list as the underlying data structure for lists. 2017-06-14 01:46:19 +01:00
Gopkg.toml Use the "dep" tool to manage dependencies. 2017-06-12 23:06:30 +01:00
LICENSE Project rename: das -> elvish 2014-01-29 18:44:07 +08:00
main_test.go Add empty tests to get accurate coverage. 2017-06-01 00:17:04 +01:00
main.go Add a web frontend that currently doesn't actually execute code. 2017-05-29 00:54:34 +01:00
Makefile Makefile: more usable. 2017-06-11 23:16:34 +01:00
README.md Add another useless badge, the Go Report Card. 2017-05-21 17:41:56 +01:00

A friendly and expressive Unix shell

GoDoc Build Status on Travis Coverage Status Go Report Card License

This project aims to explore the potentials of the Unix shell. It is a work in progress; things will change without warning. The issues list contains many things I'm working on.

Discuss Elvish by joining #elvish on freenode, the Gitter room or the international user group on Telegram. Thanks to fishroom, the IRC channel, Gitter room and Telegram group are interconnected. Chinese speakers are also welcome in #elvish-zh on freenode, or the Chinese user group on Telegram!

Screenshot

Elvish looks like this:

syntax highlighting

Prebuilt binaries

64-bit Linux: curl -s https://dl.elvish.io/elvish-linux.tar.gz | sudo tar vxz -C /usr/local/bin

64-bit Mac OS X: curl -s https://dl.elvish.io/elvish-osx.tar.gz | sudo tar vxz -C /usr/local/bin

Try cn.dl.elvish.io if you are in China and the download is too slow. (In the future dl.elvish.io will resolve to a Chinese IP for users from China, but that hasn't happended yet.)

See also Building Elvish.

RPM package

RPM Package for Fedora is available in FZUG Repo.

First add the FZUG repo:

dnf config-manager --add-repo=http://repo.fdzh.org/FZUG/FZUG.repo

Then install Elvish:

dnf install elvish

Getting Started

Note: Elvish is constantly tested under Terminal.app, libvte-based terminals and tmux. Some function keys might not work in other terminals like xterm (#328).

Elvish mimics bash and zsh in a lot of places. The following shows some key differences and highlights, as well as some common tasks:

  • Put your startup script in ~/.elvish/rc.elv. There is no alias yet, but you can achieve the goal by defining a function:

    fn ls { e:ls --color $@ }
    

    The e: prefix (for "external") ensures that the external command named ls will be called. Otherwise this definition will result in infinite recursion.

  • The left and right prompts can be customized by assigning functions to le:prompt and le:rprompt. Their outputs are concatenated (with no spaces in between) before being used as the respective prompts. The following simulates the default prompts but uses fancy Unicode:

    # "tilde-abbr" abbreviates home directory to a tilde.
    le:prompt = { tilde-abbr $pwd; put '❱ ' }
    # "constantly" returns a function that always writes the same value(s) to output.
    le:rprompt = (constantly `whoami``hostname`)
    
  • Press Up to search through history. It uses what you have typed to do prefix match. To cancel, press Escape.

    history

  • Press Tab to start completion. Use arrow key and Tab to select the candidate; press Enter, or just continue typing to accept. To cancel, press Escape.

    tab completion

  • Press Ctrl-N to start navigation mode. Press Ctrl-H to show hidden files; press again to hide. Press tab to append selected filename to your command. Likewise, pressing Escape gets you back to the default (insert) mode.

    navigation mode

  • Try typing echo [ and press Enter. Elvish knows that the command is unfinished due to the unclosed [ and inserts a newline instead of accepting the command. Moreover, common errors like syntax errors and missing variables are highlighted in real time.

  • Elvish remembers which directories you have visited. Press Ctrl-L to list visited directories. Like in completion, use Up, Down and Tab to navigate and use Enter to accept (which cds into the selected directory). Press Escape to cancel.

    location mode

    Type to filter:

    location mode, filtering

    The filtering algorithm takes your filter and adds ** to both sides of each path component. So g/di becomes pattern **g**/**di**, so it matches /home/xiaq/go/elves/elvish/edit.

  • NOTE: Default key bindings as listed above are subject to change in the future; but the functionality will not go away.

  • Elvish doesn't support history expansion like !!. Instead, it has a "bang mode", triggered by Alt-,, that provides the same functionality. For example, if you typed a command but forgot to add sudo, you can then type sudo and press Alt-, twice to fix it:

    bang mode

  • Lists look like [a b c], and maps look like [&key1=value1 &key2=value2]. Unlike other shells, a list never expands to multiple words, unless you explicitly explode it by prefixing the variable name with @:

    ~> li = [1 2 3]
    ~> put $li[1 2 3]
    ~> put $@li
    ▶ 123
    ~> map = [&k1=v1 &k2=v2]
    ~> echo $map[k1]
    v1
    
  • Environment variables live in a separate E: (for "environment") namespace and must be explicitly qualified:

    ~> put $E:HOME
    ▶ /home/xiaq
    ~> E:PATH=$E:PATH":/bin"
    
  • You can manipulate search paths through the special list $paths, which is synced with $E:PATH:

    ~> echo $paths
    [/bin /sbin]
    ~> paths = [/opt/bin $@paths /usr/bin]
    ~> echo $paths
    [/opt/bin /bin /sbin /usr/bin]
    ~> echo $E:PATH
    /opt/bin:/bin:/sbin:/usr/bin
    
  • You can manipulate the keybinding through the map $le:binding. For example, this binds Ctrl-L to clearing the terminal: le:binding[insert][Ctrl-L]={ clear > /dev/tty }. The first index is the mode and the second is the key. (Yes, the braces enclose a lambda.)

    Use pprint $le:binding to get a nice (albeit long) view of the current keybinding.

    NOTE: Bindings for letters modified by Alt are case-sensitive. For instance, Alt-a means pressing Alt and A, while Alt-A means pressing Alt, Shift and A.

  • There is no interpolation inside double quotes (yet). Use implicit string concatenation:

    ~> name = xiaq
    ~> echo "My name is "$name"."
    My name is xiaq.
    
  • Elementary floating-point arithmetics as well as comparisons are builtin. Unfortunately, you have to use prefix notation:

    ~> + 1 23
    ~> / `* 2 3` 4
    ▶ 1.5
    ~> / (* 2 3) 4 # parentheses are equivalent to backquotes, but look nicer in arithmetics
    ▶ 1.5
    ~> > 1 2 # ">" may be used as a command name
    ✗
    ~> < 1 2 # "<" may also be used as a command name; silence means "true"
    
  • Functions are defined with fn. You can name arguments:

    ~> fn square [x]{
         * $x $x
       }
    ~> square 416
    
  • Output of some builtin commands start with a funny "▶". It is not part of the output itself, but shows that such commands output a stream of values instead of bytes. As such, their internal structures as well as boundaries between values are preserved. This allows us to manipulate structured data in the shell; more on this later.

Building Elvish

Go >= 1.6 is required. Linux is fully supported. It is likely to work on BSDs and Mac OS X. Windows is not supported yet.

Elvish is a go-gettable package, and can be installed using go get github.com/elves/elvish.

If you are lazy and use bash or zsh now, here is something you can copy-paste into your terminal:

export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
mkdir -p $GOPATH

go get github.com/elves/elvish

for f in ~/.bashrc ~/.zshrc; do
    printf 'export %s=%s\n' GOPATH '$HOME/go' PATH '$PATH:$GOPATH/bin' >> $f
done

How To Write Go Code explains how $GOPATH works.

For macOS users, you can build Elvish via homebrew:

brew install --HEAD elvish

Name

In roguelikes, items made by the elves have a reputation of high quality. These are usually called elven items, but I chose "elvish" because it ends with "sh". It also rhymes with fish, one of shells that influenced the philosophy of Elvish.

The word "Elvish" should be capitalized like a proper noun. However, when referring to the elvish command, use it in lower case with fixed-width font.

Whoever practices the elvish way by either contributing to it or simply using it is called an elf. (You might have guessed this from the name of the GitHub organization.) The official adjective for elvish (as in "Pythonic" for Python, "Rubyesque" for Ruby) is "elven".