Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ jobs:
NSHELL_TEST_PTY: "1"
run: |
nix develop -c bash scripts/test-dependencies.sh
nix develop -c perl t/scripts/test-dependencies.pl
nix develop -c perl t/scripts/test-native-spawn.pl
nix develop -c sbcl --script t/scripts/test-dependency-assertions.lisp
nix develop -c sbcl --script scripts/test-history-storage.lisp

coverage:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ jobs:
NSHELL_TEST_PTY: "1"
run: |
nix develop -c bash scripts/test-dependencies.sh
nix develop -c perl t/scripts/test-dependencies.pl
nix develop -c perl t/scripts/test-native-spawn.pl
nix develop -c sbcl --script t/scripts/test-dependency-assertions.lisp
nix develop -c sbcl --script scripts/test-history-storage.lisp

release:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The release and Nix flake support `x86_64-linux` only. With
[Nix](https://nixos.org/download) and flakes enabled:

```sh
nix run github:nerima-lisp/nshell/v0.6.4
nix run github:nerima-lisp/nshell/v0.6.5
```

At the prompt, enter `string upper hello`. Commands and paths colorize live, and a
Expand Down Expand Up @@ -62,7 +62,7 @@ and session settings.
## Install

```sh
nix profile install github:nerima-lisp/nshell/v0.6.4
nix profile install github:nerima-lisp/nshell/v0.6.5
```

Pin a release tag rather than following the default branch.
Expand Down
43 changes: 17 additions & 26 deletions docs/src/guide/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,24 @@

## The input state is a value

Every keystroke runs a pure reducer over an immutable `input-state` value, and
what appears on screen is derived from that value. Nothing about the current
line lives in a terminal buffer or a mutable global.
The reducer returns a new `input-state` value. The REPL stores the current
value in `*input-state*` and derives rendering from it.

This is the single decision most of nshell's interactive behaviour follows
from. Because a keystroke is a function from state to state, the line editor
can be tested exhaustively without a terminal: a test feeds a key sequence and
asserts on the resulting buffer, cursor, kill ring, or undo stack. Multi-level
undo is a stack of prior values rather than a replay log, and rendering can be
recomputed from scratch whenever it is cheaper than diffing.
Reducer tests feed key sequences and assert on the resulting buffer, cursor,
kill ring, or undo stack without a terminal. PTY tests check terminal
integration separately. Multi-level undo stores prior values rather than a
replay log, and rendering can be recomputed from the current state.

The REPL that drives the reducer is a continuation-passing trampoline loop,
which keeps the interactive core deterministic and unit-testable.
The REPL drives the reducer through a continuation-passing trampoline loop.

## Color is a theme, not a pile of escape codes

Every colored thing nshell draws (the prompt, the command line as you type, the
completion menu) reads its style from one theme: a mapping from a named role to
a fish-style style spec such as `5fafff --bold` or `gray --italics`. Nothing in
the rendering code carries a hardcoded escape sequence, so switching the whole
shell to another palette is one `theme use` away, and a role you dislike is one
`theme set` away. Colors are written once in truecolor and downsampled at the
terminal boundary, so the same theme renders on a 256-color or 16-color
terminal and disappears entirely under `NO_COLOR`. See
The prompt, command line, and completion menu read styles from a shared theme:
a mapping from a named role to a fish-style spec such as `5fafff --bold` or
`gray --italics`. `theme use` selects a palette; `theme set` changes a role.
Theme roles control colors and text styles. Cursor movement and other terminal
controls use separate escape sequences. Colors are downsampled for 256-color
or 16-color terminals; a nonempty `NO_COLOR` disables color output. See
[Customization](customization.md).

## Highlighting answers a question before you press Enter
Expand Down Expand Up @@ -72,10 +66,9 @@ remain literal.

## Abbreviations expand in place

An abbreviation registered with `abbr` expands inline as you type, so what ends
up in history is the expanded command. This differs from an alias, which stays
unexpanded and hides what actually ran. Abbreviations keep muscle memory short
while leaving history honest and greppable.
An abbreviation registered with `abbr` expands inline as you type, so history
records the expanded command. An alias is resolved during execution; history
retains the entered alias name.

## External editing preserves the prompt state

Expand Down Expand Up @@ -124,6 +117,4 @@ instead. `set -l` forces a new local variable even when an outer one of the
same name exists; `set -g` always reaches past every local scope to the
outermost one. Reading a name walks the scope chain from innermost outward,
so a local variable shadows a global of the same name for the rest of that
call. This is fish's scoping model, and nshell's environment stores it as an
ordered list of scopes rather than a single table, so shadowing and cleanup
fall out of list structure instead of a bookkeeping pass.
call. The environment stores scopes as an ordered list.
15 changes: 8 additions & 7 deletions docs/src/guide/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
nshell colors the prompt, syntax highlighting, and completion menu from a
single **theme**: a mapping from named roles (`command`, `prompt-path`,
`completion-file`, and so on) to a style. The `theme` builtin lets you switch
between built-in presets or override individual roles, and `~/.nshellrc` runs
plain nshell commands at startup, so a `theme` line there applies on every
launch.
between built-in presets or override individual roles. `~/.nshellrc` runs
plain nshell commands at interactive startup. `--no-config` skips the file,
and `--config PATH` selects another file. Batch and script runs do not load it.

## East Asian ambiguous character width

Expand Down Expand Up @@ -138,7 +138,7 @@ run of spaces is dropped too, so `{path} {git} {status}` never leaves a
double space outside a repository.

nshell has two prompts: the left one, and a right prompt that floats at the
far edge of the terminal. They default to exactly today's layout:
far edge of the terminal. The default formats are:

```
{path} {git} {status}
Expand Down Expand Up @@ -212,7 +212,7 @@ An unknown key name or action name exits with status 2 and lists the valid
names; `bind` with anything else prints a usage line and exits 1. A key name
is spelled the way it is typed, in lowercase and hyphen-separated (`ctrl-r`,
`alt-e`, `right`, `shift-tab`). Put `bind` lines in `~/.nshellrc` to apply
custom bindings on every launch, the same way `theme` lines do.
custom bindings at interactive startup, the same way `theme` lines do.

### Capturing the previous command's output

Expand All @@ -239,8 +239,9 @@ when vi mode is off or the terminal is not interactive.
## In `~/.nshellrc`

`.nshellrc` is not a separate configuration format: it is a file of plain
nshell commands, sourced once at startup before the first prompt. Put a
`theme` command there to start every session with your preset:
nshell commands, sourced once at interactive startup before the first prompt
unless `--no-config` or `--config PATH` changes this behavior. Put a `theme`
command there to select your preset:

```sh
theme use tokyo-night
Expand Down
58 changes: 27 additions & 31 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,60 @@
# nshell

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

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 and a reproducible Nix build.
nshell provides real-time syntax highlighting, history-aware autosuggestions,
fish-style abbreviations, and context-aware completion. It is built with Nix.

!!! note "Status: development preview (0.6.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 the [roadmap](project/roadmap.md) 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.
The shell implements a tested subset of shell syntax, not full POSIX/fish
compatibility. For supported features and known limits,
see the [roadmap](project/roadmap.md).
It is not a script-compatible `/bin/sh` replacement.

## Highlights

- **Syntax highlighting** as you type — a command that would fail with
- **Syntax highlighting** as you type: a command that would fail with
`command not found` is red before you run it, existing paths are underlined,
and strings, variables, keywords, and operators each get their own color.
- **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 and flags plus
- **Abbreviations** (`abbr`) expand inline as you type.
- **Context-aware completion**: a knowledge base of commands and flags plus
filesystem completion, git branches, environment variables, and
directory-only completion for `cd`, in a colored candidate menu with
common-prefix `Tab` extension.
- **Rich line editing** — Emacs keybindings, kill-ring and yank, multi-level
- **Line editing**: Emacs keybindings, kill-ring and yank, multi-level
undo/redo, multiline editing, and a `Ctrl-R` history picker that lists
matches under the prompt.
- **Vi key bindings** (optional, `NSHELL_VI_MODE=1`) — normal-mode motions,
- **Vi key bindings** (optional, `NSHELL_VI_MODE=1`): normal-mode motions,
counts, operators (`dd`, `cw`, …), visual selection, and insert/append.
- **Themes** — one named palette drives the prompt, the highlighter, and the
- **Themes**: one named palette drives the prompt, the highlighter, and the
completion menu; ten presets ship with the shell, `theme use` switches live,
and colors downsample to 256- or 16-color terminals.
- **A prompt that reports** — working directory, git branch and dirty marker,
- **Prompt status**: working directory, git branch and dirty marker,
a prompt character that turns red after a failure, and, on the right, the
failing exit code plus the duration of anything slower than a second.
- **Job control** — background jobs (`&`), `jobs`, `fg`, `bg`, `disown`.
- **Pipelines and redirection** — `|`, `>`, `>>`, `<`, `<<`, `<<<`, logical
- **Job control**: background jobs (`&`), `jobs`, `fg`, `bg`, `disown`.
- **Pipelines and redirection**: `|`, `>`, `>>`, `<`, `<<`, `<<<`, logical
`&&` / `||`, and command sequencing.
- **Control flow and functions** — `if`, `for`, `while`, `switch`,
- **Control flow and functions**: `if`, `for`, `while`, `switch`,
`begin`/`end`, and user-defined `function`s.
- **History expansion** — `!!`, `!$`, `!-N`, `!?text?`, and `!prefix`, with
quoted and backslash-escaped exclamation marks kept literal.
- **External editing** — `Alt-E` opens the current line with the configured
- **History expansion**: `!!`, `!$`, `!-N`, `!?text?`, and `!prefix`, with
single-quoted and backslash-escaped exclamation marks kept literal.
- **External editing**: `Alt-E` opens the current line with the configured
editor and returns the edited buffer to the prompt.
- **Reproducible build** — a dumped SBCL image and its process-launch helper via Nix;
`nix run` and you're in.
- **Nix build**: a dumped SBCL image and its process-launch helper;
start the shell with `nix run`.

## Where to go next

- [Getting started](getting-started.md) — install nshell and run your first
- [Getting started](getting-started.md): install nshell and run your first
command.
- [Core concepts](guide/concepts.md) — how the interactive layer is put
- [Core concepts](guide/concepts.md): how the interactive layer is put
together.
- [Recipes](guide/recipes.md) — scripting, pipeline diagrams, and the test
- [Recipes](guide/recipes.md): scripting, pipeline diagrams, and the test
workflow.
- [Built-in commands](reference/builtins.md) — the shell's own command set.
- [Architecture](reference/architecture.md) — the layered design and the
- [Built-in commands](reference/builtins.md): the shell's own command set.
- [Architecture](reference/architecture.md): the layered design and the
toolkit family it builds on.
29 changes: 20 additions & 9 deletions docs/src/project/contributing.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Contributing to nshell

The process — branching, pull requests, commit conventions, and the org-wide
rules a review checks — lives in the
Branching, pull requests, commit conventions, and org-wide review rules are
documented in the
[nerima-lisp contributing guide](https://github.com/nerima-lisp/.github/blob/main/CONTRIBUTING.md).
This page covers only what is specific to nshell.

Expand All @@ -14,10 +14,11 @@ review will actually push back on:
- **`domain/` performs no I/O.** Whether it lives under `src/` or a feature
package, new parsing, expansion, completion, or history logic belongs here and
must be unit-testable without a terminal.
- **`infrastructure/` isolates all OS- and SBCL-specific code** — syscalls, PTY,
signals, terminal handling, persistence. Guard implementation-specific code
with `#+sbcl` where relevant.
- **`application/` holds use cases** — builtins, pipeline execution, job
- **`infrastructure/` holds OS adapters**: syscalls, PTYs, signals, terminal
handling, and persistence. The runtime targets SBCL; application and
presentation code also use SBCL facilities. Guard implementation-specific
code with `#+sbcl` where relevant.
- **`application/` holds use cases**: builtins, pipeline execution, job
management.
- **`presentation/` is the REPL, line editor, and rendering.**

Expand All @@ -43,21 +44,31 @@ Iterate with the smallest relevant suite, then run the full gate before review.

| Change | Run |
|---|---|
| Anything | `perl -e '$SIG{ALRM}=sub { exit 124 }; alarm 1800; exec @ARGV' nix flake check --print-build-logs` before review; the full gate runs on `x86_64-linux` CI |
| Anything | `perl -e '$SIG{ALRM}=sub { exit 124 }; alarm 1800; exec @ARGV' nix flake check --print-build-logs` before review; CI runs on `x86_64-linux` |
| Domain logic, builtins, parser, expansion | `perl -e '$SIG{ALRM}=sub { exit 124 }; alarm 300; exec @ARGV' nix run .#test` |
| Completion engine or cl-prolog-kit knowledge base | `perl -e '$SIG{ALRM}=sub { exit 124 }; alarm 300; exec @ARGV' sbcl --script scripts/weave.lisp` |
| PTY, subprocess, terminal, signal, job control | the non-sandboxed run below |
| Coverage-oriented validation | `perl -e '$SIG{ALRM}=sub { exit 124 }; alarm 900; exec @ARGV' nix develop -c sbcl --script scripts/coverage.lisp` |

The full CI gate also runs these checks separately from `nix flake check`:

```sh
nix develop -c bash scripts/test-dependencies.sh
nix develop -c perl t/scripts/test-dependencies.pl
nix develop -c perl t/scripts/test-native-spawn.pl
nix develop -c sbcl --script t/scripts/test-dependency-assertions.lisp
nix develop -c sbcl --script scripts/test-history-storage.lisp
```

The non-sandboxed integration run, for changes the Nix sandbox cannot exercise:

```sh
perl -e '$SIG{ALRM}=sub { exit 124 }; alarm 300; exec @ARGV' nix develop -c sbcl --script run-tests.lisp
```

Tests live in `t/` and must be hermetic: no dependence on the ambient working
directory, terminal size, or environment. Use the provided fixtures — for
example `with-stable-repl-prompt` and `with-fixed-terminal-size` — for
directory, terminal size, or environment. Use the provided fixtures, such as
`with-stable-repl-prompt` and `with-fixed-terminal-size`, for
rendering tests.

For parser, expansion, execution, or builtin changes, include focused unit
Expand Down
Loading
Loading