Skip to content

Commit bf771ca

Browse files
committed
Rename object explorer to explorer
1 parent 6e43574 commit bf771ca

13 files changed

Lines changed: 724 additions & 36 deletions

sqlit/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def compose(self) -> ComposeResult:
331331
with Horizontal(id="content"):
332332
with Vertical(id="sidebar"):
333333
yield Static(
334-
r"\[e] Object Explorer", classes="section-label", id="label-explorer"
334+
r"\[E] Explorer", classes="section-label", id="label-explorer"
335335
)
336336
tree = Tree("Servers", id="object-tree")
337337
tree.show_root = False

sqlit/state_machine.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class HelpEntry:
133133

134134
key: str # Display key (e.g., "enter", "s")
135135
description: str # Help description (e.g., "Select TOP 100")
136-
category: str # Category name (e.g., "Object Explorer")
136+
category: str # Category name (e.g., "Explorer")
137137

138138

139139
@dataclass
@@ -383,7 +383,7 @@ class MainScreenState(State):
383383

384384
def _setup_actions(self) -> None:
385385
# Navigation (shown in Navigation category)
386-
self.allows("focus_explorer", help="Focus Object Explorer", help_key="e")
386+
self.allows("focus_explorer", help="Focus Explorer", help_key="e")
387387
self.allows("focus_query", help="Focus Query", help_key="q")
388388
self.allows("focus_results", help="Focus Results", help_key="r")
389389
self.allows("toggle_fullscreen", help="Toggle fullscreen", help_key="f")
@@ -453,7 +453,7 @@ def is_active(self, app: SSMSTUI) -> bool:
453453
class TreeFocusedState(State):
454454
"""Base state when tree has focus."""
455455

456-
help_category = "Object Explorer"
456+
help_category = "Explorer"
457457

458458
def _setup_actions(self) -> None:
459459
self.allows("new_connection", key="n", label="New", help="New connection")
@@ -467,7 +467,7 @@ def is_active(self, app: SSMSTUI) -> bool:
467467
class TreeOnConnectionState(State):
468468
"""Tree focused on a connection node."""
469469

470-
help_category = "Object Explorer"
470+
help_category = "Explorer"
471471

472472
def _setup_actions(self) -> None:
473473
def can_connect(app: SSMSTUI) -> bool:
@@ -559,7 +559,7 @@ def is_active(self, app: SSMSTUI) -> bool:
559559
class TreeOnTableState(State):
560560
"""Tree focused on table or view node."""
561561

562-
help_category = "Object Explorer"
562+
help_category = "Explorer"
563563

564564
def _setup_actions(self) -> None:
565565
self.allows("select_table", key="s", label="Select TOP 100", help="Select TOP 100 (table/view)")
@@ -890,7 +890,7 @@ def generate_help_text(self) -> str:
890890
]
891891

