A sidebar on Ctrl+B: drill's first plugin, clickable to the last gesture - #18
A sidebar on Ctrl+B: drill's first plugin, clickable to the last gesture#18jainal09 wants to merge 11 commits into
Conversation
…to a fault drill promised "no plugins" and mostly still keeps it: nothing here touches startup. Ctrl+B (n/i) and Cmd+B (n/i/t -- ^B belongs to readline in the REPL, Cmd+B rides CSI-u past python) lazily dofile explorer.lua, which only then puts three pinned checkouts on 'runtimepath': nvim-tree for the tree, volt and menu for the right-click work to come. vendor.sh fetches them by bare SHA -- shallow, detached, reproducible -- so there is still no plugin manager, just a table with three rows. Never press Ctrl+B and you run the config you always ran, byte for byte. The toggle opens with focus=false: the sidebar appears, the caret stays in your code, and type_here() keeps the one promise on both directions. ASCII glyphs on purpose (stock fonts have no nerd runes), netrw untouched for bare `d`, window_picker excludes ensure a file opened from the tree can never land in the interpreter. <D-b> had to stop being the example of a floored chord: suite_config re-spells its floor case with <D-g>, and suite_options now asserts the toggle is bound exactly where claimed -- and NOT in cmdline, where ^B is cursor-to-start at the / prompt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"No plugins" removed the site dir from 'runtimepath' and called it isolation, but startup packages load from 'packpath', which still held it -- measured: a plugin dropped in ~/.local/share/nvim/site/pack/x/start/ loaded happily inside drill. The day drill gains its one deliberate plugin is the day the accidental ones should stop: site and site/after come off both options, and suite_options now asserts the seal so it cannot quietly reopen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The deal-breaker was "press a to make a file" -- keyboard folklore where a button belongs. The tree window now carries a winbar toolbar with real clickable [+ File] and [+ Folder] regions (%@handler@ click support, core since 0.8). Both seed the name prompt from the row the cursor is on -- a folder means "in here", a file means "next to me" -- and the folder button does NOT ride api.fs.create's trailing-slash convention: that is the same folklore, one key deeper. mkdir -p, reload, done. One click opens a file and one click folds a folder -- no double-click. The release acts on the node the press already parked the cursor on, and a guard on getmousepos().line == 0 keeps winbar clicks with the buttons they hit. The bug worth the commit: drill lives in insert mode, and a mouse press from insert FOCUSES the tree while STAYING in insert -- measured, mode "i" inside the NvimTree buffer -- so the release arrived in a mode no tree mapping owns and every click silently ate itself. Entering the tree now lands you in Normal, by any route, and every gesture can assume it. suite_tree is the proof: 19 cases on a real pty writing real SGR sequences -- toggle both chords, focus that never leaves your code, window-local virtualedit, toolbar clicks all the way to files appearing on disk. run.sh gains a vendor.sh preflight so the gate fetches the pins before it needs them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
menu+volt draw it and own the item clicks; the items are drill's own -- plain ASCII labels (the upstream set is nerd-font glyphs, tofu on a stock font, and its "New folder" is the trailing-slash convention wearing a menu costume). New file, New folder, Open, Open in split, Rename, Cut, Copy, Paste, Delete, every one acting on the row the right-click parked the cursor on. The mapping is global, and that is forced, not chosen: a right-click ON the tree while you are typing in the file is delivered to the FILE buffer's maps, so a tree-local mapping would never fire. It is still late -- registered only once the sidebar has ever been toggled -- and everywhere outside the tree it re-feeds the unmapped key, so the file buffer keeps stock right-click behavior, asserted on the pty from both sides: drill's menu drawn in the tree, the built-in one (and not ours) in the file. The suite also clicks an ITEM by its float coordinates -- border corner one row below the mouse, "Open" four text lines in -- and watches d.py open, the float close, and insert mode return. Menus are drawn, not queryable, so these cases read the escape-stripped pty stream, the quit_drive technique. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…moves No tree plugin ships drag-and-drop, but the events were always there: the press parks the cursor on the source row, the first <LeftDrag> report snapshots that node, and the release resolves the row under the mouse into a destination. Cut, one paste, done -- onto a folder means INTO it, onto a file means NEXT TO it. A release back on the source row is not a drag: that is a trackpad click that jittered, the gesture mouse_drive.py already defends, and it falls through to the ordinary click. Ctrl-click toggles a mark (rendered *), and dragging any MARKED row takes the whole marked set -- cut accumulates, one paste moves them all, marks clear. Dragging an unmarked row moves it alone and leaves your selection standing. The mapping is global-but-late like right-click, and for the same routing reason; outside the tree it re-feeds a plain press, which is byte-for-byte what the mouse section's Ctrl-stripping maps already did (stock <C-LeftMouse> is a tag jump that wedges a tagless editor behind E426). Eight new pty cases drive it for real: mark two, drag the unmarked third and watch it travel alone, drag a marked one and watch the pair follow, and a one-cell jitter that must open a file and move nothing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ng a click Eleven cases for the layout the sidebar creates. <C-e> still opens the REPL botright -- full width, under the tree, the IDE shape -- and the tree survives it. A file clicked in the tree lands in the FILE window, never the interpreter (the window_picker excludes terminals, and the case would catch it lying). And the netrw contract holds in the tree too: Ctrl+S and Ctrl+E pressed there wedge nothing, spawn nothing, and Ctrl+B from inside the tree still closes it and leaves you typing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…0.10
The manifest gains explorer.lua and vendor.sh (both hardcoded lists, as
before), and after the copy the installer runs vendor.sh to bring the three
pinned checkouts down. FEATURE-level on purpose: an offline install costs
Ctrl+B and nothing else, the message says exactly what to rerun, and at the
pins the fetch is an offline no-op so reinstalls pay nothing. git joins the
dependency probe the same way -- a note, never a bail.
The version gate moves 0.9 -> 0.10, which is what the pinned nvim-tree
actually requires; explorer.lua carries its own has("nvim-0.10") guard for
the git-pull upgrader who never reruns the installer.
Verified in a sandboxed HOME (mktemp -d): full run, files + vendor/ landed,
4-line rc block added, exit 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ional "Two files. No plugins" stopped being the whole truth the moment Ctrl+B learned to grow a tree, so every place that said it now says what IS true: three checkouts pinned to exact commits, fetched by vendor.sh, loaded only on the first press, and the accidental-plugin door (packpath) closed in the same change. README gets the sidebar its own section; KEYS.md documents every gesture and the modes Ctrl+B deliberately stays out of; docs/explorer.md is the full story; docs/macos-cmd.md gains the Cmd+B row and stops citing Cmd+B as the example of a floored chord (Cmd+N takes that job). The gate counts move 558 -> 719: options 172, config 52, mouse 66 (the table had gone stale before this branch), and suite_tree's 45 gesture cases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| rm -rf "$dest" | ||
| mkdir -p "$dest" | ||
| git -C "$dest" init -q | ||
| # GitHub serves fetches of a bare SHA (allow-any-sha1-in-want), so this | ||
| # needs no branch name and survives upstream force-pushes. | ||
| git -C "$dest" fetch -q --depth 1 "$url" "$sha" |
There was a problem hiding this comment.
Failed fetch destroys working checkout
When an existing checkout differs from the configured pin and the replacement fetch fails, vendor.sh deletes the working checkout before downloading its replacement, leaving an incomplete vendor directory and disabling the entire sidebar.
Knowledge Base Used: Installation and launch flow
There was a problem hiding this comment.
11 issues found across 17 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:116">
P3: The README still tells users 'Requires Neovim 0.9+', but this PR bumps install.sh's Neovim gate to 0.10+ (the sidebar's pinned plugins need 0.10). Update the Install details line to match so the documented minimum matches the enforced minimum.</violation>
</file>
<file name="tests/suite_tree.sh">
<violation number="1" location="tests/suite_tree.sh:45">
P3: Running with a filter that matches nothing (e.g. `./suite_tree.sh clik` with a typo) prints `PASS=0 FAIL=0` and exits 0, so the run is reported as green even though no case executed. When FILTER is non-empty, guard the success path on at least one matched case (or print the filter in the summary) so a mistyped filter cannot silently pass.</violation>
</file>
<file name="docs/explorer.md">
<violation number="1" location="docs/explorer.md:33">
P3: The doc promises that `Ctrl+E` and `Ctrl+R` "do nothing" inside the tree, but the global mappings still act there: `repl_show` and `run_once` only gate on `source_state()`, which, because the NvimTree buffer fails `typing_buffer()` (it is not modifiable and is not the netrw listing), simply returns the stale non-nil `last_file`. So once any file has been opened, pressing `Ctrl+E` in the tree focuses/opens the interpreter and `Ctrl+R` runs the file, neither of which is "nothing" — the same applies in the netrw listing the doc cites as the comparison. The suite only asserts "no wedge / no extra window" (tests/tree_drive.py), not a true no-op, so the tests don't back the doc claim. Either narrow the sentence to what actually holds (only `Ctrl+S`, which `save()` guards on `typing_buffer()`, is a no-op) or add a buffer-type guard to `repl_show`/`run_once` if the intent is genuinely inert keys in the tree.</violation>
<violation number="2" location="docs/explorer.md:57">
P3: install.sh now hard-requires Neovim 0.10+ (HARD abort), but README.md still states "Requires Neovim 0.9+" and this new line implies the rest of drill runs fine on 0.9. Align the minimum version in README.md (and soften this bullet) so users don't rely on 0.9 support that the installer refuses.</violation>
</file>
<file name="install.sh">
<violation number="1" location="install.sh:187">
P2: When apt's candidate is Neovim 0.9.x, this new gate rejects it, but `nvim_pkg` still offers `neovim` because its filter stops at 0.8. The installer therefore suggests an apt command that installs the same rejected version, then aborts; extend the candidate filter through 0.9.</violation>
</file>
<file name="vendor.sh">
<violation number="1" location="vendor.sh:35">
P2: When a pinned checkout is dirty, this fast path skips cleanup, so modified or extra plugin files remain loaded by the sidebar. Check the worktree is clean before declaring the pin ready, or recreate it.</violation>
<violation number="2" location="vendor.sh:40">
P2: When a pin update cannot fetch, this deletes the existing checkout first and leaves the sidebar unavailable. Fetch into a temporary checkout and replace the old directory only after checkout and verification succeed.</violation>
</file>
<file name="explorer.lua">
<violation number="1" location="explorer.lua:204">
P2: The stale `<LeftMouse>` auto-close map left by nvzone/menu is only deleted at the start of the *next* `tree_menu()` call. When a menu closes by item click (the common path), the plugin's auto_close map never deletes itself, so a leftover global `<LeftMouse>` mapping stays installed in the file buffer until the user right-clicks again. It re-feeds the built-in press so it usually doesn't visibly break anything, but the cleanup is in the wrong place. Clear it in the menu's after_close path (or have the store delete it as soon as the menu closes) instead of relying on the next open.</violation>
<violation number="2" location="explorer.lua:261">
P1: When a drag leaves the tree and releases over a file window, the tree’s buffer-local `<LeftRelease>` mapping does not clear `drag_src`. The next ordinary tree click can therefore call `drop` and move the stale file; clear drag state on release or window leave regardless of the receiving window.</violation>
</file>
<file name="nvimrc.lua">
<violation number="1" location="nvimrc.lua:11">
P1: Users with `~/.config/nvim/plugin` or `after/plugin` files can still execute those plugins in drill, despite the new no-plugin seal. Remove `stdpath("config")` and its `/after` entry from both paths, along with any other non-bundled site entries, or disable startup plugin loading.</violation>
<violation number="2" location="nvimrc.lua:1341">
P2: When the sidebar is unavailable, pressing Ctrl+B from insert mode leaves the user in Normal mode because `stopinsert` runs before the error return. Check the module error before stopping insert and call `type_here()` on this failure path.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
|
||
| local function tree_click() | ||
| local mp = vim.fn.getmousepos() | ||
| local src = drag_src |
There was a problem hiding this comment.
P1: When a drag leaves the tree and releases over a file window, the tree’s buffer-local <LeftRelease> mapping does not clear drag_src. The next ordinary tree click can therefore call drop and move the stale file; clear drag state on release or window leave regardless of the receiving window.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At explorer.lua, line 261:
<comment>When a drag leaves the tree and releases over a file window, the tree’s buffer-local `<LeftRelease>` mapping does not clear `drag_src`. The next ordinary tree click can therefore call `drop` and move the stale file; clear drag state on release or window leave regardless of the receiving window.</comment>
<file context>
@@ -0,0 +1,313 @@
+
+local function tree_click()
+ local mp = vim.fn.getmousepos()
+ local src = drag_src
+ drag_src = nil
+ if mp.line == 0 then return end
</file context>
| -- packages load from 'packpath', which still held it -- measured, a plugin in | ||
| -- ~/.local/share/nvim/site/pack/x/start/ loaded inside drill. All three | ||
| -- doors close here, so "no plugins" means the machine's plugins too. | ||
| for _, p in ipairs({ vim.fn.stdpath("data") .. "/site", |
There was a problem hiding this comment.
P1: Users with ~/.config/nvim/plugin or after/plugin files can still execute those plugins in drill, despite the new no-plugin seal. Remove stdpath("config") and its /after entry from both paths, along with any other non-bundled site entries, or disable startup plugin loading.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At nvimrc.lua, line 11:
<comment>Users with `~/.config/nvim/plugin` or `after/plugin` files can still execute those plugins in drill, despite the new no-plugin seal. Remove `stdpath("config")` and its `/after` entry from both paths, along with any other non-bundled site entries, or disable startup plugin loading.</comment>
<file context>
@@ -1,6 +1,18 @@
+-- packages load from 'packpath', which still held it -- measured, a plugin in
+-- ~/.local/share/nvim/site/pack/x/start/ loaded inside drill. All three
+-- doors close here, so "no plugins" means the machine's plugins too.
+for _, p in ipairs({ vim.fn.stdpath("data") .. "/site",
+ vim.fn.stdpath("data") .. "/site/after" }) do
+ vim.opt.runtimepath:remove(p)
</file context>
| maj="$(printf '%s' "${cand%%.*}" | tr -cd '0-9')" | ||
| rest="${cand#*.}"; min="$(printf '%s' "${rest%%.*}" | tr -cd '0-9')" | ||
| if [ "${maj:-0}" -eq 0 ] && [ "${min:-0}" -lt 9 ]; then | ||
| if [ "${maj:-0}" -eq 0 ] && [ "${min:-0}" -lt 10 ]; then |
There was a problem hiding this comment.
P2: When apt's candidate is Neovim 0.9.x, this new gate rejects it, but nvim_pkg still offers neovim because its filter stops at 0.8. The installer therefore suggests an apt command that installs the same rejected version, then aborts; extend the candidate filter through 0.9.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At install.sh, line 187:
<comment>When apt's candidate is Neovim 0.9.x, this new gate rejects it, but `nvim_pkg` still offers `neovim` because its filter stops at 0.8. The installer therefore suggests an apt command that installs the same rejected version, then aborts; extend the candidate filter through 0.9.</comment>
<file context>
@@ -184,10 +184,10 @@ check_deps() {
maj="$(printf '%s' "${cand%%.*}" | tr -cd '0-9')"
rest="${cand#*.}"; min="$(printf '%s' "${rest%%.*}" | tr -cd '0-9')"
- if [ "${maj:-0}" -eq 0 ] && [ "${min:-0}" -lt 9 ]; then
+ if [ "${maj:-0}" -eq 0 ] && [ "${min:-0}" -lt 10 ]; then
NOTES="$NOTES
- - neovim $cand is too old, need 0.9+ (the config is Lua and uses nvim_win_hide).
</file context>
| continue | ||
| fi | ||
| echo "vendor.sh: fetching $name @ ${sha:0:12}" | ||
| rm -rf "$dest" |
There was a problem hiding this comment.
P2: When a pin update cannot fetch, this deletes the existing checkout first and leaves the sidebar unavailable. Fetch into a temporary checkout and replace the old directory only after checkout and verification succeed.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vendor.sh, line 40:
<comment>When a pin update cannot fetch, this deletes the existing checkout first and leaves the sidebar unavailable. Fetch into a temporary checkout and replace the old directory only after checkout and verification succeed.</comment>
<file context>
@@ -0,0 +1,49 @@
+ continue
+ fi
+ echo "vendor.sh: fetching $name @ ${sha:0:12}"
+ rm -rf "$dest"
+ mkdir -p "$dest"
+ git -C "$dest" init -q
</file context>
| [ -z "$name" ] && continue | ||
| dest="$VENDOR/$name" | ||
| have="$(git -C "$dest" rev-parse HEAD 2>/dev/null || true)" | ||
| if [ "$have" = "$sha" ]; then |
There was a problem hiding this comment.
P2: When a pinned checkout is dirty, this fast path skips cleanup, so modified or extra plugin files remain loaded by the sidebar. Check the worktree is clean before declaring the pin ready, or recreate it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vendor.sh, line 35:
<comment>When a pinned checkout is dirty, this fast path skips cleanup, so modified or extra plugin files remain loaded by the sidebar. Check the worktree is clean before declaring the pin ready, or recreate it.</comment>
<file context>
@@ -0,0 +1,49 @@
+ [ -z "$name" ] && continue
+ dest="$VENDOR/$name"
+ have="$(git -C "$dest" rev-parse HEAD 2>/dev/null || true)"
+ if [ "$have" = "$sha" ]; then
+ echo "vendor.sh: $name already at ${sha:0:12}"
+ continue
</file context>
| -- menu leaves its auto-close <LeftMouse> map behind when a menu is closed | ||
| -- by an item click rather than an outside click; clear the stale one so | ||
| -- it cannot stack | ||
| pcall(vim.keymap.del, "n", "<LeftMouse>") |
There was a problem hiding this comment.
P2: The stale <LeftMouse> auto-close map left by nvzone/menu is only deleted at the start of the next tree_menu() call. When a menu closes by item click (the common path), the plugin's auto_close map never deletes itself, so a leftover global <LeftMouse> mapping stays installed in the file buffer until the user right-clicks again. It re-feeds the built-in press so it usually doesn't visibly break anything, but the cleanup is in the wrong place. Clear it in the menu's after_close path (or have the store delete it as soon as the menu closes) instead of relying on the next open.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At explorer.lua, line 204:
<comment>The stale `<LeftMouse>` auto-close map left by nvzone/menu is only deleted at the start of the *next* `tree_menu()` call. When a menu closes by item click (the common path), the plugin's auto_close map never deletes itself, so a leftover global `<LeftMouse>` mapping stays installed in the file buffer until the user right-clicks again. It re-feeds the built-in press so it usually doesn't visibly break anything, but the cleanup is in the wrong place. Clear it in the menu's after_close path (or have the store delete it as soon as the menu closes) instead of relying on the next open.</comment>
<file context>
@@ -0,0 +1,313 @@
+ -- menu leaves its auto-close <LeftMouse> map behind when a menu is closed
+ -- by an item click rather than an outside click; clear the stale one so
+ -- it cannot stack
+ pcall(vim.keymap.del, "n", "<LeftMouse>")
+ require("menu").open(menu_items(), { mouse = true, border = true })
+end
</file context>
| @@ -84,7 +84,11 @@ And underneath it is still real Neovim: `hjkl`, `dd`, `ciw`, macros and | |||
|
|
|||
There was a problem hiding this comment.
P3: The README still tells users 'Requires Neovim 0.9+', but this PR bumps install.sh's Neovim gate to 0.10+ (the sidebar's pinned plugins need 0.10). Update the Install details line to match so the documented minimum matches the enforced minimum.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At README.md, line 116:
<comment>The README still tells users 'Requires Neovim 0.9+', but this PR bumps install.sh's Neovim gate to 0.10+ (the sidebar's pinned plugins need 0.10). Update the Install details line to match so the documented minimum matches the enforced minimum.</comment>
<file context>
@@ -109,6 +113,22 @@ t -k # stop
Non-blocking, with a sound and a desktop notification at zero.
+## `Ctrl+B` — a file sidebar, when you want one
+
+The one optional extra: press `Ctrl+B` (or `Cmd+B` on a Mac that forwards it,
</file context>
|
|
||
| PASS=0; FAIL=0 | ||
| declare -a BAD=() | ||
| while IFS=$'\t' read -r verdict name got; do |
There was a problem hiding this comment.
P3: Running with a filter that matches nothing (e.g. ./suite_tree.sh clik with a typo) prints PASS=0 FAIL=0 and exits 0, so the run is reported as green even though no case executed. When FILTER is non-empty, guard the success path on at least one matched case (or print the filter in the summary) so a mistyped filter cannot silently pass.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/suite_tree.sh, line 45:
<comment>Running with a filter that matches nothing (e.g. `./suite_tree.sh clik` with a typo) prints `PASS=0 FAIL=0` and exits 0, so the run is reported as green even though no case executed. When FILTER is non-empty, guard the success path on at least one matched case (or print the filter in the summary) so a mistyped filter cannot silently pass.</comment>
<file context>
@@ -0,0 +1,59 @@
+
+PASS=0; FAIL=0
+declare -a BAD=()
+while IFS=$'\t' read -r verdict name got; do
+ case "$verdict" in PASS|FAIL) ;; *) continue ;; esac
+ if [ -n "$FILTER" ] && [[ "$name" != *"$FILTER"* ]]; then continue; fi
</file context>
| handling lives by, so nothing ever moves by accident. | ||
|
|
||
| Inside the tree, drill's file keys say no the same way they do in the | ||
| directory listing: `Ctrl+S`, `Ctrl+E`, `Ctrl+R` do nothing there. |
There was a problem hiding this comment.
P3: The doc promises that Ctrl+E and Ctrl+R "do nothing" inside the tree, but the global mappings still act there: repl_show and run_once only gate on source_state(), which, because the NvimTree buffer fails typing_buffer() (it is not modifiable and is not the netrw listing), simply returns the stale non-nil last_file. So once any file has been opened, pressing Ctrl+E in the tree focuses/opens the interpreter and Ctrl+R runs the file, neither of which is "nothing" — the same applies in the netrw listing the doc cites as the comparison. The suite only asserts "no wedge / no extra window" (tests/tree_drive.py), not a true no-op, so the tests don't back the doc claim. Either narrow the sentence to what actually holds (only Ctrl+S, which save() guards on typing_buffer(), is a no-op) or add a buffer-type guard to repl_show/run_once if the intent is genuinely inert keys in the tree.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/explorer.md, line 33:
<comment>The doc promises that `Ctrl+E` and `Ctrl+R` "do nothing" inside the tree, but the global mappings still act there: `repl_show` and `run_once` only gate on `source_state()`, which, because the NvimTree buffer fails `typing_buffer()` (it is not modifiable and is not the netrw listing), simply returns the stale non-nil `last_file`. So once any file has been opened, pressing `Ctrl+E` in the tree focuses/opens the interpreter and `Ctrl+R` runs the file, neither of which is "nothing" — the same applies in the netrw listing the doc cites as the comparison. The suite only asserts "no wedge / no extra window" (tests/tree_drive.py), not a true no-op, so the tests don't back the doc claim. Either narrow the sentence to what actually holds (only `Ctrl+S`, which `save()` guards on `typing_buffer()`, is a no-op) or add a buffer-type guard to `repl_show`/`run_once` if the intent is genuinely inert keys in the tree.</comment>
<file context>
@@ -0,0 +1,60 @@
+handling lives by, so nothing ever moves by accident.
+
+Inside the tree, drill's file keys say no the same way they do in the
+directory listing: `Ctrl+S`, `Ctrl+E`, `Ctrl+R` do nothing there.
+
+## What it costs when you don't use it
</file context>
| - *"sidebar plugins are not fetched"* — run `./vendor.sh` in your drill | ||
| directory (`~/drill` unless you moved it). `install.sh` does this for you; | ||
| a `git pull` upgrade does not. | ||
| - *"the sidebar needs nvim 0.10+"* — everything else in drill still works; |
There was a problem hiding this comment.
P3: install.sh now hard-requires Neovim 0.10+ (HARD abort), but README.md still states "Requires Neovim 0.9+" and this new line implies the rest of drill runs fine on 0.9. Align the minimum version in README.md (and soften this bullet) so users don't rely on 0.9 support that the installer refuses.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/explorer.md, line 57:
<comment>install.sh now hard-requires Neovim 0.10+ (HARD abort), but README.md still states "Requires Neovim 0.9+" and this new line implies the rest of drill runs fine on 0.9. Align the minimum version in README.md (and soften this bullet) so users don't rely on 0.9 support that the installer refuses.</comment>
<file context>
@@ -0,0 +1,60 @@
+- *"sidebar plugins are not fetched"* — run `./vendor.sh` in your drill
+ directory (`~/drill` unless you moved it). `install.sh` does this for you;
+ a `git pull` upgrade does not.
+- *"the sidebar needs nvim 0.10+"* — everything else in drill still works;
+ the pinned plugins are what need 0.10.
+- `Cmd+B` does nothing — your terminal is not forwarding Cmd. One setting:
</file context>
…ight-click `d lld-prac main` runs nvim from wherever the shell happened to be, and the sidebar rooted there -- a tree of your home directory is a tree of everything except your project. The toggle now roots at the folder of the file under the caret, freshly on every open, with the file's row highlighted (find_file); no real file -- the netrw listing, a scratch buffer -- falls back to the cwd as before. Three new pty cases pin it: open from sub/c.py roots at sub/, the file is listed, and reopening from a root file moves the root back. The right-click half was never drill's to fix, but it is drill's to name: iTerm2 ships a Pointer binding (right button, single click -> Open Context Menu) that wins over mouse reporting, so nvim never sees the click and the menu that appears is iTerm2's. docs/explorer.md now walks through removing it -- Settings -> Pointer -> Bindings, minus button -- after which the click reaches drill inside the editor while the shell prompt keeps its own menu. Gate: 722. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The screenshot that reported this showed the quit prompt buried under "[NvimTree] File system watcher failed (EMFILE)": nvim-tree registers one filesystem watcher per directory, the pre-rooting sidebar had rooted at the shell's cwd -- the user's home -- and the fd limit ran out mid-session, with the error spray eating every Enter meant for the dialog. Watchers are now off outright: drill's files change from inside the editor, the tree refreshes on its own actions, and the glue reloads after every drop and mkdir. The second half of the same failure: a toggle from the REPL or any nameless buffer passed no better path and fell back to the cwd, yanking a perfectly good project root back to ~. Now the toggle re-roots only when the buffer knows better -- a real file (its folder) or the netrw listing (the directory it shows) -- and keeps the previous root otherwise. Four regression cases: watchers stay off, netrw roots the tree at its dir, a Cmd+B from the REPL keeps the root, and the quit suite stays green alongside. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hiding a split hands focus to a neighbor, and with the sidebar open that neighbor is the tree -- measured: <C-e> from the interpreter parked the caret in the sidebar in Normal mode, and type_here() correctly refused to insert there. repl_hide now walks to the first window holding a typing buffer before landing you; no such window anywhere (a bare listing plus the tree) leaves focus where it fell, which type_here already treats as nothing-to-do. Three pty cases pin it, with a real file up top and the tree open. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Gates Failed
New code is healthy
(1 new file with code health below 10.00)
Enforce critical code health rules
(1 file with Bumpy Road Ahead)
Enforce advisory code health rules
(1 file with Complex Method)
Our agent can fix these. Install it.
Gates Passed
1 Quality Gates Passed
Reason for failure
| New code is healthy | Violations | Code Health Impact | |
|---|---|---|---|
| tree_drive.py | 2 rules | 8.49 | Suppress |
| Enforce critical code health rules | Violations | Code Health Impact | |
|---|---|---|---|
| tree_drive.py | 1 critical rule | 8.49 | Suppress |
| Enforce advisory code health rules | Violations | Code Health Impact | |
|---|---|---|---|
| tree_drive.py | 1 advisory rule | 8.49 | Suppress |
Quality Gate Profile: Clean Code Collective
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.
Stacked on #17 (
feat/macos-cmd) — merge that first; this PR retargetsmaincleanly after.What this is
An optional file-explorer sidebar on Ctrl+B / Cmd+B — drill's first and only plugin-powered feature, built to stay an exception:
vendor.sh(a pin table and a loop, not a plugin manager).~/.local/share/nvim/site/pack/*/startloaded inside drill despite the "no plugins" promise (measured). Both site dirs now come offruntimepathandpackpath, with a suite assert.The gestures (all mouse, all pty-tested)
[+ File]/[+ Folder]— real clickable winbar buttons (%@handler@regions). The folder button doesmkdir -p, not the trailing-slash typing convention.*), and drag-and-drop: drop a file on a folder to move it in; drag a marked row and the whole selection moves. A one-cell jitter is a click, not a drag — same trackpad rule as the rest of drill.Bugs found on the way
"i", filetypeNvimTree), landing releases in a mode no tree mapping owns — every click silently ate itself. The tree now forces Normal on entry.<D-b>stops being the docs' example of a floored chord; the floor test re-spells with<D-g>.Tests & plumbing
tests/suite_tree.sh+tests/tree_drive.py: 45 cases on a real pty — both toggle chords (Cmd+B as raw CSI-u bytes), focus that never leaves your code, toolbar clicks all the way to files on disk, a menu item clicked by its float coordinates, marked-pair drag moves, and the 3-window REPL layout.tests/run.shgains avendor.shpreflight (CI needs zero workflow changes); gate grows 558 → 719 cases, all green locally (2 full runs).install.sh: manifest + vendor fetch (FEATURE-level; offline installs lose only the sidebar), nvim gate 0.9 → 0.10 (what the pinned nvim-tree requires). Verified in a sandboxedHOME.docs/explorer.md, honesty pass on every "no plugins" claim.🤖 Generated with Claude Code
Summary by cubic
Adds an optional, vendored file-explorer sidebar on Ctrl+B/Cmd+B that loads only on first toggle. Old behavior: no plugins and the sidebar (when present) rooted at the shell’s working directory with possible user plugin leakage. New behavior: one opt‑in plugin (
nvim-tree.lua+nvzone/volt+nvzone/menu) loads lazily, the tree roots at the current file’s folder on open, it keeps the existing root when toggled from the REPL or a scratch buffer, filesystem watchers stay disabled to avoid EMFILE, and bothruntimepathandpackpathseals block third‑party loads. Hiding the REPL now returns focus to a real typing buffer instead of the tree.explorer.lualazy setup, drag/drop, menu, toolbar, rooting and watcher settings;nvimrc.luapath sealing, Ctrl+B/Cmd+B toggles, andrepl_hidefocus fix;vendor.shpinned checkouts;install.shrunsvendor.sh, adds agitdep, and enforces Neovim 0.10+;tests/run.shpreflightsvendor.sh; gate is 729 cases with 55 real‑PTY sidebar tests; docs updated.Rollout
./vendor.shafter pulling; ensure Neovim 0.10+ andgitare installed.Written for commit 9a1a3c2. Summary will update on new commits.
Greptile Summary
The PR adds an optional, lazily loaded file-explorer sidebar and vendors its pinned plugin dependencies.
Confidence Score: 3/5
The PR is not yet safe to merge because vendor refresh failures can remove working sidebar dependencies and the installer rejects a still-documented supported Neovim version.
The existing vendor replacement path deletes each nonmatching checkout before fetching its replacement, and the installation contract still disagrees between the hard Neovim 0.10 gate and README’s 0.9+ prerequisite.
Files Needing Attention: vendor.sh, install.sh, README.md
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR K[Ctrl+B or Cmd+B] --> L[Load explorer.lua] L --> V[Add pinned vendor checkouts to runtimepath] V --> T[Initialize nvim-tree and menu] T --> U[Mouse-driven sidebar] I[install.sh or tests/run.sh] --> F[vendor.sh] F --> VReviews (3): Last reviewed commit: "Ctrl+E out of the REPL means the code, n..." | Re-trigger Greptile