diff --git a/sqlit/domains/explorer/ui/mixins/tree_filter.py b/sqlit/domains/explorer/ui/mixins/tree_filter.py index 410fec35..ff3a68c4 100644 --- a/sqlit/domains/explorer/ui/mixins/tree_filter.py +++ b/sqlit/domains/explorer/ui/mixins/tree_filter.py @@ -42,13 +42,17 @@ class TreeFilterMixin: "procedures", } - def action_tree_filter(self: TreeFilterMixinHost) -> None: + def action_tree_filter(self: TreeFilterMixinHost, initial_text: str | None = None) -> None: """Open the tree filter.""" if not self.object_tree.has_focus: self.object_tree.focus() + if initial_text is None: + opened_with_slash = getattr(self, "_last_key_char", None) == "/" or getattr(self, "_last_key", None) == "slash" + initial_text = "/" if opened_with_slash else "" + self._tree_filter_visible = True - self._tree_filter_text = "" + self._tree_filter_text = initial_text self._tree_filter_query = "" self._tree_filter_fuzzy = False self._tree_filter_regex_mode = False @@ -162,7 +166,7 @@ def on_key(self: TreeFilterMixinHost, event: Any) -> None: return if key == "/": - self.action_tree_filter() + self.action_tree_filter("/") event.prevent_default() event.stop() return @@ -185,7 +189,7 @@ def on_key(self: TreeFilterMixinHost, event: Any) -> None: char = getattr(event, "character", None) if char and char.isprintable(): if char == "/" and not self._tree_filter_typing: - self.action_tree_filter() + self.action_tree_filter("/") event.prevent_default() event.stop() return @@ -232,7 +236,7 @@ def _update_tree_filter(self: TreeFilterMixinHost) -> None: self._tree_filter_matches = [] self._tree_filter_applied = False self._ensure_tree_filter_search_nodes_loaded() - self.tree_filter_input.set_filter("", 0, total) + self.tree_filter_input.set_filter(raw_text, 0, total) return self._ensure_tree_filter_search_nodes_loaded() diff --git a/sqlit/shared/ui/protocols/explorer.py b/sqlit/shared/ui/protocols/explorer.py index e6a2d522..0c58f6a9 100644 --- a/sqlit/shared/ui/protocols/explorer.py +++ b/sqlit/shared/ui/protocols/explorer.py @@ -46,7 +46,7 @@ def _get_node_kind(self, node: Any) -> str: def _activate_tree_node(self, node: Any) -> None: ... - def action_tree_filter(self) -> None: + def action_tree_filter(self, initial_text: str | None = None) -> None: ... def action_tree_filter_close(self) -> None: diff --git a/tests/unit/test_tree_filter.py b/tests/unit/test_tree_filter.py index 652fe548..fe320ad0 100644 --- a/tests/unit/test_tree_filter.py +++ b/tests/unit/test_tree_filter.py @@ -187,3 +187,29 @@ def test_tree_filter_invalid_regex_does_not_raise() -> None: assert host._tree_filter_regex_error assert host._tree_filter_matches == [] assert host.tree_filter_input.last_filter == (r"/(orders", 0, 2) + + +def test_tree_filter_opened_by_slash_keeps_slash_visible() -> None: + root = FakeNode("root") + root.add("Tables", FolderNode(folder_type="tables")) + host = FakeTreeFilterHost(root) + host._last_key = "slash" + host._last_key_char = "/" + + host.action_tree_filter() + + assert host._tree_filter_text == "/" + assert host._tree_filter_regex_mode is True + assert host.tree_filter_input.last_filter == ("/", 0, 1) + + +def test_tree_filter_empty_regex_prefix_remains_visible() -> None: + root = FakeNode("root") + root.add("Tables", FolderNode(folder_type="tables")) + host = FakeTreeFilterHost(root) + host._tree_filter_text = "/" + + host._update_tree_filter() + + assert host._tree_filter_regex_mode is True + assert host.tree_filter_input.last_filter == ("/", 0, 1)