Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions sqlit/shared/ui/widgets_text_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,23 @@ async def _on_key(self, event: Key) -> None:
if event.key == "tab":
if not self._is_insert_mode():
return
# If the autocomplete dropdown is open, let the app's key router
# accept the suggestion only when Tab is actually bound to the
# autocomplete_accept action. Otherwise Tab should insert a tab.
# If the autocomplete dropdown is open, let the app's action system
# handle Tab when the autocomplete keymap claims it. Otherwise Tab
# should insert a tab character.
app = cast("AutocompleteProtocol", self.app)
if getattr(app, "_autocomplete_visible", False):
from sqlit.core.keymap import get_keymap

keymap = get_keymap()
if "tab" in keymap.keys_for_action("autocomplete_accept"):
return
for binding in keymap.get_action_keys():
if (
binding.key == event.key
and binding.context == "autocomplete"
and await self.app.run_action(binding.action)
):
event.prevent_default()
event.stop()
return
self._push_undo_if_changed()
tab = self._tab_insert_string()
selection = self.selection
Expand Down
47 changes: 47 additions & 0 deletions tests/ui/test_query_tab_insert.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,50 @@ async def test_tab_inserts_when_autocomplete_accept_is_rebound(self) -> None:
assert app.query_input.text == "sel\t"
finally:
reset_keymap()

@pytest.mark.asyncio
async def test_tab_honors_other_autocomplete_action_rebinding(self) -> None:
app = _make_app()

try:
async with app.run_test(size=(100, 35)) as pilot:
app.action_focus_query()
await pilot.press("i")
await pilot.pause()

defaults = DefaultKeymapProvider()
action_keys = [
binding
for binding in defaults.get_action_keys()
if not (
binding.key == "tab"
and binding.context == "autocomplete"
)
]
action_keys.append(
ActionKeyDef("tab", "autocomplete_next", "autocomplete")
)
set_keymap(
FileBasedKeymapProvider(
"rebound-autocomplete-next",
defaults.get_leader_commands(),
action_keys,
)
)

app.query_input.text = "s"
app.query_input.cursor_location = (0, 1)
app._show_autocomplete(
["select", "set", "session", "sequence", "security"],
"s",
)
await pilot.pause()
assert app.autocomplete_dropdown.selected_index == 0

await pilot.press("tab")
await pilot.pause()

assert app.query_input.text == "s"
assert app.autocomplete_dropdown.selected_index == 1
finally:
reset_keymap()
Loading