A Haskell shell.
Here lies a prototype/experiment for the following question: can the normal Haskell REPL make a passable shell if it has file completion and directory awareness?
It's a simple read-eval-print loop for Haskell that has some simple awareness of the current directory and completion works. I whipped this up in a few hours, it's only a couple hundred lines of code.
It looks like this:
Welcome to Hell!
chris:~/$ ls
Backups Desktop Downloads Emacs Mail Pictures Renoise Samples
Books Documents Dropbox Flash Org Projects Repos Scripts
It has some UNIX basics:
chris:~/$ cd "Projects/hell/"
chris:~/Projects/hell$ ls
dist examples hell.cabal LICENSE README.md src TAGS
chris:~/Projects/hell$ ls "-a"
. .. dist examples .ghci .git .gitignore hell.cabal LICENSE README.md
All functions are based on shell-conduit and are variadic. They are generated by taking all binaries in your PATH.
The only exception (so far) is cd
. There is no binary called cd
in
POSIX because it is a shell concept.
It uses the GHC API (so please submit a pull request if it doesn't work with your GHC version) and the Haskeline package to make a simple read-eval-print loop, keeping track of any current directory changes. The Haskeline package does completion at the prompt built-in.
It tries to run the line as an IO a
statement:
chris:~/$ cd "."
If that's the wrong
type, it runs it as a shell-conduit Segment
:
chris:~/$ ls $| grep "E"
LICENSE
README.md
Or finally it evaluates
it as an expression, printing the result with print
:
chris:~/$ 2 * 3
forall a. GHC.Num.Num a => a
6
I think it's pretty neat to have Haskell evaluation in your shell. I often open GHCi to do little arithmetical calculations.
If it can't find any way to run it or print the value, it just displays the type:
chris:~/$ head
forall a. [a] -> a
The commands of GHCi like :t
and :k
are not supported at this
time. Top-level bindings are not yet supported either.
It supports completion of function names and binaries:
chris:~/$ get
getChar getfacl getZipSink
getContents gethostip getZipSource
getContents getkeycodes getAppUserDataDirectory
getLine getopt getCurrentDirectory
getLine getpcaps getDirectoryContents
getFpco gettext getHomeDirectory
getafm gettextize getModificationTime
getcap gettextsh getPermissions
getconf getty getTemporaryDirectory
geteltorito getweb getUserDocumentsDirectory
getent getZipConduit
and filenames:
chris:~/Pictures$ ls "Screenshot from 2014-0
Screenshot from 2014-08-13 22:05:10.png Screenshot from 2014-09-09 14:55:46.png
Screenshot from 2014-09-15 17:09:26.png Screenshot from 2014-08-11 11:39:00.png
Screenshot from 2014-09-13 19:03:34.png Screenshot from 2014-09-12 12:26:51.png
Screenshot from 2014-08-13 12:57:14.png Screenshot from 2014-09-15 17:03:34.png
Screenshot from 2014-08-15 18:19:03.png Screenshot from 2014-08-28 16:50:04.png
It's an ironic name, like Little John. And who knows, a Haskell shell might be hell.
That's not going to happen. Hell is about plain Haskell.