Linus Torvalds' original μEmacs, transformed into a pure C23 implementation for modern Linux systems.
μEmacs is a minimalist text editor preserving Linus Torvalds' original keybindings and philosophy, now implemented with modern C23 standards. This version removes all legacy platform code, focusing exclusively on Linux performance and reliability.
This project follows the uEmacs spirit that Linus favors:
- Minimal surface area: small codebase, straightforward C, no frameworks.
- Drop-in build: clone, compile fast, run — no toolchain gymnastics.
- Few dependencies: only what’s native on Linux (ncursesw, a C compiler).
- Text-first, TUI-only: no GUI layers; reliable terminal behavior is the goal.
- Predictable install: single binary plus data directory; no background services.
- No bloat: every feature must earn its place by improving core editing.
μEmacs traces a straight line from MicroEMACS (1985) through Petri Kutvonen’s uEmacs/PK to Linus Torvalds’ tiny personal uEmacs. This project keeps that lineage intact — modernizing just enough for 2025 while preserving the small, fast, drop‑in editor Linus prefers.
μEmacs builds on a small, portable lineage:
- MicroEMACS (1985): Dave G. Conroy; later Daniel M. Lawrence.
- uEmacs/PK (1990s): Petri H. Kutvonen’s enhanced MicroEMACS 3.9e.
- Linus Torvalds’ uEmacs: a simple, personal fork maintained as a tiny, fast editor.
Why small matters (uEmacs/PK README): “Creeping featurism, growing size, and reduced portability made [later versions] less attractive… [uEmacs/PK] adds some new functionality and comfort but does not sacrifice the best things (small size and portability).”
References
- uEmacs (Torvalds): https://github.com/torvalds/uemacs
- uEmacs/PK README (history and goals): https://github.com/torvalds/uemacs/blob/master/README
- MicroEMACS (overview): https://en.wikipedia.org/wiki/MicroEMACS
Run the editor using either the Unicode or ASCII-friendly command:
μEmacs [FILE ...]muEmacs [FILE ...]
Core Implementation (~28,255 lines of C23 code)
- C23 Implementation: Modern atomic operations, thread safety, and memory management
- Linus's Original Keybindings: Preserved exactly as designed, with undo/redo on available keys
- O(1) Keymap System: Hash-based lookup for instant command execution
- Zero Legacy Code: 500+ lines of obsolete platform code removed (MSDOS, VMS, etc.)
Advanced Text Editing
- VSCode-Style Undo/Redo: Atomic circular buffer with intelligent operation grouping, 400ms coalescing window, and 10,000 operation capacity
- Modern Kill Ring: 32-entry atomic circular buffer (8KB per entry) with system clipboard integration via xclip/xsel
- Copy (Meta+W) and Kill (Ctrl+W, etc.) automatically mirror the selection into the system clipboard
- Use "yank-clipboard" (M-x yank-clipboard) to paste directly from the system clipboard
- Multiple Search Engines: Boyer-Moore-Horspool (O(n/m) performance) and Thompson NFA regex engine with zero-heap runtime
- UTF-8 Support: Full Unicode handling with proper terminal integration, bidirectional conversion, and minimality validation
Terminal Integration
- Modern Terminal Support: 24-bit true color, bracketed paste mode, GPU terminal optimization (Alacritty, Kitty)
- Signal-Safe Operations: Atomic terminal state changes with generation counting and concurrent access protection
- Customizable Status Line: Real-time git integration, atomic buffer statistics, and configurable mode indicators
- Clean Exit UX: Proper alternate screen restore on exit (no split history; no manual Ctrl+L needed)
- ESC Meta Processing: Reliable ESC-as-Meta with C23 atomic key transformation and instantaneous case conversion
Performance & Reliability
- Gap Buffer: O(1) insert/delete at cursor with dynamic resizing and UTF-8 awareness
- Display Matrix: Dirty region tracking with hardware-accelerated scrolling and selection highlighting
- Memory Safety: Centralized allocation system with leak tracking and overflow protection
Quick install options
- Auto-detect:
./scripts/system_install.sh - Arch (AUR-style, local PKGBUILD):
./scripts/system_install.sh --mode aur - Generic CMake install:
./scripts/system_install.sh --mode cmake --prefix /usr/local - Debian/Ubuntu (.deb via CPack):
./scripts/system_install.sh --mode deb
Manual build from source
# Clone and build
git clone [repository] && cd μEmacs
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
# Run from build tree
./build/bin/μEmacs [FILE]After system install
- Commands:
μEmacsandmuEmacs(ASCII alias) - Data files:
/usr/share/muemacs - Desktop entry:
/usr/share/applications/muEmacs.desktop - Man page:
/usr/share/man/man1/muEmacs.1
Install notes
- Arch/AUR mode builds from the current working tree with a locally generated PKGBUILD and source tarball (no network fetches).
- The installed binary is
/usr/bin/μEmacswith an ASCII alias symlink/usr/bin/muEmacs.
- Fast and deterministic: standard CMake flow, native packages optional, no network at build.
- Portable across distros: either
cmake --installor a self-contained Arch/DEB package. - Avoids dependency creep: runtime is just a single binary linked with ncursesw.
- Linux (kernel 5.0+)
- GCC 12+ or Clang 15+ with C23 support
- ncursesw library
- 4MB RAM minimum
Optional tools
- xclip or xsel (recommended) for system clipboard integration
Recommended for CI and non-interactive environments:
# Run the non-interactive integration suite (fast, no PTY/expect required)
./build/bin/full_integration_test
# Or via CMake target
cmake --build . --target api_tests -jInteractive Expect-based tests are optional and disabled by default. To run them on a real terminal:
# Enable interactive tests explicitly and run
cmake --build . --target itests -j
# Equivalent manual invocation
UEMACS_INTERACTIVE=1 ENABLE_EXPECT=1 ./build/bin/full_integration_testNotes
- Interactive tests require a real TTY/PTY. In CI or headless shells they will be skipped automatically.
- The helper
interactive_stress_test.expwill auto-exit unlessUEMACS_INTERACTIVE=1is set.
Performance benchmarks
make benchHeavy Stress Testing (non-interactive)
# Run extreme stress suite with large operation counts
cmake --build . --target stress -j
# Scale intensity (default factor=1). Example: 3x intensity with longer phase timeouts
UEMACS_STRESS=3 UEMACS_PHASE_TIMEOUT=3600 ./build/bin/full_integration_test
# Enable the separate ultra-stress suite only when desired
EXTREME_STRESS=1 ./build/bin/full_integration_testDefaults are shipped with the program and used at runtime:
- System defaults:
/usr/share/muemacs/editor/settings.json
Notes
- By design, μEmacs reads and writes the shipped
settings.json. After a system-wide install, editing may require elevated permissions. For local development builds, editconfig/editor/settings.jsonin the tree.
Example settings.json
{
"column_width": 80,
"wrap": true,
"ruler": true,
"rulercol": 80,
"highlightline": true,
"hilinestyle": 1,
"rulerstyle": 1,
"modeline_show_git": true,
"modeline_show_stats": true,
"modeline_show_modes": true,
"modeline_show_position": true
}Commands
M-x set-column-width(orC-x W) → prompts for a number, sets width and enables wrapM-x save-settings→ writes current values to JSON (creates the file/directories if needed)M-x open-user-config→ opens settings.json for editing (creates file/directories if needed)M-x list-settings→ shows current values in the modeline/message area
- Simple by design: Configuration ships with the program and works out-of-the-box. System installs place defaults at
/usr/share/muemacs/editor/settings.json. If you want to customize without elevated permissions, run μEmacs from your build tree and editconfig/editor/settings.json.
These updates focus on everyday usability while preserving the uEmacs ethos:
- UTF‑8 everywhere: robust handling and terminal fidelity.
- Safer defaults: stack protections, hardened flags; no runtime overhead.
- Terminal niceties: bracketed paste, clean alt‑screen restore, truecolor support.
- Packaging quality of life: optional AUR/DEB packaging; still a single binary at runtime.
- Discoverability: desktop entry and man page; launch remains TUI, terminal‑native.
- Practical alias:
muEmacssymlink to avoid typing the micro symbol.
- No GUI toolkit, servers, or background daemons.
- No heavy plugin framework or embedded scripting runtime.
- No telemetry, network fetches, or auto‑updates.
- No sprawling config layers: defaults ship with the program; simple, predictable behavior.
Meta Key: Ctrl+[ (ESC key) or Ctrl+] for prefix
- ESC works reliably as Meta with C23 atomic case conversion for all letter combinations
Ctrl+X Ctrl+C- Exit μEmacsCtrl+X Ctrl+S- Save fileCtrl+X Ctrl+F- Find/open fileCtrl+G- Abort commandMeta+Z- Quick exit (Linus's original)
Ctrl+A- Beginning of lineCtrl+E- End of lineCtrl+F- Forward characterCtrl+B- Backward characterCtrl+N- Next lineCtrl+P- Previous lineCtrl+V- Next pageCtrl+Z- Previous page (Linus's original)Meta+<- Beginning of fileMeta+>- End of file
Ctrl+D- Delete next characterCtrl+H- Delete previous characterCtrl+K- Kill to end of lineCtrl+O- Open lineCtrl+T- Transpose charactersCtrl+Space- Set markCtrl+W- Kill region (cut)Meta+W- Copy regionCtrl+Y- Yank (paste)Meta+Y- Yank pop (cycle kill ring)
- Clipboard is integrated by default:
Meta+W(Copy) andCtrl+W(Kill region) push text to the system clipboardM-x yank-clipboardpastes from the system clipboard (useful when content wasn’t produced inside μEmacs)
Ctrl+_- UndoCtrl+/- Undo (alternative)Ctrl+X R- RedoMeta+_- Redo (alternative)
Ctrl+S- Search forwardCtrl+R- Search backwardMeta+R- Replace stringMeta+Ctrl+R- Query replace
Ctrl+X 0- Delete windowCtrl+X 1- Delete other windowsCtrl+X 2- Split windowCtrl+X O- Next windowCtrl+X B- Select bufferCtrl+X Ctrl+B- List buffersCtrl+X K- Kill buffer
Meta+F- Forward wordMeta+B- Backward wordMeta+D- Delete next wordMeta+Ctrl+H- Delete previous wordMeta+U- Uppercase wordMeta+L- Lowercase wordMeta+C- Capitalize word
Ctrl+X (- Begin macroCtrl+X )- End macroCtrl+X E- Execute macroMeta+X- Execute named commandMeta+K- Bind to keyCtrl+X =- Show cursor positionMeta+G- Go to lineCtrl+L- Redraw screen
Meta+Xopens a simple prompt (:) that accepts a command name.- Many commands take numeric prefix arguments (no inline typing at the prompt).
- Example (writing mode at 100 cols):
ESC 1 0 0 ESC x writing-mode RET.
- Example (writing mode at 100 cols):
- By default,
C-his Backspace (delete previous character), matching historical μEmacs behavior. - Help is available via
M-?andM-x describe-*commands by default. - You can enable an Emacs-style help prefix on
C-hwith:M-x enable-help-prefix→C-h k(describe-key),C-h b(describe-bindings)M-x disable-help-prefix→ restoresC-has Backspace
- To persist this behavior, add
enable-help-prefixto your startup file (e.g.,emacs.rc).
All commands available via Meta+X followed by command name:
abort-command- Cancel current operationexit-emacs- Exit editorquick-exit- Quick save and exithelp- Display helpexecute-named-command- Prompt for command
find-file- Open filesave-file- Save current bufferwrite-file- Write buffer to fileread-file- Insert file contentsview-file- Open file read-onlyinsert-file- Insert file at cursorlist-buffers- Show buffer listselect-buffer- Switch to buffernext-buffer- Next bufferdelete-buffer- Kill buffername-buffer- Rename buffer
beginning-of-file- Go to startend-of-file- Go to endbeginning-of-line- Go to line startend-of-line- Go to line endgoto-line- Go to line numbernext-line- Move downprevious-line- Move upforward-character- Move rightbackward-character- Move leftnext-word- Next wordprevious-word- Previous wordnext-subword- Next subword (camelCase)previous-subword- Previous subwordgoto-matching-fence- Jump to matching bracket
delete-next-character- Delete char forwarddelete-previous-character- Delete char backwarddelete-next-word- Delete word forwarddelete-previous-word- Delete word backwardkill-to-end-of-line- Kill to line endkill-region- Kill selected regioncopy-region- Copy regionyank- Pasteyank-pop- Cycle kill ringyank-clipboard- Paste from clipboardquote-character- Insert literal chartranspose-characters- Swap charsduplicate-line- Duplicate current linemove-line-up- Move line upmove-line-down- Move line down
case-word-upper- Uppercase wordcase-word-lower- Lowercase wordcase-word-capitalize- Capitalize wordcase-region-upper- Uppercase regioncase-region-lower- Lowercase regionfill-paragraph- Wrap paragraphjustify-paragraph- Justify textcount-words- Count words in region
search-forward- Search forwardsearch-reverse- Search backwardincremental-search- Interactive searchreverse-incremental-search- Reverse isearchreplace-string- Replace allquery-replace-string- Interactive replacehunt-forward- Repeat search forwardhunt-backward- Repeat search backward
split-current-window- Split windowdelete-window- Close windowdelete-other-windows- Keep only currentnext-window- Switch to next windowprevious-window- Switch to previous windowgrow-window- Enlarge windowshrink-window- Shrink windowresize-window- Resize window
begin-macro- Start macro recordingend-macro- End macro recordingexecute-macro- Run macrostore-macro- Save macroexecute-buffer- Execute buffer as commandsexecute-file- Execute file as commandsexecute-command-line- Execute shell commandexecute-program- Run external programshell-command- Run shell commandpipe-command- Pipe region through commandfilter-buffer- Filter buffer through command
bind-to-key- Bind command to keyunbind-key- Remove key bindingdescribe-key- Show key bindingdescribe-bindings- Show all bindingsadd-mode- Add buffer modedelete-mode- Remove buffer modeadd-global-mode- Add global modedelete-global-mode- Remove global modeset- Set variableset-column-width- Set wrap column (prompts for number)writing-mode- Enable a writing session (sets wrap to 80 or numeric arg, turns on wrap)exit-writing-mode- Restore prior wrap/fill settingsset-mark- Set markexchange-point-and-mark- Swap cursor and markunmark-buffer- Clear mark
undo- Undo last operationredo- Redo last undone operationuniversal-argument- Repeat next commandclear-and-redraw- Refresh displayredraw-display- Redraw screenupdate-screen- Update displayapropos- Search command help
- Intelligent Grouping: Auto-coalesces character insertions within 400ms windows and word boundaries
- Atomic Operations: Thread-safe with
_Atomicoperations and circular buffer architecture - Dynamic Capacity: Starts at 100 operations, expands to 10,000 with 2x growth factor
- Version Tracking: Each operation has unique 64-bit timestamp and version ID
- Memory Safety: Prevents recursive undo/redo, tracks resize failures
- Real-time Git Integration: Shows branch name and dirty state (
*) with background pthread updates - Atomic Buffer Statistics: Line count, column position, file size with lock-free updates
- Mode Indicators: Configurable display of buffer modes (CMODE, VIEW, etc.)
- Terminal-Adaptive: Automatically adjusts for terminal width and capabilities
- Performance Metrics: Optional display of search timing and memory usage
- Clean/Dirty Baseline: Accurate saved-state delta; undo back to saved state clears the dirty indicator
- Boyer-Moore-Horspool: Sublinear O(n/m) average case with 256-character bad-character table
- Thompson NFA: Zero-heap regex engine supporting
.,[char-class],^$anchors,*closure - Hybrid Selection: Automatically chooses optimal algorithm based on pattern complexity
- Case-Insensitive: Optional case folding for both search engines
- Cross-line Patterns: Multi-line regex support with proper anchoring
- Bracketed Paste: Automatic detection of
ESC[200~...ESC[201~sequences with state machine parser - Alt Screen Restore: Leaves the terminal history intact after exit, avoiding the “split screen” artifact
- 24-bit Color: RGB color support
\033[38;2;r;g;bm for modern terminals - Cursor Shapes: Block, underline, bar cursor styles with capability detection
- GPU Terminal Optimization: Designed for Alacritty, Kitty, WezTerm performance
- Unicode Locale: Automatic UTF-8 locale initialization and validation
- Event Hooks: Register callbacks for editor events (file load, buffer switch, etc.)
- Multiple Handlers: Up to 8 hooks per event type with context passing
- Dynamic Registration: Runtime hook registration/deregistration
- Type Safety: Enumerated event types with validation
- Atomic Data Structures: Kill ring, undo stack, terminal state, display matrix
- Memory Safety: Centralized allocation with leak tracking and overflow protection
- Thread Safety: Signal-safe operations throughout with generation counting
- Zero-Copy Operations: Efficient string handling with gap buffer and UTF-8 awareness
- Original μEmacs: Linus Torvalds
- C23 Modernization: Will Clingan
- Version 0.0.23: Homage to C23 standard implementation
Original μEmacs license terms apply. Modernization preserves Linus Torvalds' vision and minimalist philosophy. See also
- docs/TERMINAL_COMPATIBILITY.md
- docs/UPGRADING.md
Add to your startup file (e.g., emacs.rc):
enable-help-prefix
bind-to-key kill-region ^W bind-to-key yank ^Y
Writing at fixed columns (keyboard-only)
-
One-shot session:
M-x writing-mode(wraps at 80). With a numeric argument, uses that width (e.g.,M-100 M-x writing-mode). -
Exit and restore prior settings:
M-x exit-writing-mode. -
Persist defaults (always start wrapped at 80):
set-column-width 80 add-global-mode wrap
Interactive tips
-
M-xis bound to bothMeta+XandMeta+x. -
Optional convenience (pick your own keys):
Current line and column guide (visual helpers)
-
Highlight current line (reverse video row):
set highlightline 1
-
Enable a vertical column ruler (reverse video on a specific column):
set ruler 1 set rulercol 80 # change to your preferred column
-
Disable either at any time:
set highlightline 0 set ruler 0
Styles (inherit terminal theme; no fixed colors)
-
Choose styles: 0 none, 1 underline (default), 2 bold, 3 dim
set hilinestyle 1 # underline the current line set rulerstyle 1 # underline the ruler column
-
Example: dim current line, bold ruler:
set hilinestyle 3 set rulerstyle 2
-
Font rendering & smoothing
- Inherited from your terminal emulator (FreeType/Pango on Linux). μEmacs (a TUI) does not control antialiasing. Configure smoothing and font choice in your terminal.
-
Color depth
- Truecolor: set
COLORTERM=truecolorand use a terminal that supports 24-bit color (Kitty/WezTerm/Alacritty). μEmacs will detect and honor capabilities but does not force a scheme. - Palette: when colors are needed, prefer terminal palette indices and defaults; μEmacs avoids hardcoded RGB and reverse video for theme fidelity.
- Truecolor: set
-
TERM and compatibility
- Use a sensible
TERM(e.g.,xterm-256coloror terminal-specific likexterm-kitty). - ESC as Meta is fully supported; Kitty “CSI u” keyboard protocol is decoded for precise modifiers (Alt/Meta, Ctrl). Shift is not encoded in legacy mappings by design.
- Use a sensible
-
Keyboard-only design
- Mouse interactions are intentionally unsupported in this build. All focus is on fast, low-latency keyboard editing.
-
Visual helpers
- Current line and column ruler use ANSI SGR attributes (underline/bold/dim) to inherit your terminal’s theme. Configure with
set highlightline,set ruler,set rulercol,set hilinestyle, andset rulerstyle.
- Current line and column ruler use ANSI SGR attributes (underline/bold/dim) to inherit your terminal’s theme. Configure with
-
Truecolor: export
COLORTERM=truecolorin your shell profile and use a terminal that supports 24‑bit color (Kitty/WezTerm/Alacritty). Example:export COLORTERM=truecolor
-
Fonts and smoothing: pick a monospaced font you like (e.g., JetBrains Mono, Fira Code, Iosevka Mono) in your terminal settings. Smoothing/antialiasing is controlled by the terminal/OS.
-
TERM: use
xterm-256coloror a terminal‑specific$TERM(e.g.,xterm-kitty) for accurate capabilities. -
Sample terminal configs (minimal):
- Alacritty: set
env: { COLORTERM: truecolor }, pick a font infont:block, choose a theme undercolors:. - Kitty: add
allow_hyperlinks no, pick a font underfont_family, and select acolor_theme. - WezTerm: in
wezterm.lua, setenable_wayland = true(Linux),font = wezterm.font("Your Mono Font"), andcolor_scheme = "YourTheme".
- Alacritty: set
-
Minimal underline (default):
set highlightline 1 set hilinestyle 1 set ruler 1 set rulerstyle 1 set rulercol 80
-
Subtle dim:
set highlightline 1 set hilinestyle 3 # dim current line set ruler 1 set rulerstyle 1 # underline ruler
-
High‑contrast (bold ruler):
set highlightline 1 set hilinestyle 1 # underline current line set ruler 1 set rulerstyle 2 # bold ruler column
-
No helpers:
set highlightline 0 set ruler 0