mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Swap to a dual-working approach
Plan C; or is it plan D? Something like that. Anyway... in this approach we keep a single "forever" async task worker per directory tree, which in turn looks at the async Queue, and when a new node appears on it it starts a short-lived thread to load the directory data. This seems to be working fine on macOS. Next up is testing on Windows.
This commit is contained in:
@@ -11,7 +11,7 @@ from rich.text import Text, TextType
|
|||||||
from .. import work
|
from .. import work
|
||||||
from ..message import Message
|
from ..message import Message
|
||||||
from ..reactive import var
|
from ..reactive import var
|
||||||
from ..worker import Worker, get_current_worker
|
from ..worker import Worker, WorkerCancelled, WorkerFailed, get_current_worker
|
||||||
from ._tree import TOGGLE_STYLE, Tree, TreeNode
|
from ._tree import TOGGLE_STYLE, Tree, TreeNode
|
||||||
|
|
||||||
|
|
||||||
@@ -269,22 +269,22 @@ class DirectoryTree(Tree[DirEntry]):
|
|||||||
yield entry
|
yield entry
|
||||||
|
|
||||||
@work
|
@work
|
||||||
def _load_directory(self, node: TreeNode[DirEntry]) -> None:
|
def _load_directory(self, node: TreeNode[DirEntry]) -> list[Path]:
|
||||||
"""Load the directory contents for a given node.
|
"""Load the directory contents for a given node.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
node: The node to load the directory contents for.
|
node: The node to load the directory contents for.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The list of entries within the directory associated with the node.
|
||||||
"""
|
"""
|
||||||
assert node.data is not None
|
assert node.data is not None
|
||||||
node.data.loaded = True
|
node.data.loaded = True
|
||||||
worker = get_current_worker()
|
return sorted(
|
||||||
self.app.call_from_thread(
|
self.filter_paths(
|
||||||
self._populate_node,
|
self._directory_content(node.data.path, get_current_worker())
|
||||||
node,
|
|
||||||
sorted(
|
|
||||||
self.filter_paths(self._directory_content(node.data.path, worker)),
|
|
||||||
key=lambda path: (not path.is_dir(), path.name.lower()),
|
|
||||||
),
|
),
|
||||||
|
key=lambda path: (not path.is_dir(), path.name.lower()),
|
||||||
)
|
)
|
||||||
|
|
||||||
@work(exclusive=True)
|
@work(exclusive=True)
|
||||||
@@ -292,7 +292,26 @@ class DirectoryTree(Tree[DirEntry]):
|
|||||||
"""Background loading queue processor."""
|
"""Background loading queue processor."""
|
||||||
worker = get_current_worker()
|
worker = get_current_worker()
|
||||||
while not worker.is_cancelled:
|
while not worker.is_cancelled:
|
||||||
self._load_directory(await self._to_load.get())
|
# Get the next node that needs loading off the queue. Note that
|
||||||
|
# this blocks if the queue is empty.
|
||||||
|
node = await self._to_load.get()
|
||||||
|
content: list[Path] = []
|
||||||
|
try:
|
||||||
|
# Spin up a short-lived thread that will load the content of
|
||||||
|
# the directory associated with that node.
|
||||||
|
content = await self._load_directory(node).wait()
|
||||||
|
except WorkerCancelled:
|
||||||
|
# The worker was cancelled, that would suggest we're all
|
||||||
|
# done here and we should get out of the loader in general.
|
||||||
|
break
|
||||||
|
except WorkerFailed:
|
||||||
|
# This particular worker failed to start. We don't know the
|
||||||
|
# reason so let's no-op that (for now anyway).
|
||||||
|
pass
|
||||||
|
# We're still here and we have directory content, get it into
|
||||||
|
# the tree.
|
||||||
|
if content:
|
||||||
|
self._populate_node(node, content)
|
||||||
|
|
||||||
def _on_tree_node_expanded(self, event: Tree.NodeExpanded) -> None:
|
def _on_tree_node_expanded(self, event: Tree.NodeExpanded) -> None:
|
||||||
event.stop()
|
event.stop()
|
||||||
|
|||||||
Reference in New Issue
Block a user