# mojibake - 文字化け A terminal text editor with Helix-style modal editing. > [!WARNING] > **Early development — not ready for daily use.** > > There is no yank/paste, no search, and no syntax highlighting. Undo works one > keystroke at a time rather than per edit. Treat this as a working foundation, > not an editor you should trust with real files yet. See [Status](#status) for > exactly what does and does not work. ```sh cargo install --path . moji ``` The crate is `mojibake-editor` (the name `mojibake` was already taken on crates.io by an unrelated encoder); the command is `moji`. A path that does not exist is created on write. With no path, `moji` opens an empty scratch buffer. ## Status ### Works - Opens, edits and saves UTF-8 files; UTF-16 with a BOM round-trips - CRLF and CR line endings are detected and preserved - Helix selection-first editing: `w` selects a word, so `wd` deletes one - Motions, goto, insert-entry, delete/change, undo/redo, paging - Counts (`5l`, `2w`) - Config-driven modal keymap in TOML; chords resolve without a timeout - Writes through symlinks, preserves permissions, restores on failure - Rendering is O(viewport) — a 200k-line file scrolls without lag ### Does not work yet - **No yank or paste.** `y`, `p`, `P` are unbound. - **No search.** `/`, `?`, `n`, `N` are unbound. - **No `f`/`t` motions.** They need pending-argument capture, which the keymap cannot express yet. - **Undo is per keystroke.** Typing `abc` in insert mode costs three undos; Helix commits one checkpoint when you leave insert mode. - **`:w ` ignores its argument** and writes to the original path. - **One file at a time.** No buffer list, no splits. - No syntax highlighting, no LSP, no multiple cursors, no soft wrap. ## Keybindings Bindings follow the [Helix default keymap](https://docs.helix-editor.com/keymap.html) and live in `.config/config.toml`. Defaults ship compiled in; user settings override them **per individual binding**, so rebinding one key keeps every default you did not mention. Editing is **selection-first**, like Helix and unlike Vim: a motion leaves a selection and an operator acts on it. There is no operator-pending state. | Mode | Keys | |---|---| | Motion | `h` `j` `k` `l`, `w` `b` `e`, `W` `B` `E` | | Goto | `gg` `ge` `gh` `gl` `gs` | | Selection | `x` `;` `%` `v` `Alt-;` | | Insert | `i` `a` `I` `A` `o` `O` | | Change | `d` `c`, `u` undo, `U` redo | | Scroll | `Ctrl-u` `Ctrl-d` half page, `Ctrl-b` `Ctrl-f` full page | | Command | `:w` `:q` `:wq` `:x` `:q!` `:w!` | Counts work as a prefix: `5l`, `12j`. ## Configuration TOML only, at `$MOJIBAKE_CONFIG/config.toml`. See `.config/config.toml` for the annotated defaults. ```toml [editor] scrolloff = 5 insert_final_newline = true [keybindings.normal] "" = "GotoFileStart" "" = "PageCursorHalfDown" ``` ## Roadmap Ordered by what most blocks real use. ### 1 — Blocking daily use - [ ] Yank and paste: `y`, `p`, `P`, plus a register - [ ] Undo checkpoints — group an insert session into one step (Helix commits on leaving insert mode; see `Command::NormalMode`) - [ ] Search: `/`, `?`, `n`, `N` - [ ] Pending-argument capture in the keymap, then `f` `t` `F` `T` and `r` - [ ] Honour the `:w ` argument instead of discarding it (`run_command_line` binds it as `_arg`) - [ ] Prompt on `:q` with unsaved changes rather than only refusing ### 2 — Editor features - [ ] Multiple buffers and `:b` / `gn` / `gp` - [ ] Auto-indent on newline; `>` and `<` to shift lines - [ ] `J` join lines, `~` switch case, `.` repeat - [ ] Match mode `m` — matching bracket, surround - [ ] Soft wrap (reworks the viewport anchor — see `MJB-DR-003`) - [ ] Multiple cursors (`Selection` is already shaped for it — see `MJB-DR-005`) ### 3 — Language support - [ ] tree-sitter syntax highlighting - [ ] `languages.toml` - [ ] LSP client: diagnostics, completion, goto-definition ### 4 — Project and process - [ ] CI: build, clippy, test, `scripts/check-trace.sh`, coverage - [ ] Resolve the six open derived requirements in `docs/requirements/derived.md` — each needs a judgement, not code - [ ] Decide on ropey: stay on `2.0.0-beta.1` or move to stable `1.6.1` (see `docs/reviews/library-selection.md`) - [ ] Decide whether to publish to crates.io at all, or self-host only - [ ] Replace the `unwrap` calls in `src/tui.rs::Drop` inherited from the application template ## Development ```sh cargo build cargo clippy --all-targets -- -D warnings cargo test ./scripts/check-trace.sh cargo llvm-cov --summary-only test ``` `direnv` users get `.envrc`, which points config and data at the working tree. ### Architecture - `src/buffer/` — the editor core: rope document, selection, transactions, motions, viewport, keymap. No `ratatui` dependency, so it is testable without a terminal. - `src/components/buffer.rs` — the only widget; renders the visible window. - `src/app.rs` — event loop and global key routing. Text is held in a [ropey](https://github.com/cessen/ropey) rope and addressed by **byte** offset throughout. Rendering is O(viewport): the view is anchored by the byte offset of the first visible line, and only that window is walked, so per-frame cost does not scale with file size. ## Process Developed to **DO-178C DAL-C**. Start with **[`docs/process.md`](docs/process.md)**, which explains the requirement artifacts, the ID system, and what a commit must satisfy. - `docs/process.md` — the system, and the commit rules - `docs/requirements/` — high-level, low-level, and derived requirements - `docs/traceability/trace.md` — HLR → LLR → source → test matrix - `docs/reviews/` — review checklists and library-selection rationale Every low-level requirement is tagged in source as `// MJB-LLR-nnn` and has a test named `mjb_llr_nnn_*`. The matrix is checked mechanically, not by inspection: ```sh ./scripts/check-trace.sh ``` It verifies traceability in **both** directions — requirements with no implementation or no test, and tests naming a requirement that no longer exists. All three sets must be empty. Run it before every commit. `git config commit.template .gitmessage` sets up the commit format; the template lists the change classes and the pre-commit gate. Current: 294 tests, clippy clean at `-D warnings`, 98/98 requirements traced, 96.2% statement coverage of `src/buffer/**`. ## License BSD 2-Clause. See [LICENSE](LICENSE).