textual
textual copied to clipboard
TreeControl doesn't refresh when adding new nodes
I'm using textual 0.3.0.
As the title says, when I add nodes, the tree control doesn't refresh.
Interestingly enough, after toggling its css, it starts to behave correctly.
Attached below is the code for a minimally reproducing program. Run it, wait a few seconds, and then press either F
or D
and see it suddenly updates.
Whatever "mode" gets activated, it should be active before the user inputs anything.
test_tree_refresh.py
from textual import events
from textual.app import App, ComposeResult
from textual.containers import Container, Vertical
from textual.reactive import var
from textual.widgets import Footer, Header, Static
from functools import lru_cache
import os.path
from rich.console import RenderableType
from rich.text import Text
from textual.widgets._tree_control import TreeControl, TreeNode
class DirectoryTree(TreeControl[str]):
def __init__(
self,
path: str,
*,
name: str | None = None,
id: str | None = None,
classes: str | None = None,
) -> None:
self.path = os.path.expanduser(path.rstrip("/"))
label = os.path.basename(self.path)
data = "$"
super().__init__(label, data, name=name, id=id, classes=classes)
self.root.tree.guide_style = "black"
def render_node(self, node: TreeNode[str]) -> RenderableType:
return self.render_tree_label(
node,
node.data,
node.expanded,
node.is_cursor,
node.id == self.hover_node,
self.has_focus,
)
@lru_cache(maxsize=1024 * 32)
def render_tree_label(
self,
node: TreeNode[str],
data,
expanded: bool,
is_cursor: bool,
is_hover: bool,
has_focus: bool,
) -> RenderableType:
meta = {
"@click": f"click_label({node.id})",
"tree_node": node.id,
"cursor": node.is_cursor,
}
label = Text(data)
if is_hover:
label.stylize("underline")
label.stylize("white")
label.highlight_regex(r"\d*", "cyan")
if label.plain.startswith("."):
label.stylize("dim")
if is_cursor and has_focus:
label.stylize("reverse")
icon = "📂" if expanded else "📁"
icon_label = Text(f"{icon} ", no_wrap=True, overflow="ellipsis") + label
icon_label.apply_meta(meta)
return icon_label
def on_styles_updated(self) -> None:
self.render_tree_label.cache_clear()
class TestApp(App):
"""Textual code browser app."""
CSS_PATH = "test_tree_refresh.css"
BINDINGS = [
("f", "toggle_files", "Toggle Files"),
("q", "quit", "Quit"),
("d", "toggle_dark", "Toggle dark mode")
]
show_tree = var(True)
def watch_show_tree(self, show_tree: bool) -> None:
"""Called when show_tree is modified."""
self.set_class(show_tree, "-show-tree")
def compose(self) -> ComposeResult:
"""Compose our UI."""
dt = DirectoryTree(".", id="tree")
dt.root.expand()
yield Header()
yield Container(
Vertical(dt, id="tree-view"),
Vertical(Static(id="code", expand=True), id="code-view"),
)
yield Footer()
def on_mount(self, event: events.Mount) -> None:
tree_view = self.query_one("#tree-view")
tree_view.focus()
self.set_interval(0.1, self.add_node)
def add_node(self):
tree = self.query_one("#tree")
tree.root.add('foo', 'bar')
def action_toggle_files(self) -> None:
"""Called in response to key binding."""
self.show_tree = not self.show_tree
TestApp().run()
test_tree_refresh.css:
Screen {
background: $surface-darken-1;
}
#tree-view {
display: none;
scrollbar-gutter: stable;
width: auto;
}
TestApp.-show-tree #tree-view {
display: block;
dock: left;
height: 100%;
max-width: 50%;
background: #151C25;
}
DirectoryTree {
padding-right: 1;
}
#code-view {
overflow: auto scroll;
min-width: 100%;
}
#code {
width: auto;
}
Sorry for the delay. The current TreeControl implementation has a few deficiencies. We're working on a new version.
I suspect your issue could be solved with a call to _clear_caches
call in the meantime.
Hi @willmcgugan , thanks for looking into it.
Can you please explain your solution? The only reference to _clear_caches
I can find is in _data_table: https://github.com/search?q=repo%3ATextualize%2Ftextual%20_clear_caches%20&type=code
We're working on a new version.
Any estimation to when it will be ready? And is there any issue for it, so I can subscribe to notifications?
@erezsh #741 would be the closest to an issue regarding reworking the tree control, but likely the best thing to watch is the draft PR Will has going for his work on this: https://github.com/Textualize/textual/pull/1170
And of course it will be mentioned in the release notes for whatever release this is rolled into.
@erezsh Just to update, the Tree
update got released around the middle of last month.
Hi @davep , I see that you removed _tree_control.py
.. Did you move TreeControl
elsewhere, or just removed it?
Renamed to _tree.py