Skip to content

Vim search and fix symbol keybindings on non-US keyboard layouts - #3945

Open
fsoft72 wants to merge 10 commits into
lapce:masterfrom
fsoft72:vim-search
Open

fsoft72 wants to merge 10 commits into
lapce:masterfrom
fsoft72:vim-search

Conversation

@fsoft72

@fsoft72 fsoft72 commented Sep 23, 2026

Copy link
Copy Markdown

This PR makes two related improvements to vim (modal) keybindings:

  1. Bind / to open search in Normal mode

Previously / in vim Normal mode was bound to palette.line (go to line), leaving no way to trigger the classic vim
search shortcut. It's now bound to the existing search command, which already supports regex via the find bar's retoggle.

  1. Fix symbol keybindings on non-US keyboard layouts

While testing the above on an Italian keyboard, / and several other vim symbol bindings (^, $, %, *, <, >, :) didn't work at all, along with the non-vim ctrl+/ (toggle line comment) shortcut.

Because the keymap matcher resolved character bindings from key_without_modifiers (the physical key's unshifted base character) plus a separately tracked Shift bit, instead of the character actually produced (logical, which already accounts for Shift/AltGr/layout). This happens to work on US QWERTY, where most punctuation is unshifted and the shifted-symbol/digit-key correspondence matches the convention baked into the default keymap (e.g. shift+4 for $). On other layouts it breaks: on Italian keyboards, for example, / is produced by Shift+7, so neither the unshifted base character nor the tracked modifier match what the default keymap expects.

The fix:

  • For non-alphabetic character keys, the matcher now builds a second, preferred key representation from the character actually produced (logical), with Shift/AltGr absorbed into it. Alphabetic key matching (shift+<letter>) is untouched.
  • The old key_without_modifiers-based representation is kept as a fallback, tried only when the new one doesn't match, so existing custom keymaps.toml entries using the old shift+<digit> convention keep working.
  • The default keymap's symbol bindings (line_end, line_start_non_blank, match_pairs, search_whole_word_forward, indent/outdent, command palette) are migrated from shift+<digit> to their literal characters ($, ^, %, *, <, >, :), which now resolve correctly on any layout.

Covered by new unit tests in lapce-app/src/keypress/press.rs and lapce-app/src/keypress.rs, including a case for dead-key composition and one confirming ctrl+<symbol> shortcuts still require the Ctrl modifier (not just the symbol). Manually verified on an Italian keyboard layout in vim Normal mode.

Extend the internal terminal to recognize http(s) URLs and
path:line:col references anywhere in the visible viewport, not just
under an already-selected word. Holding Ctrl now underlines the link
under the cursor and switches to a pointer cursor; Ctrl+click opens
URLs in the system browser and still jumps file references to the
matching editor location.
Previously "/" was bound to palette.line (go to line) in vim normal
mode, leaving no vim-style search shortcut. Rebind it to the existing
"search" command, which already supports regex via the find bar's
regex toggle. Since mode = "n" keymaps are dropped entirely when
core.modal is disabled, this only takes effect in vim mode.
Root-causes the / and ^ vim keybinding failures on Italian keyboards to
key_without_modifiers-based matching for symbol keys, and specs a fix
using the actual produced character while keeping the old shift+<digit>
syntax working for backward compatibility.
Task-by-task plan implementing the design in
docs/superpowers/specs/2026-09-23-layout-aware-symbol-keymaps-design.md.
Introduce a layout-aware key representation for non-alphabetic
character keys (digits, punctuation), built from the character the
keyboard actually produces instead of the US-QWERTY-shaped
key_without_modifiers + explicit shift bit. The old representation is
kept as legacy_keymap_press for the fallback added in the next commit.
match_keymap now tries the new logical-character-based representation
first and only falls back to the old key_without_modifiers-based one
(single keypress only) when that finds nothing, so old custom
keymaps.toml entries keep working.
Migrates shift+<digit> style bindings (line_end, line_start_non_blank,
match_pairs, search_whole_word_forward, indent/outdent, command
palette) to literal characters ($, ^, %, *, <, >, :), which the
layout-aware matcher now resolves correctly on any keyboard layout.
logical_symbol_key() bailed whenever key_without_modifiers wasn't a
Character, which missed the dead-key case: on Italian keyboards "^" is
a dead key, so the keypress that finishes the composition (e.g. Space)
reports key_without_modifiers = Named(Space) while logical carries the
real composed character. Only skip the logical-based match for plain
alphabetic character keys, where explicit-shift letter handling must
stay unchanged.
These were working documents for this session and aren't meant to be
part of the upstream PR.
@panekj panekj added the S-llm Created with use of LLMs label Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-llm Created with use of LLMs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants