Skip to content

nerima-lisp/nshell

Repository files navigation

nshell

A modern, fish-inspired interactive shell written in Common Lisp.

CI License: MIT Built with Nix

nshell is an interactive shell that puts the interactive experience first: real-time syntax highlighting, history-aware autosuggestions, fish-style abbreviations, and a fast, context-aware completion engine — all built on a clean, test-driven Common Lisp core (8,800+ checks) and a reproducible Nix build.

Status: early development (0.4.x). The interactive editor and core pipeline execution are solid and heavily tested. The shell language is a growing subset of POSIX/fish semantics — see Roadmap for what is and isn't supported yet. nshell is usable as a daily interactive shell for common workflows; it is not a script-compatible /bin/sh replacement.


Highlights

  • Syntax highlighting as you type — commands, strings, operators, and paths are colorized live.
  • Autosuggestions from your history, fish-style, accepted with / Ctrl-F.
  • Abbreviations (abbr) that expand inline as you type — keep your muscle memory, type less.
  • Context-aware completion — a knowledge base of commands/flags plus filesystem completion, with common-prefix Tab extension and a candidate menu.
  • Rich line editing — Emacs keybindings, kill-ring & yank, multi-level undo/redo, multiline editing, and incremental history search (Ctrl-R). Optional vi key bindings (NSHELL_VI_MODE=1): normal-mode motions, counts, operators (dd, cw, …), visual selection, and insert/append.
  • Configurable prompt — hostname, working directory, git branch/dirty status, command duration, and exit code, with theming.
  • Job control — background jobs (&), jobs, fg, bg, disown.
  • Pipelines & redirection|, >, >>, <, <<, <<<, logical && / ||, and command sequencing.
  • Control flow & functionsif, for, while, switch, begin/end, and user-defined functions.
  • Reproducible build — a single statically-dumped SBCL image via Nix; nix run and you're in.

Quick start

With Nix (flakes enabled), run nshell without installing anything:

nix run github:takeokunn/nshell

Or build a binary into your profile:

nix profile install github:takeokunn/nshell
nshell
man nshell   # the manual page is installed alongside the binary

One-off command

nshell -c 'echo hello | string upper'

Run a script

nshell examples/greet.nsh World

Script files support multiline blocks (functions, if/for/while/switch), comments, and a #! shebang; arguments after the script name are available as $argv. See examples/ for a runnable sample.

CLI

Usage: nshell [--help] [--version] [-c COMMAND [ARGS...]] [SCRIPT [ARGS...]]

Without arguments, nshell starts an interactive shell when stdin is a terminal
and reads batch input from stdin otherwise.
With -c/--command, nshell executes COMMAND once in batch mode; trailing ARGS are available as $argv.
With SCRIPT, nshell runs the script file; trailing ARGS are available as $argv.

Building from source

nshell builds with SBCL and ASDF. The supported and tested path is Nix:

git clone https://github.com/takeokunn/nshell
cd nshell
nix build            # produces ./result/bin/nshell
nix flake check --print-build-logs
nix develop          # dev shell with SBCL + cl-weave

Inside nix develop, you can load the system into a REPL:

(asdf:load-system :nshell)
(nshell:main)

Built-in commands

alias, abbr, bg, cd, complete, contains, count, disown, echo, exec, exit, export, false, fg, function, help, history, jobs, ls, not, pipeline-graph, pwd, read, seq, set, source, string, test, true, type, which.

pipeline-graph 'CMD | CMD ...' renders a typed pipeline as a Graphviz DOT graph (or a Mermaid flowchart with --mermaid) without executing it — a diagnostic built on the cl-dataflow computation-graph toolkit. Quote the pipeline so the shell passes it as a single argument rather than running it, e.g. pipeline-graph 'cat access.log | grep 404 | wc -l'.

Run help inside nshell for details.

Architecture

nshell follows a domain-driven, layered design. Each layer depends only on the layers beneath it:

src/
├── domain/          Pure shell logic: parsing, expansion, completion,
│                    history, prompting, job-control — no I/O.
├── application/     Use cases: builtins, pipeline execution, job management.
├── infrastructure/  ACLs over the OS: syscalls, PTY, signals, terminal I/O,
│                    persistence. SBCL-specific code is isolated here.
└── presentation/    The REPL, line editor (input-state reducer), rendering,
                     highlighting, autosuggestions, completion UI.

