- Zig 59.5%
- Janet 38.3%
- Nix 2.2%
Koa - A Modal Code Editor
A fully extensible and experimental modal code editor for the terminal. The Zig codebase provides a minimal bootstrap layer while Janet handles all editor logic, enabling maximum extensibility and live customization.
Key Features:
- Janet-based Core: Editor logic written in Janet for ultimate flexibility
- Live Reconfiguration: Hot-swap key bindings, behaviors, and plugins
- Zig Bootstrap: Minimal, efficient native layer for TUI and system integration
- Tree-sitter Integration: Syntax highlighting via native bindings (WIP)
- Unlimited Extensibility: Complete editor customization without recompilation
Current Status
Bootstrap Foundation (Zig):
- Janet Integration: jzignet library integrated for embedding Janet
- Janet-Zig Bridge System: File system, TUI, and syntax bridges implemented
- Janet Event Loop Foundation: Event loop infrastructure implemented in Janet
- Basic TUI Interface: libvaxis integration for terminal UI
- File Operations: Bridge functions for file I/O (placeholders until jzignet string support)
- Event Loop Handoff: Control handed from Zig to Janet main loop
Editor Core (Strategic Hybrid):
- Janet Editor State: Core state management moved to Janet
- Modal System Framework: Basic modal system structure in Janet
- Janet Event Handling: Input processing framework in Janet
- Complete Event Loop: Implement actual event processing
- Text Editing in Janet: Port text operations to Janet
- High-Level UI Bridge: Zig renders editor state from Janet
Architecture
Strategic Hybrid Design:
┌─────────────────────────────────────────────────────────────┐
│ Janet Layer (Editor Logic) │
├─────────────────────────────────────────────────────────────┤
│ • Modal system & state management │
│ • Text operations & buffer management │
│ • Key bindings & command system │
│ • Plugin system & user configuration │
│ • File I/O coordination │
└─────────────────────────────────────────────────────────────┘
↕ High-Level Bridge
┌─────────────────────────────────────────────────────────────┐
│ Zig Layer (UI & System Core) │
├─────────────────────────────────────────────────────────────┤
│ • Complete UI rendering │
│ • TUI operations & child window management │
│ • File I/O and system calls │
│ • Tree-sitter integration │
│ • Performance-critical operations │
└─────────────────────────────────────────────────────────────┘
Current Structure (strategic hybrid):
.
├── src/ # Zig source code
│ ├── main.zig # Bootstrap: Janet init + hybrid event loop
│ ├── runtime.zig # Bootstrap: Janet runtime loader
│ ├── janet_env.zig # Bootstrap: Janet environment management
│ ├── syntax.zig # Tree-sitter bindings (legacy, superseded by bridges/syntax.zig)
│ └── bridges/ # Zig-Janet bridge modules
│ ├── vaxis.zig # High-level UI bridge
│ ├── fs.zig # File system operations
│ └── syntax.zig # Tree-sitter bindings (TBD)
└── runtime/ # Janet runtime source code
├── core.janet # Core runtime entrypoint (init file)
├── modal.janet # Modal system
├── buffer.janet # Buffer management
├── keymap.janet # Keybindings
├── editor.janet # Editor state and management
├── movement.janet # Movement logic
├── selection.janet # Selection logic
├── utils.janet # Utility functions
└── config.janet # Configuration system (TBD)
Roadmap
Phase 1: Strategic Hybrid Foundation
-
Janet Integration & Bootstrap
- Integrate jzignet library for Janet embedding
- Set up Janet environment initialization in Zig
- Create minimal Zig bootstrap that hands control to Janet
- Design Janet API for editor state management
-
High-Level UI Bridge (Current Priority)
- Create semantic rendering bridge functions
- Maintain existing ui.zig performance and features
- Bridge accepts editor state from Janet, renders in Zig
- Replace primitive vaxis calls with high-level operations
-
Editor State Migration to Janet
- Port current editor state management to Janet
- Implement modal system (Normal/Insert/Select/Command) in Janet
- Create Janet text operations (insert, delete, cursor movement)
- Implement Janet-based key binding system
Phase 2: Advanced Editor Operations (Janet-Driven)
-
Dynamic Configuration System
- Implement live configuration system foundation
- Create event-driven architecture for editor events
- Design plugin architecture foundation
-
Movement Commands
- Word navigation (w, b, e) with customizable word boundaries
- Paragraph navigation ({, })
- Go to line (G, gg) with jump lists
- Page scrolling (Ctrl-D, Ctrl-U) with smooth scrolling options
- Search and jump (/, ?, n, N) with regex support
-
Text Operations
- Delete operations (dd, D, dw, etc.) with custom operators
- Yank/Copy operations (yy, Y, yw, etc.) with multiple registers
- Paste operations (p, P) with register selection
- Undo/Redo (u, Ctrl-R) with branching undo tree
- Replace mode (R) with preview
-
Extensible Command System
- Command mode with Janet expression evaluation
- Custom command definitions in Janet
- Command history and completion
- Macro recording and playback
Phase 3: Language Support & Syntax Highlighting
-
Tree-sitter Integration (via Zig bridge)
- Integrate neurocyte/tree-sitter library
- Create Janet API for syntax highlighting
- Parse and highlight common languages:
- Zig, Rust, C/C++
- JavaScript/TypeScript
- Python, Go, Java
- Janet, Lua, Lisp dialects
- Markdown, JSON, YAML
-
Semantic Features (Janet-configurable)
- Bracket matching with custom rules
- Indentation awareness per language
- Comment toggling with language-specific styles
- Code folding with custom fold markers
Phase 4: Advanced Editor Features
-
Multiple Buffers & Windows
- Buffer management system in Janet
- Split windows with customizable layouts
- Tab interface with user-defined styling
- Buffer-local configurations and hooks
-
Language Server Protocol (LSP)
- LSP client implementation in Janet
- Code completion with customizable sources
- Go to definition and references
- Error diagnostics with user-defined handlers
- Custom LSP server configurations
Phase 5: Ultimate Extensibility & Community
-
Advanced Plugin System
- Plugin manager with dependency resolution
- API versioning and compatibility layer
- Sandboxed plugin execution
- Community plugin registry integration
-
Performance & Optimization
- Janet code JIT compilation exploration
- Lazy loading for large files
- Async operations for non-blocking UI
- Memory optimization for large codebases
-
Community & Ecosystem
- Plugin development documentation
- Example configurations and themes
- Migration tools from other editors
- Community contribution guidelines
Architecture Philosophy
Strategic Hybrid Approach: This architecture balances flexibility with performance:
Zig Layer (Performance Core): Handles operations where performance matters:
- Complete UI rendering using existing optimized ui.zig
- TUI operations with proper child window management
- File I/O and system calls
- Tree-sitter integration for syntax highlighting
- Memory-intensive operations
Janet Layer (Logic Core): Provides maximum extensibility:
- All editor logic and behavior
- Complete customization and extensibility
- Hot-swappable configurations and key bindings
- Plugin system and user extensions
- Domain-specific languages for configuration
High-Level Bridge: Clean interface between layers:
- Janet computes editor state and decisions
- Zig renders state efficiently using native vaxis features
- Minimal bridge calls with semantic operations
- Clear separation of concerns
This approach maximizes both flexibility and performance, avoiding the overhead of primitive bridge operations while maintaining the extensibility benefits of Janet scripting (or so I hope!).
Building and Running
# Build the editor (add -Doptimize=ReleaseFast for production build)
zig build
# Run with a file
./zig-out/bin/koa demo.zig
# Run without arguments for empty buffer
./zig-out/bin/koa
Testing
zig build test
Key Bindings
Normal Mode
hjklor arrow keys - Movement (undo current selections)^orHome- Beginning of line$orEnd- End of linei- Enter insert modev- Enter select mode (preserves current selections):- Enter command modew- Move to next wordb- Move to previous wordPageUp- Move to top (20 lines jump)PageDown- Move to bottom (20 lines jump)o- Create line below and enter insert modeO- Create line above and enter insert modex- Select whole line or next line if the current one is already fully selectedd- Delete character under cursor or the current selection if one existsD- Duplicate selected lineDelete- Delete character under cursorBackspace- Delete character before cursor
Insert Mode
- arrow keys - Movement
Escape- Return to normal modeBackspace- Delete character before cursorDelete- Delete character under cursorEnter- Insert newlineTab- Insert 4 spaces (hardcoded for now)Home- Beginning of lineEnd- End of line
Select Mode
hjklor arrow keys - Movement (extends selection)^orHome- Beginning of line$orEnd- End of linedorDelete- Delete selectioni- Delete selection and enter insert modex- Select whole line or next line if the current one is already fully selectedw- Expand selection to next wordb- Shorten selection to previous wordEscape,v- Return to normal mode
Command Mode
Escape- Return to normal modew- Save fileW- Save file and quit (temporary until command mode gets better)q- Quit editor (does not handle unsaved changes confirmation yet!)
Contributing
This is a learning project exploring modal editor design with Zig. Contributions and suggestions are welcome!
License
MIT License - Feel free to use this code for learning and experimentation.