added j / k for vim-style line movement
j and k move the caret one line, delegated to sublime's own `move` command so they behave exactly like the arrow keys. They dispatch through the existing ACTIONS registry, so the keymap, the status-bar hints and the ? popup all stay in sync through the single KEY_GROUPS table. Unlike the other letter keys, j / k keep no command_mode context: the view is read-only, so leaving them live while Vintage is in command mode can only ever move the caret. That asymmetry was previously documented only in a comment, which was wrong (it claimed j / k were the only unguarded bindings, but escape has always carried its own context instead). It is now pinned by test_command_mode_guard_is_deliberate, so normalising the keymap fails the suite with the reason attached. Also tidies two long lines in commands.py. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -134,7 +134,7 @@ def test_help_popup_lists_every_key():
|
||||
assert view.is_popup_visible()
|
||||
for group in ("Navigate", "Panels", "This file", "View"):
|
||||
assert ">{}<".format(group) in html
|
||||
for keys in ("] [", "n p", "o ⏎", "f", "c", "s", "u", "d", "r", "?", "esc"):
|
||||
for keys in ("] [", "n p", "o ⏎", "j k", "f", "c", "s", "u", "d", "r", "?", "esc"):
|
||||
assert ">{}<".format(keys) in html
|
||||
assert "next / previous change" in html and "open the real file at this line" in html
|
||||
# working-tree mode: nothing dimmed, every single-action row is a link
|
||||
@@ -176,11 +176,15 @@ def test_help_popup_toggles_and_navigates():
|
||||
DISPLAY_KEYS = {"enter": "⏎", "escape": "esc"}
|
||||
|
||||
|
||||
def test_keymap_matches_help_table():
|
||||
"""The keymap, ACTIONS and the popup agree on both the actions and the keys that reach them"""
|
||||
def keymap_bindings():
|
||||
path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "Default.sublime-keymap")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
bindings = json.load(f)
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def test_keymap_matches_help_table():
|
||||
"""The keymap, ACTIONS and the popup agree on both the actions and the keys that reach them"""
|
||||
bindings = keymap_bindings()
|
||||
|
||||
assert all(b["command"] == "vdiff_action" for b in bindings)
|
||||
bound = {b["args"]["action"] for b in bindings}
|
||||
@@ -192,6 +196,20 @@ def test_keymap_matches_help_table():
|
||||
assert bound_keys == {token for k in render.KEYS for token in k.keys.split()}
|
||||
|
||||
|
||||
# j / k stay live in Vintage command mode on purpose: the view is read-only, so the worst they can do
|
||||
# is move the caret, and a vim user should not have to leave command mode to scroll a diff.
|
||||
# escape carries its own context (panel / overlay / popup / selection guards) instead.
|
||||
UNGUARDED_ACTIONS = {"line_down", "line_up", "close"}
|
||||
|
||||
|
||||
def test_command_mode_guard_is_deliberate():
|
||||
"""Every binding yields to Vintage except the ones that documented a reason not to"""
|
||||
guard = {"key": "setting.command_mode", "operand": False}
|
||||
for binding in keymap_bindings():
|
||||
unguarded = binding["args"]["action"] in UNGUARDED_ACTIONS
|
||||
assert (guard in binding["context"]) != unguarded, binding["keys"]
|
||||
|
||||
|
||||
def test_minihtml_stylesheets_reject_unsupported_selectors():
|
||||
"""minihtml drops the rest of a stylesheet at a selector it cannot parse; these are the forms
|
||||
that silently broke HELP_CSS, so no stylesheet constant may use them"""
|
||||
|
||||
Reference in New Issue
Block a user