elvish/README.md

198 lines
5.7 KiB
Markdown
Raw Normal View History

2013-10-06 15:35:27 +08:00
An experimental Unix shell
==========================
2013-06-16 16:45:22 +08:00
2013-09-21 21:05:27 +08:00
This is a work in progress. Things may change and/or break without notice. You
have been warned...
2013-12-29 15:04:37 +08:00
The Editor
----------
2014-01-08 18:52:09 +08:00
Those marked with :white_check_mark: are implemeneted (but could be broken from time to
time).
2013-12-29 15:04:37 +08:00
Like fish:
2014-01-08 18:52:09 +08:00
* Syntax highlighting :white_check_mark:
2013-12-29 15:04:37 +08:00
* Auto-suggestion
Like zsh:
2014-01-08 18:52:09 +08:00
* Right-hand-side prompt :white_check_mark:
* Dropdown menu completion :white_check_mark:
2013-12-29 15:04:37 +08:00
* Programmable line editor
And:
* A vi keybinding that makes sense
* More intuive multiline editing
* An intuive method to save typed snippets into a script
The Language
------------
2014-01-08 18:52:09 +08:00
(Like the previous section, only those marked with :white_check_mark: have been implemented.)
2013-12-29 15:20:49 +08:00
2014-01-08 18:52:09 +08:00
* Running external programs and pipelines, of course: :white_check_mark:
2013-12-29 15:12:01 +08:00
```
> vim README.md
2013-12-29 15:20:49 +08:00
...
2013-12-29 15:12:01 +08:00
> cat -v /dev/random
2013-12-29 15:20:49 +08:00
...
> dmesg | grep bar
...
2013-12-29 15:12:01 +08:00
```
2013-12-29 15:04:37 +08:00
* Basically prefix syntax without the outmost pair of parentheses (`>`
represents the prompt):
2013-12-29 15:07:29 +08:00
```
> + 1 2
3
> * (+ 1 2) 3
9
```
2013-12-29 15:04:37 +08:00
* Use backquote for literal string (so that you can write both single and
2014-01-08 18:52:09 +08:00
double quotes inside), double backquotes for a literal backquote: :white_check_mark:
2013-12-29 15:07:29 +08:00
```
> echo `"He's dead, Jim."`
"He's dead, Jim."
> echo ```He's dead, Jim."`
``He's dead, Jim."
```
2013-12-29 15:04:37 +08:00
* Barewords are string literals:
2013-12-29 15:07:29 +08:00
```
> = a `a`
true
```
2013-12-29 15:04:37 +08:00
* Tables are a hybrid of array and hash (a la Lua); tables are first-class
2014-01-08 18:52:09 +08:00
values: :white_check_mark:
2013-12-29 15:07:29 +08:00
```
2014-01-08 18:52:09 +08:00
> println [a b c &key value]
2013-12-29 15:07:29 +08:00
[a b c &key value]
2014-01-08 18:52:09 +08:00
> println [a b c &key value][0]
2013-12-29 15:07:29 +08:00
a
2014-01-08 18:52:09 +08:00
> println [a b c &key value][key]
2013-12-29 15:07:29 +08:00
value
```
2013-12-29 15:04:37 +08:00
2014-01-08 18:52:09 +08:00
* Declare variable with `var`, set value with `set`; `var` also serve as a
shorthand of var-set combo: :white_check_mark:
2013-12-29 15:07:29 +08:00
```
> var v
> set v = [foo bar]
2014-01-08 18:52:09 +08:00
> var u = [foo bar] # equivalent
2013-12-29 15:07:29 +08:00
```
2013-12-29 15:04:37 +08:00
* First-class closures, lisp-like functional programming:
2013-12-29 15:07:29 +08:00
```
> map {|x| * 2 $x} [1 2 3]
[2 4 6]
2013-12-30 16:23:22 +08:00
> filter {|x| > $x 2} [1 2 3 4 5]
2013-12-29 15:07:29 +08:00
[3 4 5]
2013-12-30 16:23:22 +08:00
> map {|x| * 2 $x} (filter {|x| > $x 2} [1 2 3 4 5])
2013-12-29 15:07:29 +08:00
```
2013-12-29 15:04:37 +08:00
2014-01-08 18:52:09 +08:00
* Get rid of lots of irritating superfluous parentheses with pipelines (`put`
is the builtin for outputting compound data):
2013-12-29 15:07:29 +08:00
```
2013-12-30 16:23:22 +08:00
> put [1 2 3 4 5] | filter {|x| > $x 2} | map {|x| * 2 $x}
2013-12-29 15:07:29 +08:00
[6 8 10]
```
2013-12-29 15:04:37 +08:00
* Use the table `$env` for environmental variables:
2013-12-29 15:07:29 +08:00
```
> put $env[HOME]
/home/xiaq
> set env[PATH] = $env[PATH]:/bin
```
2013-12-29 15:04:37 +08:00
There are many parts of the language that is not yet decided. See TODO.md for
a list of things I'm currently thinking about.
2013-10-06 15:36:41 +08:00
Motivation
2013-09-22 18:49:07 +08:00
----------
The basic idea is to have a shell that is also a decant programming language.
Shells have long rejected such things as data structure beyond text arrays.
Some support associative arrays, which may be assigned to variables but not
passed as arguments to builtins or shell functions, making the use of them
very tedious.
The lesson of Tcl has taught us the "everything is (unstructured) text"
philosophy, which is also the idea underpinning classical Unix pipelines, is
too limited for proper programming. Indeed, the power of Tcl often lies in the
dynamic interpretation of text, assuming some predefined structure in it. Yet
2013-10-06 15:35:27 +08:00
with shells, where such facilities are basically nonexistent, it requires
great discipline to build maintainable software. Traditional initscripts,
program wrapper scripts and some of the more tricky tab-completion scripts are
notable examples.
2013-09-22 18:49:07 +08:00
However, the shell does come with a very powerful abstraction - the pipeline.
It is basically a facility for concatenative programming. Consider the
following code in lisp:
```
(set coll' (map f (filter pred coll)))
```
Written concatenatively, this can be - assuming `put` puts the argument to
output (akin to `echo`), and `set` can take data from input in place of in the
argument list:
```
put $coll | filter pred | map f | set coll2
```
The concatenative approach is much more natural (try reading both versions
aloud).
2013-10-06 15:35:27 +08:00
Another defining character of shells is the easiness to invoke external
programs; comparing `subprocess.call(['ls', '-l'])` with `ls -l` - the
difference is clear. Being easy to invoking external programs is what makes
shells shells *in its original sense*, i.e. user interface to the operating
system.
Putting together, the idea of this new Unix shell is starting from pipelines
and external program interaction, adding in programming-language-ish flavors,
towards building a decant programming language with a friendly (command line)
2013-11-16 19:30:04 +08:00
user interface, suitable for both *back-of-the-envolope* computation **and**
building more complex (but maybe not too complex!) software.
2013-10-06 15:35:27 +08:00
This is not exactly an ambitious goal, but it's something I have always
dreamed of.
2013-09-22 18:49:07 +08:00
2013-09-18 16:45:18 +08:00
Building
--------
2013-09-21 21:05:27 +08:00
You need go >= 1.1 to build this. Just run `make`. The resulting binary is
called `das`.
Name
----
2013-09-21 21:08:54 +08:00
Indeed, **das** is not a very good name for a Unix shell. The name is actually
a corrupted form of **dash**, which also happens to be the German definite
neuter article.
2013-11-16 19:30:04 +08:00
I have some other ideas in mind. One of them is **elv**, since I found
"elvish" to be a great adjective - I can't use "elf" though, since it's
already [taken](http://www.cs.cmu.edu/~fp/elf.html) and may be confused with
the well known [file
2013-09-21 21:05:27 +08:00
format](http://en.wikipedia.org/wiki/Executable_and_Linkable_Format).
Another possible source of names is the names of actual seashells; but my
English vocabulary is too small for me to recall any beyond "nautilus", which
is both too long and already taken.
I'm not avoiding names ending in "sh" though; but I do find "bash" to be a
2013-11-16 19:30:04 +08:00
terrible name. "fish" is clever, but it has a quite [unpleasant
adjective](https://en.wiktionary.org/wiki/fishy). I find "dash" really good
though, which is why it came to my mind :).
2013-09-18 16:45:18 +08:00
2013-07-26 14:46:24 +08:00
License
-------
BSD 2-clause license. See LICENSE for a copy.