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
1 change: 1 addition & 0 deletions .claude/commands/complete-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update all markdown files, archive anything that we no longer need to read into SESSION_HISTORY.md, commit and push
2 changes: 1 addition & 1 deletion .claude/commands/complete-session.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Update all markdown files, archive anything that we no longer need to read into SESSION_HISTORY.md, commit and push
Update all markdown files, archive anything that we no longer need to read into SESSION_HISTORY.md
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "vimcode"
version = "0.3.7"
version = "0.3.8"
edition = "2021"
description = "Vim-like code editor with GTK4 and tree-sitter"
license = "MIT"
Expand Down
31 changes: 22 additions & 9 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@
---

## Recently Completed
- **Session 182**: LaTeX Extension (Parts A + C) — **Part C**: LaTeX text objects (`ie`/`ae` environment, `ic`/`ac` command, `i$`/`a$` math) and motions (`]]`/`[[` section jumps, `]m`/`[m`/`]M`/`[M` environment jumps, `][`/`[]` for `\end{}`); 22 new tests (4391 total). **Part A**: LaTeX registry extension in `vimcode-ext` repo — manifest.toml with texlab LSP, `latex.lua` with `<leader>ll` compile, `<leader>lv` view PDF, `<leader>lc/lC` clean, `<leader>le` log, `<leader>lt` TOC panel; `:LatexCompile`/`:LatexView`/`:LatexClean`/`:LatexLog`/`:LatexToc` commands. Also fixed: `vcd <dir>` opens folder, "Open Workspace From File…" renames, TUI folder picker mouse clicks.
- **Session 181**: LaTeX Extension (Part B) — tree-sitter LaTeX syntax highlighting (18th language); vendored grammar v0.3.0 via build.rs+cc; LaTeX-aware spell checking (inverted logic: check prose, skip commands/math); `check_line()` API updated from `bool` to `Option<SyntaxLanguage>`.
- **Session 180b**: Spell Checker Bug Fixes + UI Polish — z= numbered suggestion list with single-key selection; fixed markdown spell checking (SyntaxLanguage::from_path vs empty highlights); undo/dirty tracking for spell replacements; GTK scrollbar width halved (10→5px); text overflow behind scrollbar fixed; group divider grab fixed (proper editor bounds in hit-test/drag).
- **Session 180**: Spell Checker — `src/core/spell.rs` with spellbook 0.4 (pure-Rust Hunspell); bundled en_US dictionary compiled into binary; user dictionary at `~/.config/vimcode/user.dic`; tree-sitter-aware (comments/strings in code, all text in plain text/Markdown); `]s`/`[s`/`z=`/`zg`/`zw` keybindings; `spell`/`spelllang` settings; `:set spell`/`:set nospell`; "Toggle Spell Check" palette entry; cyan dotted underline (GTK) + colored underline (TUI); 60 new tests (4314 total).
- **Session 179**: Resize Tab Groups — GTK Alt+,/Alt+. keyboard; TUI mouse drag on group dividers; both backends now have full keyboard + mouse group resize.
- **Session 178**: Version Querying — `--version` / `-V` CLI flag on both binaries; Help > About shows version; `env!("CARGO_PKG_VERSION")` compile-time.
- **Session 177**: Fix Wrap Mode Mouse Click — GTK `view_row_to_buf_pos_wrap()` uses word-wrap segments for correct visual-row-to-buffer-line mapping; TUI click/drag add `segment_col_offset`. Fixes BUGS.md wrap click issue.
- **Session 176**: GTK Performance — Lazy tree loading (one level at a time, expand on demand), Open Folder fix (set_current_dir + engine.cwd for tree refresh).
- **Session 191**: Subprocess stderr safety audit — Audited all `Command::new()` call sites (~50); only `registry.rs` `download_script()` had inherited stderr (`.status()` without redirect); fixed by adding `.stdout(null()).stderr(null())`. All other sites already use `.output()` (auto-captures) or explicit `Stdio` redirection. 4511 tests.
- **Session 190**: LSP Go-to-Definition Fix + Kitty Keyboard Fix — Fixed `gd`/`gi`/`gy` appearing to hang (message not cleared after successful jump); Kitty `shift_map_us()` fix for shifted symbols; context menu mode-aware shortcuts; LSP response robustness (string ID fallback, `unwrap_or` on definition/hover parse). 4511 tests.
- **Session 189**: VSCode-style Editor Context Menu — Full 9-item editor right-click menu; engine-driven for both GTK and TUI; 8 new tests (4510 total).
- **Session 188**: Centralize Context Menus + Editor Right-Click — GTK context menus driven by engine items; 4 new tests (4501 total).
- **Session 187**: Tab Context Menu Splits Fix — Fixed GTK/TUI split inconsistency; added 4 split options; 4 new tests (4498 total).

