commits
tags
from __future__ import annotations
from pathlib import Path
from typing import Iterable
from textual.command import CommandPalette
from textual.containers import Horizontal, Vertical
from textual.reactive import var
from textual.screen import ModalScreen
from textual.widgets import Button, DirectoryTree, Label
class NerdCommandPalette(CommandPalette):
icon: var[str] = var(" ") # nf-fa-search
class DirsOnlyDirectoryTree(DirectoryTree):
ICON_NODE = " " # nf-fa-folder
ICON_NODE_EXPANDED = " " # nf-fa-folder_open
def filter_paths(self, paths: Iterable[Path]) -> Iterable[Path]:
return [p for p in paths if p.is_dir() and not p.name.startswith(".")]
class DirectoryPickerScreen(ModalScreen[Path | None]):
CSS = """
DirectoryPickerScreen {
align: center middle;
}
#picker-dialog {
width: 80%;
height: 80%;
border: round $primary;
background: $surface;
padding: 1 2;
}
#picker-title {
height: auto;
text-style: bold;
}
#picker-current {
height: auto;
color: $text-muted;
margin-bottom: 1;
}
DirsOnlyDirectoryTree {
height: 1fr;
border: round $panel;
}
#picker-buttons {
height: auto;
margin-top: 1;
align: right middle;
}
#picker-buttons Button {
margin-left: 1;
}
#up-btn {
dock: left;
margin-left: 0;
}
"""
BINDINGS = [
("escape", "cancel", "Cancel"),
("backspace", "go_up", "Up"),
]
def __init__(self, start_path: Path) -> None:
super().__init__()
path = start_path
while not path.is_dir():
if path.parent == path:
path = Path.home()
break
path = path.parent
self.start_path = path
self.selected_path = path
def compose(self):
yield Vertical(
Label("Choose a folder to save downloads to", id="picker-title"),
Label(str(self.selected_path), id="picker-current"),
DirsOnlyDirectoryTree(self.start_path, id="picker-tree"),
Horizontal(
Button("Up", id="up-btn"),
Button("Cancel", id="cancel-btn"),
Button("Select", id="select-btn", variant="primary"),
id="picker-buttons",
),
id="picker-dialog",
)
def on_mount(self) -> None:
self.query_one(DirsOnlyDirectoryTree).focus()
def on_directory_tree_directory_selected(
self, event: DirectoryTree.DirectorySelected
) -> None:
self.selected_path = event.path
self.query_one("#picker-current", Label).update(str(self.selected_path))
def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "select-btn":
self.dismiss(self.selected_path)
elif event.button.id == "cancel-btn":
self.dismiss(None)
elif event.button.id == "up-btn":
self.action_go_up()
def action_cancel(self) -> None:
self.dismiss(None)
def action_go_up(self) -> None:
tree = self.query_one(DirsOnlyDirectoryTree)
current_root = Path(tree.path)
parent = current_root.parent
if parent == current_root:
return
tree.path = parent
self.selected_path = parent
self.query_one("#picker-current", Label).update(str(parent))