feat: improve CodeMirror quick tools modifier support#2435
Conversation
Adds CodeMirror-aware quick tools handling for modifier text input, navigation keys, shift selection, and shortcut command resolution, with focused editor tests covering the new behavior. Also cleans up the advanced HTTP plugin config entry in package.json.
Greptile SummaryThis PR introduces CodeMirror-native handling for quick tools modifier keys, adding new modules for text input interception, navigation command dispatch, shift/multi-cursor selection, and shortcut combo resolution. It also refactors the touch selection controller to support both shift-extend and multi-cursor (Ctrl/Meta) pointer interactions.
Confidence Score: 4/5The new CM extension modules are well-structured and well-tested, but quickTools.js carries two unresolved defects from prior review rounds that directly affect modifier-key behaviour at runtime. The modifier state is not reliably reset after non-arrow quick-tool key presses, and the module-level input variable is overwritten inside the CM inputHandler callback — both flagged in prior review threads and neither addressed in this revision. Those paths are exercised on every modifier+key press, so they represent a real correctness risk for the feature this PR is built around. src/handlers/quickTools.js warrants the closest look — the modifier-reset and input-mutation issues from prior reviews still live there. src/lib/editorManager.js has a minor unconditional preventDefault in the new mousedown handler. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Quick Tool Button Press] --> B{action type}
B -->|modifier key| C[actions: state + events]
B -->|key code| D[getKeys + keyCombination]
C --> E{Any modifier active?}
E -->|yes, CM editor focused| F[editor.focus]
E -->|yes, other input| G[$input.focus]
D --> H[runCodeMirrorQuickToolKey]
H --> I{isCodeMirrorEditorInput?}
I -->|yes| J[runQuickToolKey / runScopeHandlers]
I -->|no| K[getInput.dispatchEvent keydown]
J --> L{runScopeHandlers handled?}
L -->|yes| M[view.focus / return true]
L -->|no| N[getFallbackCommand lookup]
N --> O{command found?}
O -->|yes| P[command view + view.focus]
O -->|no| Q[return false]
M --> R[shouldResetKeys? resetKeys]
P --> R
K --> R
S[Virtual keyboard input] --> T[CM inputHandler: handleCodeMirrorQuickToolsTextInput]
T --> U{Any modifier active?}
U -->|no| V[return false - normal insert]
U -->|shift only| W[resetKeys + replaceSelection with mapped char]
U -->|ctrl/alt/meta| X[findQuickToolCommand in registry]
X --> Y{command found?}
Y -->|yes| Z[executeCommand + view]
Y -->|no| AA[dispatchEvent keydown on contentDOM]
Z --> AB[resetKeys + return true]
AA --> AB
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Quick Tool Button Press] --> B{action type}
B -->|modifier key| C[actions: state + events]
B -->|key code| D[getKeys + keyCombination]
C --> E{Any modifier active?}
E -->|yes, CM editor focused| F[editor.focus]
E -->|yes, other input| G[$input.focus]
D --> H[runCodeMirrorQuickToolKey]
H --> I{isCodeMirrorEditorInput?}
I -->|yes| J[runQuickToolKey / runScopeHandlers]
I -->|no| K[getInput.dispatchEvent keydown]
J --> L{runScopeHandlers handled?}
L -->|yes| M[view.focus / return true]
L -->|no| N[getFallbackCommand lookup]
N --> O{command found?}
O -->|yes| P[command view + view.focus]
O -->|no| Q[return false]
M --> R[shouldResetKeys? resetKeys]
P --> R
K --> R
S[Virtual keyboard input] --> T[CM inputHandler: handleCodeMirrorQuickToolsTextInput]
T --> U{Any modifier active?}
U -->|no| V[return false - normal insert]
U -->|shift only| W[resetKeys + replaceSelection with mapped char]
U -->|ctrl/alt/meta| X[findQuickToolCommand in registry]
X --> Y{command found?}
Y -->|yes| Z[executeCommand + view]
Y -->|no| AA[dispatchEvent keydown on contentDOM]
Z --> AB[resetKeys + return true]
AA --> AB
Reviews (3): Last reviewed commit: "fixed stuffs" | Re-trigger Greptile |
- Add CodeMirror-aware quick-tools modifier input, navigation, shift tap selection, and multi-cursor handling. - Keep editor focus/caret visible while quick-tools modifiers are active. - Hide unreliable Shift tap/click setting for now. - Clear stuck quick-toolbar modifier/active state around search open/close. - Add focused tests for modifier combos, pointer selection, multi-cursor, and search cleanup.
This comment was marked as outdated.
This comment was marked as outdated.
- addressed the greptile review regarding: combo normalization and mutation thing - Fixed non-arrow quick-tool keys leaving modifier state active after dispatch. - Fixed rapid quick-tool taps leaving orphan `.active` feedback on symbol buttons - Restored `shiftClickSelection` in editor settings - Made disabling shiftClickSelection actually block Shift pointer/range selection, including line numbers. - Updated editor tests for the restored Shift selection behavior. - Added old-WebView settings switch fallback
Adds CodeMirror-aware quick tools handling for modifier text input, navigation keys, shift selection, and shortcut command resolution, with focused editor tests covering the new behavior. Also cleans up the advanced HTTP plugin config entry in package.json.