Closed JoeZiminski closed 7 months ago
Hey there! I'm struggling to understand exactly what the underlying issue seems to be, maybe some sort of MRE would be helpful? Something with code that I can run.
I say this because I created a silly subclass of DirectoryTree
that changes the colour of files/folders that have an a
in the name and that custom colour doesn't go away when I click those files/folders or when I navigate the directory tree.
The recording below shows said directory tree in action where all files/folders with an a
in the name are coloured green:
https://github.com/Textualize/textual/assets/5621605/0759bdec-5acd-4d24-ae7c-f9a52b590bd5
Thanks @rodrigogiraoserrao! Apologies, did not think to supply an MRE 🤦♂️ Please find below:
from rich.style import Style
from rich.text import Text
from textual.app import App
from textual.widgets import DirectoryTree
from textual.widgets._directory_tree import DirEntry
from textual.widgets._tree import TOGGLE_STYLE, TreeNode
ROOT_PATH = "path/to/some/folder"
FOLDERNAME_TO_HIGHLIGHT = ["dir_1", "dir_2"]
class MyDirectoryTree(DirectoryTree):
DEFAULT_CSS = """
MyDirectoryTree:focus > .tree--cursor {
background: $panel-lighten-2;
}
"""
def render_label(
self, node: TreeNode[DirEntry], base_style: Style, style: Style
) -> Text:
"""
This function is exactly the same as the parent method
except for the `style_node_color` call.
"""
node_label = node._label.copy()
node_label.stylize(style)
node_path = node.data.path
if node._allow_expand:
prefix = (
"📂 " if node.is_expanded else "📁 ",
base_style + TOGGLE_STYLE,
)
node_label.stylize_before(
self.get_component_rich_style(
"directory-tree--folder", partial=True
)
)
else:
prefix = (
"📄 ",
base_style,
)
node_label.stylize_before(
self.get_component_rich_style(
"directory-tree--file", partial=True
),
)
node_label.highlight_regex(
r"\..+$",
self.get_component_rich_style(
"directory-tree--extension", partial=True
),
)
self.style_node_color(node_label, node_path)
text = Text.assemble(prefix, node_label)
return text
def style_node_color(self, node_label, node_path):
if node_path.stem in FOLDERNAME_TO_HIGHLIGHT:
node_label.stylize_before("bright_red")
class TuiApp(App):
def compose(self):
yield MyDirectoryTree(ROOT_PATH)
if __name__ == "__main__":
TuiApp().run()
It looks long because of the override of render_label
but the only change in the overriden method is the call to style_node_color
. To highlight some directories you will need to replace ROOT_PATH
and FOLDERNAME_TO_HIGHLIGHT
with some arbitary directory path on your system, and folder name/s within it, repsectively.
I wonder why we are seeing different behaviour, maybe it is due to how we are styling the node (in the overriden render_label
). The result I get is like the below:
Thanks a lot for taking a look at this!
You don't have to copy and paste the whole code only to add an extra function call at the end.
This would do the same thing as your code:
def render_label(
self, node: TreeNode[DirEntry], base_style: Style, style: Style
) -> Text:
text = super().render_label(node, base_style, style)
self.style_node_color(text, node.data.path)
return text
As for the overriding, notice that in my comment above I'm using Text.stylize
whereas your code is using Text.stylize_before
:
I'll close this issue as it seems to me it is resolved. Feel free to reopen if you feel I missed something!
Don't forget to star the repository!
Follow @textualizeio for Textual updates.
Hi, in our program (image below) we have overriden the
render_label
function onDirectoryTree
to apply custom styling to different nodes (depending on their file-transfer status). However, when these are clicked the color is overridden by the default .CSS, and I asked on Discord and don't believe it is possible to set a kind of 'null' .CSS entry to just use the underlying styling.As a workaround we can excise the relevant lines in
_tree.py
(e.g. here). However, it would be nice to acheive this without overriding the entire function.Would you consider factoring out the blocks of code that handle this setting of CSS in the function e.g.
for this block to be replaced with a function call to something like:
and something similar for the lines.
I'm sure there are nicer and more generalisable ways to do this, but from a selfish point of veiw it would work great 😄 .
Cheers, Joe