> Sessions 180b and earlier in **SESSION_HISTORY.md**.
> Sessions 189 and earlier in **SESSION_HISTORY.md**.

## Roadmap
- [x] **Spell checker** — Vim-compatible `]s`/`[s`/`z=`/`zg`/`zw`; spellbook Hunspell parser; bundled en_US dictionary; tree-sitter-aware; `spell`/`spelllang` settings; user dictionary at `~/.config/vimcode/user.dic`
Expand Down Expand Up @@ -74,5 +71,21 @@
- [x] **AI inline completions** — ghost-text completions from AI provider interleaved with LSP ghost text; separate `ai_completions` setting (default false to avoid unexpected API costs); debounced after 500ms idle in insert mode; Tab accepts whole suggestion, `Alt-]`/`Alt-[` cycle through alternatives
- [x] **Swap file crash recovery** — Vim-like swap files (`~/.config/vimcode/swap/`); FNV-1a path hashing; atomic writes (`.tmp` + rename); PID-based stale detection; `[R]ecover/[D]elete/[A]bort` recovery dialog; `:set swapfile`/`:set updatetime=N`; periodic writes via `tick_swap_files()`; cleanup on shutdown

### Context Menus
- [x] **Context menu action polish** — Two-step "Select for Compare" → "Compare with 'file'" diff flow; fixed GTK copy_relative_path and open_side bugs; engine-driven action handling; 8 new tests

### Explorer
- [x] **Drag-and-drop file/folder move** — Drag files and folders in the explorer tree to move them to a new location. Should work in both TUI (mouse drag) and GTK (native DnD) backends. Visual feedback during drag (insertion indicator, highlight target folder). Confirmation dialog with clickable buttons.
- [x] **Inline rename in explorer** — Rename files/folders directly in the explorer tree (as close to in-place editing as possible), rather than via a separate prompt. In GTK this can be a native editable cell; in TUI, render an input field overlaid on the tree row.
- [x] **Copy/paste files in explorer** — "Copy" and "Paste" items in the right-click context menu. Copy stores the source path; Paste into a different folder duplicates with the same name, Paste into the same folder prompts for a new name (inline in the tree). Support both single files and folders (recursive copy).
- [x] **Context menu popup clamping** — TUI context menu popup rendering moved after status/command line in draw order so popups are no longer painted over by lower UI elements. Position clamping ensures popup stays within terminal bounds.

### Editor
- [x] **VSCode-style editor right-click context menu** — Full 9-item editor right-click: Go to Definition (`gd`), Go to References (`gr`), Rename Symbol (`<leader>rn`), Open Changes (`gD`), Cut, Copy, Paste, Open to the Side (vsplit), Command Palette (`Ctrl+Shift+P`). LSP items disabled without active server; Cut/Copy disabled without visual selection. Both GTK and TUI backends.

### Robustness
- [x] **Centralize context menu definitions** — GTK backend hardcodes its own `gio::Menu` items separately from the engine's `open_explorer_context_menu()` / `open_tab_context_menu()`. This causes drift (e.g. "Open in Integrated Terminal" was missing from GTK). GTK should read from the engine's `ContextMenuState.items` to build its native menus, so new items only need to be added once in the engine.
- [x] **Subprocess stderr safety audit** — Audit all `Command::spawn()` calls across the codebase to ensure stdout/stderr are redirected (null or piped). Unguarded spawns let child process output corrupt the TUI display. Fixed `xdg-open`/`open` calls; need to verify LSP, DAP, git, terminal, and any other subprocess spawns are safe.

### Documentation
- [x] **GitHub Wiki** — 9 pages: Home, Getting Started, Key Remapping, Settings Reference, Extension Development, Lua Plugin API, Theme Customization, DAP Debugger Setup, LSP Configuration; README Documentation section links to wiki
34 changes: 17 additions & 17 deletions PROJECT_STATE.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# VimCode Project State

**Last updated:** Mar 14, 2026 (Session 182LaTeX Extension: Parts A + C) | **Tests:** 4391
**Last updated:** Mar 16, 2026 (Session 191Subprocess stderr safety audit) | **Tests:** 4511

> Feature documentation lives in **README.md**.
> Per-session implementation notes through Session 180b are in **SESSION_HISTORY.md**.
> Per-session implementation notes through Session 191 are in **SESSION_HISTORY.md**.

---

Expand All @@ -26,18 +26,18 @@ When implementing a new key/command, add tests covering:

## Recent Work

### Session 182LaTeX Extension: Parts A + C (Mar 14, 2026)
- **LaTeX text objects**: `ie`/`ae` (inner/around `\begin{env}...\end{env}`, nested-aware), `ic`/`ac` (inner/around `\command{...}`, LaTeX only), `i$`/`a$` (inner/around math: `$...$`, `$$...$$`, `\[...\]`, `\(...\)`)
- **LaTeX motions**: `]]`/`[[` jump to next/previous `\section`/`\chapter`/`\subsection`/`\subsubsection`/`\part`/`\paragraph`/`\subparagraph` (including starred variants); `][`/`[]` jump to next/previous `\end{}`; `]m`/`[m` jump to next/previous `\begin{}`; `]M`/`[M` jump to next/previous `\end{}`
- **Registry extension (vimcode-ext repo)**: `latex/manifest.toml` with texlab LSP config; `latex/latex.lua` with vimtex-inspired keymaps (`<leader>ll` compile, `<leader>lv` view, `<leader>lc`/`lC` clean, `<leader>le` log, `<leader>lt` TOC); TOC sidebar panel via `vimcode.panel` API; `:LatexCompile`/`:LatexView`/`:LatexClean`/`:LatexCleanAll`/`:LatexLog`/`:LatexToc` commands
- **Bug fixes**: `vcd <directory>` opens folder as workspace (TUI + GTK); "Open Workspace From File…" creates/opens `.vimcode-workspace` in current file's directory; TUI folder picker mouse click support
- 22 new tests (4391 total)

### Session 181LaTeX Extension: Tree-sitter Syntax + Spell Checking (Mar 14, 2026)
- **Tree-sitter LaTeX support**: Added `SyntaxLanguage::Latex` — 18th built-in language. Vendored `tree-sitter-latex` v0.3.0 grammar (language version 14, compatible with tree-sitter 0.24) under `vendor/tree-sitter-latex/`. Compiled via `build.rs` + `cc` crate. Highlight query covers comments, commands (`generic_command`), sections, math (inline/displayed/environment), labels, citations. Breadcrumb scopes: `generic_environment`, `section`, `chapter`, `subsection`, `subsubsection`.
- **File extensions**: `.tex`, `.bib`, `.cls`, `.sty`, `.dtx`, `.ltx`
- **LaTeX-aware spell checking**: Changed `check_line()` signature from `has_syntax: bool` to `syntax_lang: Option<SyntaxLanguage>`. LaTeX mode inverts the logic — checks all prose text EXCEPT words in `keyword` (commands) and `type` (math) scopes. Added `is_in_latex_command_or_math()` helper.
- **Flatpak**: Regenerated `flatpak/cargo-sources.json` with new `cc` and `tree-sitter-language` dependencies.
- 15 new tests across syntax.rs (8: detection + highlighting) and spell.rs (3: LaTeX prose/commands/math + existing tests updated for new API) — 4331 total

> Sessions 180b and earlier archived in **SESSION_HISTORY.md**.
### Session 191Subprocess stderr safety audit (Mar 16, 2026)
- Audited all ~50 `Command::new()` call sites across the codebase
- Only one unsafe site found: `registry.rs` `download_script()` used `.status()` with inherited stderr — could corrupt TUI display during extension downloads
- Fixed by adding `.stdout(Stdio::null()).stderr(Stdio::null())` to the curl call
- All other sites already safe: `.output()` auto-captures both streams; `.spawn()` calls all have explicit `Stdio` redirection
- Breakdown: `git.rs` (~20 calls, all `.output()`), `engine.rs` (~8 calls, all redirected or `.output()`), `ai.rs` (3 curl `.output()`), `dap.rs`/`lsp.rs` (`.spawn()` with explicit piped/null), `dap_manager.rs`/`lsp_manager.rs` (all `.output()`)