892892
category_order = [
893-
"Object Explorer",
893+
"Explorer",
894894
"Query Editor (Normal)",
895895
"Query Editor (Insert)",
896896
"Results",

sqlit/ui/mixins/tree.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def _db_type_badge(self, db_type: str) -> str:
3939
return badge_map.get(db_type, db_type.upper() if db_type else "DB")
4040

4141
def refresh_tree(self) -> None:
42-
"""Refresh the object explorer tree."""
42+
"""Refresh the explorer tree."""
4343
self.object_tree.clear()
4444
self.object_tree.root.expand()
4545

@@ -368,12 +368,12 @@ def on_tree_node_highlighted(self, event: Tree.NodeHighlighted) -> None:
368368
self._update_footer_bindings()
369369

370370
def action_refresh_tree(self) -> None:
371-
"""Refresh the object explorer."""
371+
"""Refresh the explorer."""
372372
self.refresh_tree()
373373
self.notify("Refreshed")
374374

375375
def action_collapse_tree(self) -> None:
376-
"""Collapse all nodes in the object explorer."""
376+
"""Collapse all nodes in the explorer."""
377377
def collapse_all(node):
378378
for child in node.children:
379379
collapse_all(child)

sqlit/ui/mixins/ui_navigation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def _update_section_labels(self) -> None:
8080
label_results.add_class("active")
8181

8282
def action_focus_explorer(self) -> None:
83-
"""Focus the Object Explorer pane."""
83+
"""Focus the Explorer pane."""
8484
if self._fullscreen_mode != "none":
8585
self._set_fullscreen_mode("none")
8686
# Unhide explorer if hidden

tests/ui/keybindings/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Keybindings tests package."""

tests/ui/keybindings/conftest.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Shared fixtures and mocks for keybindings tests."""
2+
3+
from __future__ import annotations
4+
5+
import pytest
6+
7+
from sqlit.keymap import (
8+
KeymapProvider,
9+
LeaderCommandDef,
10+
ActionKeyDef,
11+
reset_keymap,
12+
)
13+
14+
15+
class MockKeymapProvider(KeymapProvider):
16+
"""Mock keymap provider for testing custom keymaps."""
17+
18+
def __init__(
19+
self,
20+
leader_commands: list[LeaderCommandDef] | None = None,
21+
action_keys: list[ActionKeyDef] | None = None,
22+
):
23+
self._leader_commands = leader_commands or []
24+
self._action_keys = action_keys or []
25+
26+
def get_leader_commands(self) -> list[LeaderCommandDef]:
27+
return self._leader_commands
28+
29+
def get_action_keys(self) -> list[ActionKeyDef]:
30+
return self._action_keys
31+
32+
33+
@pytest.fixture(autouse=True)
34+
def reset_keymap_after_test():
35+
"""Reset keymap after each test to avoid cross-test pollution."""
36+
yield
37+
reset_keymap()
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""Tests for contextual keybindings that only work in specific contexts."""
2+
3+
from __future__ import annotations
4+
5+
from unittest.mock import patch
6+
7+
import pytest
8+
9+
from sqlit.app import SSMSTUI
10+
from sqlit.keymap import get_keymap
11+
12+
from ..mocks import MockConnectionStore, MockSettingsStore, create_test_connection
13+
14+
15+
class TestContextualKeybindings:
16+
"""Test that keybindings only work in their intended context."""
17+
18+
@pytest.mark.asyncio
19+
async def test_focus_explorer_key_when_query_focused(self):
20+
"""Focus explorer key should focus explorer when query panel is focused."""
21+
keymap = get_keymap()
22+
focus_explorer_key = keymap.action("focus_explorer")
23+
24+
app = SSMSTUI()
25+
26+
async with app.run_test(size=(100, 35)) as pilot:
27+
# Focus query first
28+
app.action_focus_query()
29+
await pilot.pause()
30+
assert app.query_input.has_focus
31+
32+
# Press focus explorer key
33+
await pilot.press(focus_explorer_key)
34+
await pilot.pause()
35+
36+
assert app.object_tree.has_focus
37+
38+
@pytest.mark.asyncio
39+
async def test_focus_query_key_when_explorer_focused(self):
40+
"""Focus query key should focus query when explorer is focused."""
41+
keymap = get_keymap()
42+
focus_query_key = keymap.action("focus_query")
43+
44+
app = SSMSTUI()
45+
46+
async with app.run_test(size=(100, 35)) as pilot:
47+
# Focus explorer first
48+
app.action_focus_explorer()
49+
await pilot.pause()
50+
assert app.object_tree.has_focus
51+
52+
# Press focus query key
53+
await pilot.press(focus_query_key)
54+
await pilot.pause()
55+
56+
assert app.query_input.has_focus
57+
58+
@pytest.mark.asyncio
59+
async def test_edit_connection_blocked_when_query_focused(self):
60+
"""Edit connection key should NOT trigger edit_connection when query is focused."""
61+
keymap = get_keymap()
62+
edit_key = keymap.action("edit_connection")
63+
64+
connections = [create_test_connection("TestDB", "sqlite")]
65+
mock_connections = MockConnectionStore(connections)
66+
mock_settings = MockSettingsStore({"theme": "tokyo-night"})
67+
68+
with patch("sqlit.app.load_connections", mock_connections.load_all), \
69+
patch("sqlit.app.load_settings", mock_settings.load_all), \
70+
patch("sqlit.app.save_settings", mock_settings.save_all):
71+
72+
app = SSMSTUI()
73+
74+
async with app.run_test(size=(100, 35)) as pilot:
75+
# Focus query
76+
app.action_focus_query()
77+
await pilot.pause()
78+
79+
edit_called = False
80+
original_edit = app.action_edit_connection
81+
82+
def mock_edit():
83+
nonlocal edit_called
84+
edit_called = True
85+
original_edit()
86+
87+
app.action_edit_connection = mock_edit
88+
89+
# Press edit key - should focus explorer (since e is also focus_explorer), not edit connection
90+
await pilot.press(edit_key)
91+
await pilot.pause()
92+
93+
assert not edit_called

0 commit comments

Comments
 (0)