Tags: esmuellert/codediff.nvim
Tags
feat: inline (unified) diff layout with treesitter syntax highlighting ( #281) ## Summary Add a new inline diff layout as an alternative to side-by-side. Deleted lines appear as virtual line overlays with treesitter syntax highlighting, providing a VSCode-style unified diff experience. Set `diff.layout = "inline"` to enable. Default remains `"side-by-side"` — no breaking changes. ## Features - **Inline diff rendering** — single-window layout with deleted lines as `virt_lines` overlays - **Treesitter syntax highlighting** on virtual lines — deleted code retains keyword, string, function colors merged with diff backgrounds - **Character-level diff highlights** on both virtual lines (deleted) and real lines (inserted) - **Full mode support** — works with standalone, explorer, and history modes - **Shared keymaps** — `do` reverts hunk to original, `dp` is no-op (buffer already has modified content), navigation/textobject/staging all work - **44 new tests** covering all inline scenarios with 0 regressions ## Changes ### New files - `lua/codediff/ui/inline.lua` — core renderer (virt_lines, char highlights, treesitter syntax) - `lua/codediff/ui/view/inline_view.lua` — inline engine (create/update/rerender/show_single_file) - `tests/ui/inline_spec.lua` — 10 renderer unit tests - `tests/ui/inline_syntax_spec.lua` — 8 treesitter syntax tests - `tests/ui/view/inline_standalone_spec.lua` — 14 standalone view tests - `tests/ui/view/inline_explorer_spec.lua` — 4 explorer mode tests - `tests/ui/view/inline_history_spec.lua` — 4 history mode tests - `tests/ui/view/inline_interaction_spec.lua` — 12 interaction tests (nav, do, autoscroll, textobject, lifecycle) ### Modified files (additive, gated by `layout == "inline"`) - `config.lua` — `layout = "side-by-side"` option - `view/init.lua` — router dispatches to inline engine - `keymaps.lua` — layout-aware do/dp/find_hunk_at_cursor - `navigation.lua` — inline uses modified line numbers - `auto_refresh.lua` — inline render branch - `lifecycle/cleanup.lua` — threshold for inline sessions - `lifecycle/state.lua` — inline namespace clear + resume render - `explorer/render.lua` — A/D/?? routing to inline_view.show_single_file - `history/render.lua` — A/D routing to inline_view.show_single_file ## Usage ```lua require('codediff').setup({ diff = { layout = 'inline' }, }) ``` ## Testing - 44 new inline-specific tests - All existing tests pass (5 made layout-resilient) - Full suite passes with both `inline` and `side-by-side` as default
feat: add close_on_open_in_prev_tab option for gf keymap (#280) ## Summary When enabled, pressing `gf` closes the codediff tab after opening the file in the previous tab. Default is `false` (existing behavior preserved). Closes #276 ## Changes - **config.lua**: Added `close_on_open_in_prev_tab = false` option under `keymaps.view` - **keymaps.lua**: After `open_in_prev_tab` navigates to the file, optionally closes the diff tab - **README.md**: Documented new option - **doc/codediff.txt**: Updated vimdoc ## Usage ```lua require('codediff').setup({ keymaps = { view = { close_on_open_in_prev_tab = true, }, }, }) ```
refactor: view engine extraction + single-pane display for A/D/?? fil… …es (#279) ## Changes ### Refactor: View engine extraction - Split `view/init.lua` (832 lines) into three focused modules: - `view/init.lua` (47 lines): thin router - `view/side_by_side.lua`: side-by-side diff engine - `view/panel.lua`: shared explorer/history panel setup - Pure code move, no behavior change ### Feature: Single-pane display for added/deleted/untracked files - Close the empty pane instead of shrinking it to 1px when a file only exists on one side - Handles all modes: explorer (staged/unstaged/two-revision) and history - Layout manager properly sizes the remaining pane - 9 new layout test cases (Cases 10-18) - Consolidates 4 show_* functions into one `show_single_file()` core ### Testing - All existing tests pass (0 regressions) - 25 layout tests total (16 existing + 9 new)
fix: defer heavy module loading for faster startup (#272) (#275) ## Summary Reduces codediff.nvim's startup impact from **~15ms to ~0.6ms** (96% reduction) by deferring heavy module loading until the user first invokes `:CodeDiff`. Closes #272 ## Problem `plugin/codediff.lua` eagerly loaded 42 Lua modules + a C library via FFI at startup, even when the user never used any diff functionality. This consumed ~15ms on cold start and ~8ms on warm start. ### Before (startup profiling) ``` startup: 48.9 codediff.lua 19.42 39.75 ███████████▊ codediff.ui 18.75 38.38 ███████████▌ codediff.ui.view 18.38 37.62 ███████████▎ codediff.ui.explorer 2.12 4.33 █▎ codediff.ui.auto_refresh 1.75 3.57 █ codediff.core.diff 1.09 2.24 ▌ ``` ### After ``` startup: 7.3 codediff.lua 0.58 7.92 ██▎ codediff.ui.highlights 0.31 4.32 █▎ codediff.config 0.18 2.47 ▌ codediff.core.virtual_file 0.09 1.20 ▎ ``` ## Changes - **`plugin/codediff.lua`**: Replace 4 eager top-level `require()` calls with 2 lightweight ones (`codediff.ui.highlights` + `codediff.core.virtual_file`). Wrap the `:CodeDiff` command handler to lazy-load `codediff.commands` on first invocation. - **`plugin/vscode-diff.lua`**: Lazy-wrap the `:VscodeDiff` command handler. - **`lua/codediff/ui/init.lua`**: Remove eager `lifecycle.setup()` call (was registering global autocmds at startup). - **`lua/codediff/ui/view/init.lua`**: Add once-guard to call `lifecycle.setup()` on first `view.create()`, so cleanup autocmds are only registered when actually needed. ## What loads at startup (~0.6ms) - `codediff.ui.highlights` — highlight group definitions - `codediff.core.virtual_file` — `codediff://` URL scheme registration - Command registration (negligible) ## What's deferred to first `:CodeDiff` invocation - C diff library (FFI + `ffi.load()`) - Explorer, History, Conflict UI modules - Lifecycle autocmds (`WinClosed`/`TabClosed`/`BufEnter`) - Git operations module - View keymaps, navigation, layout ## Testing - ✅ All plenary tests pass (37 files, 0 failures) - ✅ E2E validation: `:CodeDiff file`, `:VscodeDiff`, lifecycle cleanup, multi-tab all work - ✅ 5 profiling runs confirm consistent ~0.6ms startup
feat: restore file to comparison revision (#274) ## Summary Closes #270 When comparing against a specific commit (e.g. `origin/HEAD`, a commit hash), the restore action (`X`) now reverts the file to that revision instead of the index version. This matches diffview.nvim's behavior. ### Changes - Added optional `source` parameter to `git.restore_file()` with backward compatibility for existing callers - Explorer actions now pass `base_revision` as the source revision - 6 new tests for restore_file with/without source revision ### Testing - All existing tests pass - 6 new restore tests (all pass)
feat(ui): add 3do conflict viewer (#252) This is a pull request that adds config parameters to where the 3-way diff view would spawn the current state window. Originally, we could only do it at the bottom with a fixed height. - Add another mode for putting the current state of the conflicting file in center. - Add configuration parameters where we can now spawn the window at the center or configure the bottom window height. ## Notes It would be nicer if we could do these configuration parameters in a table, but it would kind of break the current config format for that section.
feat: hunk textobject (ih) (#269) ## Summary Adds `ih` textobject for diff hunks, enabling standard Vim operations on hunks: - `vih` — select hunk - `yih` — yank hunk - `dih` — delete hunk - `cih` — change hunk Works in both operator-pending and visual modes on diff buffers. Uses existing `find_hunk_at_cursor()` infrastructure. Configurable via `keymaps.view.hunk_textobject`. Closes #144
PreviousNext