The REPL is structured as a continuation-passing / trampoline loop: each keystroke runs a pure reducer over an immutable input-state, and rendering is derived from that state. This keeps the interactive core deterministic and unit-testable without a terminal.

Toolkit foundation

nshell builds on the nerima-lisp Common Lisp toolkit family, each wired at the layer where it fits the domain-driven design:

  • cl-parser-kit — its rule-based tokenizer and Pratt (operator-precedence) parser drive $((...)) arithmetic, which parses to an AST and then evaluates (adding **, bitwise & | ^ ~, shifts << >>, and the ternary ?:).
  • cl-dataflow — renders pipelines as validated computation graphs (pipeline-graph) and models the job lifecycle as an analyzable state machine.
  • cl-boundary-kit — makes the REPL edge's OS effects (hostname, working directory, clock) explicit, swappable boundaries, so the prompt and command timing are deterministic under test.
  • cl-cli — declaratively describes the nshell command line (--help/--version/-c/script dispatch).
  • cl-tty-kit — provides Unicode-correct display-width, truncation, and padding, plus the ANSI/SGR escape vocabulary used by rendering, prompt, and completion.

Testing

nshell runs entirely on cl-weave, with two complementary suites exposed through Nix checks:

  • nshell/test — the primary regression suite (~1,290 cases, describe/it/expect).
  • nshell/weave — a focused suite that exercises the completion engine's cl-prolog knowledge base with property-based tests, fixtures, benchmarks, and direct Prolog queries (findall, negation-as-failure, foreign predicates) plus the cl-prolog/weave query bridge.

Run the same hermetic Linux/macOS gate used by CI (it runs both suites):

nix flake check --print-build-logs

Run only the current platform's test derivation:

nix build .#checks.$(nix eval --impure --raw --expr builtins.currentSystem).test

Run the full non-sandboxed integration suite when changing PTY, subprocess, terminal, or job-control behavior. This covers the real-PTY interactive smoke, Ctrl-C recovery, and job-control lifecycle checks that are intentionally skipped inside hermetic Nix builds:

nix develop -c sbcl --non-interactive \
  --eval '(require :asdf)' \
  --eval '(push (truename "./") asdf:*central-registry*)' \
  --eval '(asdf:test-system :nshell/test)'

Generate an HTML coverage report for the same suite:

nix develop -c sbcl --script scripts/coverage.lisp

The report is written to coverage/cover-index.html by default. Set NSHELL_COVERAGE_DIR to redirect the output.

Run the cl-weave suite on its own (the weave alias in nix develop, or directly). The runner self-registers sibling ../cl-weave and ../cl-prolog checkouts, so no extra environment setup is needed:

sbcl --script scripts/weave.lisp

Unit, integration, property-based, and end-to-end tests live under tests/. New shell-language, expansion, completion, job-control, and input-state changes should include focused regression tests plus the relevant property or PTY coverage when behavior crosses process, terminal, or parser boundaries. See CONTRIBUTING.md for test-selection expectations.

Roadmap

nshell is converging on world-class interactive-shell parity. Near-term focus:

  • Shell language depth — richer list variables and explicit semantics around compound expansions. (Quoting, parameter expansion with defaults, required checks, substring slicing, and patterns, arithmetic $((...)) — including **, bitwise, shift, and ternary operators — brace expansion, command substitution $(...)/(...), fd redirections 2>/2>&1/&>, here-docs <<, here-strings <<<, and function arguments via $argv/$argv[N] are done.)
  • Job control hardening — robust foreground process-group handling so Ctrl-C / Ctrl-Z reliably interrupt and suspend pipelines.
  • Completion intelligence — broader command metadata and higher-fidelity flag/value completion.
  • Distribution — nixpkgs, Homebrew, and prebuilt release binaries.

See CHANGELOG.md for released changes.

For release qualification, see PUBLIC_READINESS.md.

Contributing

Contributions are welcome. Please run nix flake check --print-build-logs before opening a pull request; CI runs that hermetic gate on Linux and macOS and also runs the full non-sandboxed integration suite on Linux. See CONTRIBUTING.md for style, test, semantics, and issue-reporting expectations.

Security

Please report vulnerabilities privately instead of opening a public issue. See SECURITY.md for the supported scope, report contents, and disclosure process.

License

MIT © the nshell authors.

About

Modern, fish-inspired interactive shell written in Common Lisp

Topics

Resources

License

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages