diff --git a/sqlit/core/keymap.py b/sqlit/core/keymap.py index 79d814f0..fe5c1bfa 100644 --- a/sqlit/core/keymap.py +++ b/sqlit/core/keymap.py @@ -371,6 +371,11 @@ def _build_action_keys(self) -> list[ActionKeyDef]: ActionKeyDef("W", "cursor_WORD_forward", "query_normal"), ActionKeyDef("b", "cursor_word_back", "query_normal"), ActionKeyDef("B", "cursor_WORD_back", "query_normal"), + # Unbound by default — users can bind in their keymap.json + # (typically "e"/"E"), but they must also rebind whatever + # `focus_explorer` action is currently using those keys. + ActionKeyDef("", "cursor_word_end", "query_normal"), + ActionKeyDef("", "cursor_WORD_end", "query_normal"), ActionKeyDef("0", "cursor_line_start", "query_normal"), ActionKeyDef("circumflex_accent", "cursor_first_non_blank", "query_normal"), ActionKeyDef("dollar_sign", "cursor_line_end", "query_normal"), diff --git a/sqlit/domains/query/state/query_normal.py b/sqlit/domains/query/state/query_normal.py index 2f2f6ae6..dedbda7c 100644 --- a/sqlit/domains/query/state/query_normal.py +++ b/sqlit/domains/query/state/query_normal.py @@ -35,6 +35,8 @@ def _setup_actions(self) -> None: self.allows("cursor_WORD_forward", help="Move to next WORD") self.allows("cursor_word_back", help="Move to previous word") self.allows("cursor_WORD_back", help="Move to previous WORD") + self.allows("cursor_word_end", help="Move to end of word") + self.allows("cursor_WORD_end", help="Move to end of WORD") self.allows("cursor_first_non_blank", help="Move to first non-blank") self.allows("cursor_line_start", help="Move to line start") self.allows("cursor_line_end", help="Move to line end") diff --git a/sqlit/domains/query/ui/mixins/query_editing_cursor.py b/sqlit/domains/query/ui/mixins/query_editing_cursor.py index 106fb5a5..3aed3de0 100644 --- a/sqlit/domains/query/ui/mixins/query_editing_cursor.py +++ b/sqlit/domains/query/ui/mixins/query_editing_cursor.py @@ -131,6 +131,14 @@ def action_cursor_WORD_back(self: QueryMixinHost) -> None: """Move cursor to previous WORD (B).""" self._move_with_motion("B") + def action_cursor_word_end(self: QueryMixinHost) -> None: + """Move cursor to end of word (e). Unbound by default.""" + self._move_with_motion("e") + + def action_cursor_WORD_end(self: QueryMixinHost) -> None: + """Move cursor to end of WORD (E). Unbound by default.""" + self._move_with_motion("E") + def action_cursor_first_non_blank(self: QueryMixinHost) -> None: """Move cursor to first non-whitespace character (^).""" self._move_with_motion("^")