feat(editor): navigate to definition on a plain middle-button click (#666)

The editor's mousedown handler ignored every button except the left one, so a middle click fell through to the webview's autoscroll. A plain middle click now moves the caret to the clicked symbol and runs go-to-definition, suppressing autoscroll; a keymap shortcut bound to Button2 still takes precedence, and modifier + middle combinations stay unbound.

Fixes #663

Co-authored-by: a-rookie-of-C-language <186315048+a-rookie-of-C-language@users.noreply.github.com>
This commit is contained in:
arookieofc
2026-11-01 16:17:18 +08:00
committed by GitHub
co-authored by a-rookie-of-C-language
parent 683f8d8826
commit 8d38aa4a9c
2 changed files with 15 additions and 6 deletions
+7 -6
View File
@@ -1,8 +1,8 @@
/**
* Go to declaration / implementation / type declaration (⌘B, ⌥⌘B, ⇧⌘B and
* ⌘-click with a link underline while ⌘ is held), the multiple-targets
* chooser, and document highlights (occurrences of the symbol at the caret,
* plus the sticky find.highlightUsages variant).
* Go to declaration / implementation / type declaration (⌘B, ⌥⌘B, ⇧⌘B,
* ⌘-click with a link underline while ⌘ is held, and a plain middle-button
* click), the multiple-targets chooser, and document highlights (occurrences
* of the symbol at the caret, plus the sticky find.highlightUsages variant).
*/
import { EditorSelection, Prec, StateEffect, StateField, type Extension, type Text } from "@codemirror/state";
import {
@@ -489,7 +489,7 @@ const linkPlugin = ViewPlugin.fromClass(
this.show(false);
},
mousedown(e, view) {
if (e.button !== 0) return false;
if (e.button !== 0 && e.button !== 1) return false;
if (
dispatchMouseShortcut(e, () => {
const pos = view.posAtCoords({ x: e.clientX, y: e.clientY }, false);
@@ -502,7 +502,8 @@ const linkPlugin = ViewPlugin.fromClass(
e.preventDefault();
return true;
}
if (!isNavigationGesture(e)) return false;
// IDEA parity: middle button navigates on a plain click, without the modifier.
if (e.button === 1 ? e.metaKey || e.ctrlKey || e.altKey || e.shiftKey : !isNavigationGesture(e)) return false;
const pos = view.posAtCoords({ x: e.clientX, y: e.clientY }, false);
if (pos == null) return false;
e.preventDefault();
+8
View File
@@ -94,6 +94,14 @@ describe("mouse navigation", () => {
expect(lspGoto).toHaveBeenCalledExactlyOnceWith(1, { line: 0, col: 9 }, "definition");
});
it("opens the definition from a plain middle-button click", async () => {
const event = click({ button: 1 });
await vi.waitFor(() => expect(openFile).toHaveBeenCalledOnce());
expect(lspGoto).toHaveBeenCalledExactlyOnceWith(1, { line: 0, col: 9 }, "definition");
expect(view.state.selection.main.head).toBe(9);
expect(event.defaultPrevented).toBe(true);
});
it.each([
{ button: 1, metaKey: true, altKey: true },
{ button: 2, metaKey: true, altKey: true },