A lightweight, fast text editor for the terminal, written in Rust.
Warning
Vibe coded. This project is an experiment in getting an AI assistant to follow Functional Reactive Programming (FRP) principles and produce reasonable code within that discipline. I've focused on the overall architecture rather than reviewing the code output in detail. For projects I've mostly written by hand, see ureq and str0m.
led is built on a functional reactive programming (FRP) architecture where the model is a pure reducer, all side effects live in drivers, and the UI is a derived function of state. The result is a responsive editor with rich features and a small footprint.
Full LSP integration with out-of-the-box support for:
| Language | Server |
|---|---|
| Rust | rust-analyzer |
| TypeScript/JavaScript | typescript-language-server |
| Python | pyright |
| C/C++ | clangd |
| Swift | sourcekit-lsp |
| TOML | taplo |
| JSON | vscode-json-language-server |
| Bash | bash-language-server |
Language servers are not bundled — install them separately and make sure they are on your PATH. led will automatically start the right server when you open a file.
# Rust
rustup component add rust-analyzer
# TypeScript / JavaScript
npm install -g typescript-language-server typescript
# Python
npm install -g pyright
# C / C++
brew install llvm # macOS
apt install clangd # Debian/Ubuntu
# Swift (included with Xcode)
# sourcekit-lsp is available after installing Xcode or the Swift toolchain
# TOML
cargo install taplo-cli --locked
# JSON
npm install -g vscode-langservers-extracted
# Bash
npm install -g bash-language-server
- Completions — fuzzy-filtered popup with auto-imports
- Go to definition
- Rename — workspace-wide symbol rename
- Code actions — quick fixes and refactors
- Diagnostics — inline errors and warnings with gutter indicators
- Inlay hints — toggleable type annotations
- Format — on-demand formatting with import sorting
- Progress — spinner in status bar during long operations
Tree-sitter powered highlighting for Bash, C, C++, JavaScript, JSON, Make, Markdown, Python, Ruby, Rust, Swift, TOML, and TypeScript. Rainbow bracket coloring with matching bracket highlighting.
led detects a file's language using three methods, in priority order:
- File extension —
.rs→ Rust,.py→ Python,.rb→ Ruby, etc. - Filename —
Makefile,Gemfile,Rakefile,Vagrantfile - Editor modeline — if the extension and filename don't match a known language, led scans the first 5 lines for Emacs or Vim modelines:
# -*- mode: ruby -*-
# vim: set ft=ruby :
This is useful for scripts and config files that lack a recognized extension.
The following mode strings are recognized in modelines:
| Mode string | Language |
|---|---|
rust |
Rust |
python |
Python |
javascript, js |
JavaScript |
typescript, ts |
TypeScript |
tsx |
TSX |
json |
JSON |
toml |
TOML |
markdown, md |
Markdown |
bash, sh |
Bash |
c |
C |
cpp, c++ |
C++ |
swift |
Swift |
make |
Make |
ruby |
Ruby |
- Project search (
Ctrl+f) — ripgrep-powered search across the workspace with case and regex toggles. Results grouped by file with a live preview pane. - Buffer search (
Ctrl+s) — incremental search within the current file with match highlighting and wrap-around navigation. - Find file (
Ctrl+x Ctrl+f) — fuzzy path completion for quick file opening.
Side panel file tree with expand/collapse, file preview on selection, and background open. Toggle with Ctrl+b.
Current branch in the status bar. Per-file status (modified, staged, untracked) shown in the file browser. Line-level change indicators in the editor gutter.
led automatically saves and restores your session — open files, cursor positions, scroll positions, tab order, and undo history are preserved across restarts via a per-workspace SQLite database.
Multiple editor instances on the same workspace are supported. The primary instance holds a lock; secondary instances sync edits through the workspace database.
- Undo/redo with Emacs-style linear history
- Mark and region (set mark, kill region, yank)
- Kill ring with text accumulation across consecutive deletes
- Smart indentation on newline
- Jump list — navigate back and forth through your position history
- Symbol outline via LSP document symbols
- Bracket matching and jump-to-matching-bracket
- Auto-close buffers to prevent resource exhaustion
cargo install --path led
Or build from source:
git clone https://github.com/user/led.git
cd led
cargo build --release
The binary will be at target/release/led.
led [path]
Open a file or directory. With no argument, led opens the current directory.
| Flag | Description |
|---|---|
--log-file PATH |
Write debug logs to a file |
--reset-config |
Reset keybindings and theme to defaults, clear session DB |
Configuration lives in ~/.config/led/.
| File | Purpose |
|---|---|
keys.toml |
Key bindings |
theme.toml |
Color theme |
db.sqlite |
Session database |
Run led --reset-config to restore default keybindings and theme.
Key bindings are defined in TOML. Modifiers are ctrl, alt, and shift. Chord sequences use sub-tables.
[keys]
"ctrl+s" = "in_buffer_search"
"alt+enter" = "lsp_goto_definition"
# Chord: Ctrl+x followed by Ctrl+s
[keys."ctrl+x"]
"ctrl+s" = "save"Context-specific bindings for the file browser and search panel use [browser] and [file_search] sections.
| Key | Action |
|---|---|
Enter |
Insert newline |
Backspace |
Delete backward |
Delete / Ctrl+d |
Delete forward |
Tab |
Insert tab / accept completion |
Ctrl+k |
Kill line |
Ctrl+/ / Ctrl+_ / Ctrl+7 |
Undo |
Ctrl+Space |
Set mark |
Ctrl+w |
Kill region |
Ctrl+y |
Yank (paste) |
Ctrl+x ( |
Start recording macro |
Ctrl+x ) |
Stop recording macro |
Ctrl+x e |
Play macro (e repeats) |
Ctrl+x N e |
Play macro N times (0=until error) |
| Key | Action |
|---|---|
Up / Down |
Move up / down |
Left / Right |
Move left / right |
Home / Ctrl+a |
Line start |
End / Ctrl+e |
Line end |
Page Up / Alt+v |
Page up |
Page Down / Ctrl+v |
Page down |
Ctrl+Home / Alt+< |
File start |
Ctrl+End / Alt+> |
File end |
Alt+] |
Jump to matching bracket |
| Key | Action |
|---|---|
Ctrl+Left |
Previous tab |
Ctrl+Right |
Next tab |
Ctrl+x k |
Kill buffer |
| Key | Action |
|---|---|
Ctrl+x Ctrl+s |
Save |
Ctrl+x Ctrl+a |
Save all |
Ctrl+x Ctrl+d |
Save (no format) |
Ctrl+x Ctrl+w |
Save as |
Ctrl+x Ctrl+f |
Find file |
| Key | Action |
|---|---|
Ctrl+f |
Project search |
Ctrl+s |
Buffer search |
Alt+1 (in search) |
Toggle case sensitivity |
Alt+2 (in search) |
Toggle regex |
Alt+3 (in search) |
Toggle replace mode |
Alt+Enter (in search) |
Replace all |
In replace mode, the search input, replace input, and results form a single vertical list navigated with Up/Down. Tab switches between the search and replace inputs. On a result row, Right replaces the selected match, Left undoes the last replace. Enter closes the panel. Alt+Enter replaces all remaining matches and closes.
| Key | Action |
|---|---|
Alt+Enter |
Go to definition |
Ctrl+r |
Rename symbol |
Alt+i |
Code action |
Ctrl+t |
Toggle inlay hints |
Ctrl+x i |
Sort imports |
| Key | Action |
|---|---|
Alt+. |
Next issue |
Alt+, |
Previous issue |
"Issue" navigation cycles through LSP errors and warnings, unstaged and staged git changes, and PR diff lines and review comments — in that priority order.
| Key | Action |
|---|---|
Ctrl+x Ctrl+p |
Open PR / comment URL |
Ctrl+x Ctrl+p opens the current pull request in the browser. If the cursor is on a line with a PR review comment, that comment's URL is opened instead.
| Key | Action |
|---|---|
Alt+b / Alt+Left |
Jump back |
Alt+f / Alt+Right |
Jump forward |
Alt+o |
Outline |
| Key | Action |
|---|---|
Ctrl+b |
Toggle side panel |
Alt+Tab |
Toggle focus (editor / side panel) |
Ctrl+h e |
Open messages |
Esc / Ctrl+g |
Abort / cancel |
Ctrl+z |
Suspend |
Ctrl+x Ctrl+c |
Quit |
| Key | Action |
|---|---|
Left |
Collapse directory |
Right |
Expand directory |
Enter |
Open selected |
Alt+Enter |
Open in background |
Ctrl+q |
Collapse all |
led follows a strict FRP cycle:
State → Derived → Drivers → Model → State
- State — a single immutable
AppStatecontaining all editor state - Derived — pure transforms from state into driver commands (no business logic)
- Drivers — handle side effects: terminal I/O, file system, LSP, git, syntax parsing, clipboard, timers, session persistence
- Model — a pure reducer
(State, Mutation) → Statecomposed from combinator chains
The codebase is organized as a Cargo workspace with 15 crates — each driver (LSP, git, syntax, file search, clipboard, etc.) is its own crate with a clean boundary.
MIT



