tshell icon indicating copy to clipboard operation
tshell copied to clipboard

Experimental alternative shell for Emacs

Intro

tshell is an experimental buffer-oriented Emacs shell.

It is built around several basic ideas:

  • RET runs current line, so you can easily iterate on your one-liners
  • line prompt determines interpreter: $ for shell, > for elisp
  • output by default goes into a single *tshell-out* buffer
  • to get a named shell with history, write tshell buffer to a file, like ~/.tshell_history
  • contents of the *tshell-out* buffer can be easily used as input for commands
  • create shortcuts via transient

Demo

See https://imgur.com/a/dsdKG2D

Installation

git clone https://github.com/TatriX/tshell ~/.emacs.d/tshell
(use-package tshell
  :after transient
  :load-path "~/.emacs.d/tshell")

or

(add-to-list 'load-path ~/.emacs.d/tshell)
(require 'tshell)

Completion

There is a very rough completion support via fish-completion:

(use-package fish-completion
  :config
  (when (and (executable-find "fish")
             (require 'fish-completion nil t))
    (global-fish-completion-mode 1)))

Note that you need to have [fish](https://fishshell. com/) installed. You can also use bash-completion as a fallback for fish-completion.

Usage

Run M-x tshell. You can change interpreter by just editing prompt character:

$ # For example type `C-a C-k >` to get
> ;; elisp interpreter

If you want to create a new line without evaluating anything, type C-j or M-j.

Current working directory

Current working directory is determined as in any other buffer by the value of local default-directory variable:

> default-directory

It is shown in the header line. You can change it in multiple ways:

$ cd /tmp
$ pwd

Typing C-c C-d is equivalent to M-x cd. That means it uses your favorite completion mechanism!

ls

You probably want to see the contents of the current directory quite often.

The easiest way to do that is to type C-c C-l.

Input/Output redirection

tshell does almost nothing to your command, so you can do pipes and redirections as usual:

$ cd ~/.emacs.d/tshell
$ # Here I show multiple lines, but actually I just edit the same line
$ ls
$ ls | grep el$
$ ls | grep el$ > /tmp/files
$ # And now open it
$ e /tmp/files

But most of the time you just want to pass contents of your *tshell-out* to the next command.

$ ls *md
$ > sed 's/md/org/' # Here I'm using `>` to send contents of the `*tshell-out*` to stdin of `sed`

If you realized that you need to rerun the command, you can either type C-p RET C-n to recreate desired input or you can undo changes in the *tshell-out* buffer.

Undo

To undo changes in *tshell-out* buffer you can run

: undo

or just switch to the *tshell-out* buffer and use your regular undo keybinding, like C-/.

History variables

Every time you evaluate a lisp command, result of the evaluation is stored in variable *

> (+ 13 69) # 82
> (+ 42 *) # 124

* is a regular elisp variable, so you can use it in any other context, like *scratch* buffer or M-x eval.

Misc

You can type C-c C-y to insert contents of the *tshell-out* buffer at point:

$ locate tshell | grep 'el$'
$ e # Type `C-c C-y`
$ e /home/tatrix/.emacs.d/tshell/tshell.el # `e` is a special command which opens file in the emacs buffer

Customization

You can customize how your prompt looks:

(setq tshell-shell-prompt "zsh>")
(setq tshell-elisp-prompt "elisp>")