### Session 190LSP Go-to-Definition Fix + Kitty Keyboard Fix (Mar 16, 2026)
- **Context menu mode-aware shortcuts**: Editor right-click context menu shows Vim shortcuts (`gd`, `gr`, `gD`) in Vim mode and VSCode shortcuts (`F12`, `Shift+F12`, `F2`) in VSCode mode.
- **Kitty terminal ":" fix**: `shift_map_us()` in TUI translates base key + SHIFT modifier to correct shifted character when Kitty's `REPORT_ALL_KEYS_AS_ESCAPE_CODES` keyboard enhancement sends `; + Shift` instead of `:`.
- **LSP `gd` "hanging" fix**: `DefinitionResponse`, `ImplementationResponse`, and `TypeDefinitionResponse` handlers now clear `self.message` after processing. Previously "Jumping to definition..." message persisted after successful jump, appearing as if the operation was still pending.
- **LSP response robustness**: Added `unwrap_or()` fallback for definition/hover responses (empty result instead of silent drop); string ID fallback for response parsing (some servers echo IDs as strings).
- LSP debug logging infrastructure (gated behind `VIMCODE_LSP_DEBUG` env var) retained in `lsp.rs` reader thread.

> Sessions 189 and earlier archived in **SESSION_HISTORY.md**.
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ For detailed how-to guides and configuration references, see the **[VimCode Wiki
- **First-class Vim mode** — deeply integrated, not a plugin
- **Cross-platform** — GTK4 desktop UI + full terminal (TUI) backend
- **CPU rendering** — Cairo/Pango (works in VMs, remote desktops, SSH)
- **Clean architecture** — platform-agnostic core, 4391 tests, zero async runtime dependency
- **Clean architecture** — platform-agnostic core, 4511 tests, zero async runtime dependency

> **Note:** VimCode does not implement VimScript. Extension and scripting is handled via
> the built-in Lua 5.4 plugin system. The goal is full Vim *keybinding* and *editing*
Expand Down Expand Up @@ -92,6 +92,7 @@ VimCode requires **GTK4 development libraries** for the GUI backend. The TUI mod
**Platform notes:**
- **macOS:** GTK4 works via Homebrew; this is not a native AppKit app
- **Windows:** Use the MSYS2 MinGW64 shell and set `rustup default stable-x86_64-pc-windows-gnu`
- **Nerd Font recommended:** VimCode uses Nerd Font icons throughout the UI — the file explorer, activity bar, tab bar, terminal toolbar, and debug panel all rely on Nerd Font glyphs. Install any [Nerd Font](https://www.nerdfonts.com/) (e.g. JetBrainsMono Nerd Font, FiraCode Nerd Font) and set it as your terminal font (TUI) or configure `font_family` in `settings.json` (GTK). Without a Nerd Font, icons will display as missing-glyph boxes.

### Build & run

Expand Down Expand Up @@ -269,13 +270,20 @@ cargo fmt

### Multi-File Editing

VimCode has three spatial layers that combine Vim and VSCode concepts:
- **Windows** — Vim-style splits *within* a single tab (`:split`, `:vsplit`, `Ctrl-W s/v`)
- **Tabs** — pages within an editor group, like Vim tabs or browser tabs (`gt`/`gT`, `:tabnew`)
- **Editor Groups** — VSCode-style side-by-side tab bars (`Ctrl+\`, `Ctrl-W e/E`), each with its own set of tabs

The tab context menu offers both: "Split Right/Down" creates a Vim window split inside the current tab, while "Split Right/Down to New Group" creates a new editor group with its own tab bar.

**Buffers**
- `:bn` / `:bp` — next/previous buffer
- `:b#` — alternate buffer
- `:ls` — list buffers (shows `[Preview]` suffix for preview tabs)
- `:bd` — delete buffer

**Windows**
**Windows** (splits within the current tab — not to be confused with Editor Groups)
- `:split` / `:vsplit` — horizontal/vertical split
- `:close` — close window; `:only` — close all other windows
- `Ctrl-W h/j/k/l` — move focus between panes (or `:wincmd h/j/k/l`)
Expand All @@ -288,7 +296,7 @@ cargo fmt
- `Ctrl+Tab` / `Ctrl+Shift+Tab` — MRU tab switcher popup (cycles most-recently-used tabs; Enter confirms, Escape cancels); release modifier to auto-confirm (GTK)
- `Alt+t` — MRU tab switcher (works in both TUI and GTK; hold Alt and press `t` to cycle; release Alt or wait 500ms to confirm in TUI)

**Editor Groups (VSCode-style split panes, recursive)**
**Editor Groups / Tab Groups (VSCode-style split panes, recursive)**
- `Ctrl+\` — split editor right (any group can be split again for nested layouts)
- `Ctrl-W e` / `Ctrl-W E` — split editor right / down
- `Ctrl+1` through `Ctrl+9` — focus group by position (tree order)
Expand Down Expand Up @@ -424,7 +432,7 @@ For full details on adapters, launch.json, conditional breakpoints, and the debu
- **Auto-refresh** — filesystem changes are detected automatically (no manual refresh needed)
- **Rename:** `F2` (GTK inline) / `r` (TUI prompt) — rename file or folder in-place
- **Move:** Drag-and-drop (GTK) / `M` key prompt (TUI) — move to another folder; full path pre-filled with cursor key editing (Left/Right/Home/End/Delete)
- **Right-click context menu (GTK):** New File, New Folder, Rename, Delete, Copy Path, Select for Diff
- **Right-click context menu:** New File, New Folder, Rename, Delete, Copy Path, Copy Relative Path, Open to Side, Open to Side (vsplit), Select for Compare / Compare with Selected (opens diff view), Reveal in File Manager; tab bar: Close, Close Others, Close to Right, Close Saved, Split Right/Down; editor area: Go to Definition, Go to References, Rename Symbol, Open Changes, Cut, Copy, Paste, Open to Side (vsplit), Command Palette
- **Preview mode:**
- Single-click → preview tab (italic/dimmed, replaced by next single-click)
- Double-click → permanent tab
Expand Down Expand Up @@ -805,6 +813,8 @@ Full editor in the terminal via ratatui + crossterm — feature-parity with GTK.
| `n` / `N` | Next / previous match |
| `m{a-z}` / `'{a-z}` | Set mark / jump to mark |
| `q{a-z}` / `@{a-z}` | Record macro / play macro |
| `q:` | Open command-line history window (Enter executes, `q` closes) |
| `q/` / `q?` | Open search history window (Enter searches, `q` closes) |
| `gt` / `gT` | Next / previous tab |
| `Ctrl+Tab` / `Ctrl+Shift+Tab` | MRU tab switcher (forward / backward) |
| `Alt+t` | MRU tab switcher (TUI + GTK compatible) |
Expand All @@ -815,6 +825,8 @@ Full editor in the terminal via ratatui + crossterm — feature-parity with GTK.
| `gy` | Go to type definition (LSP) |
| `gs` | Stage hunk (in `:Gdiff` buffer) |
| `gD` | Diff peek — preview hunk popup with Revert/Stage |
| `gR` | Enter virtual replace mode (expands tabs to spaces when overwriting) |
| `g+` / `g-` | Go to newer / older text state (chronological undo timeline) |
| `K` | Show hover info (LSP) |
| `]c` / `[c` | Next / previous change (works on real files + diff buffers) |
| `]d` / `[d` | Next / previous diagnostic (LSP) |
Expand All @@ -825,6 +837,7 @@ Full editor in the terminal via ratatui + crossterm — feature-parity with GTK.
| `[{` / `]}` | Jump to unmatched `{` / `}` |
| `[(` / `])` | Jump to unmatched `(` / `)` |
| `[*` / `]*` | Jump to comment block start / end (`/*`/`*/`) |
| `[#` / `]#` | Jump to previous / next unmatched `#if`/`#else`/`#endif` preprocessor directive |
| `[z` / `]z` | Jump to fold start / end |
| `do` | Diff obtain (pull line from other diff window) |
| `dp` | Diff put (push line to other diff window) |
Expand Down
Loading
Loading