textual
textual copied to clipboard
Can't Tree.select_node with newly added node
select_node doesn't work on on an add_leaf in one update cycle.
Can workaround with run_worker, see works vs doesn't work comments.
MRE:
from textual.binding import Binding
from textual.app import App, ComposeResult
from textual.widgets import Tree, Footer
class TreeApp(App[None]):
BINDINGS = [
Binding(key="p", action="paul", description="Paul"),
Binding(key="w", action="worm", description="Uh oh"),
Binding(key="r", action="ride", description="Kwisatz Haderach"),
]
def compose(self) -> ComposeResult:
tree: Tree[dict[str, str]] = Tree("Dune")
tree.root.add_leaf("Paul")
tree.root.add_leaf("Jessica")
tree.root.add_leaf("Chani")
tree.root.expand()
yield tree
yield Footer()
def action_paul(self):
tree = self.query_one(Tree)
tree.select_node(self.paul) # Works
def action_worm(self):
tree = self.query_one(Tree)
node = tree.root.add_leaf("Worm")
tree.select_node(node) # Doesn't work
def action_ride(self):
tree = self.query_one(Tree)
node = tree.root.add_leaf("Shai-Hulud")
async def select():
tree.select_node(node) # Works
self.run_worker(select)
if __name__ == "__main__":
app = TreeApp()
app.run()
Textual Diagnostics
Versions
| Name | Value |
|---|---|
| Textual | 0.39.0 |
| Rich | 13.3.3 |
Python
| Name | Value |
|---|---|
| Version | 3.11.4 |
| Implementation | CPython |
| Compiler | MSC v.1934 64 bit (AMD64) |
| Executable | C:\Users\dave.venvs\ng\Scripts\python.exe |
Operating System
| Name | Value |
|---|---|
| System | Windows |
| Release | 10 |
| Version | 10.0.20348 |
Terminal
| Name | Value |
|---|---|
| Terminal Application | vscode (1.83.1) |
| TERM | Not set |
| COLORTERM | truecolor |
| FORCE_COLOR | Not set |
| NO_COLOR | Not set |
Rich Console options
| Name | Value |
|---|---|
| size | width=93, height=68 |
| legacy_windows | False |
| min_width | 1 |
| max_width | 93 |
| is_terminal | True |
| encoding | utf-8 |
| max_height | 68 |
| justify | None |
| overflow | None |
| no_wrap | False |
| highlight | None |
| markup | None |
| height | None |
Feel free to add screenshots and / or videos. These can be very helpful!
I can't reproduce this using your MRE. What exactly are you doing when running the MRE that's causing the problem?
Could you describe in more detail what you mean when you say it doesn't work?
Is there a stack trace you can share, or does it just not behave as you'd expect?
If you press w this adds the "Worm" node but the select_node on the next line doesn't work, instead it selects "Dune".
Possibly another case of work happening on idle so needs acall_after_refresh?
@TomJGooding Sure seems like it!
@darrenburns The problem is that node._line for the new "Worm" node is -1 when select_node is called.
It looks like the line number for each node is only calculated in _build from a call in _on_idle.
You could explicitly call _build when a new node is added, but I'm not sure that's the proper fix?
Yes @TomJGooding, thanks for clarifying 🙏🏻 I've updated MRE to be less confusing.
Your analysis makes sense.
I think figuring out when _build is going to be... wait for it... a real can of worms 🙃
Since select_node uses the line number of the node, it makes sense to recalculate them if the cache has been cleared.
move_cursor should call self._refresh_node(node), or more minimally, run the following:
if self._tree_lines_cached is None:
self._build()