mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Simple file search live filter sandbox example
This commit is contained in:
74
sandbox/file_search.py
Normal file
74
sandbox/file_search.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
from rich.console import RenderableType
|
||||
from rich.style import Style
|
||||
from rich.table import Table
|
||||
from rich.text import Text
|
||||
|
||||
from textual.app import App
|
||||
from textual.geometry import Size
|
||||
from textual.reactive import Reactive
|
||||
from textual.widget import Widget
|
||||
from textual.widgets.text_input import TextInput, TextWidgetBase
|
||||
|
||||
|
||||
def get_files() -> list[Path]:
|
||||
files = [file for file in Path.cwd().iterdir()]
|
||||
return files
|
||||
|
||||
|
||||
class FileTable(Widget):
|
||||
filter = Reactive("", layout=True)
|
||||
|
||||
def __init__(self, *args, files: Iterable[Path] | None = None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.files = files if files is not None else []
|
||||
|
||||
@property
|
||||
def filtered_files(self) -> list[Path]:
|
||||
return [
|
||||
file
|
||||
for file in self.files
|
||||
if self.filter == "" or (self.filter and self.filter in file.name)
|
||||
]
|
||||
|
||||
def get_content_height(self, container: Size, viewport: Size, width: int) -> int:
|
||||
return len(self.filtered_files)
|
||||
|
||||
def render(self, style: Style) -> RenderableType:
|
||||
grid = Table.grid()
|
||||
grid.add_column()
|
||||
for file in self.filtered_files:
|
||||
file_text = Text(" " + file.name)
|
||||
file_text.highlight_regex(self.filter, "black on yellow")
|
||||
grid.add_row(file_text)
|
||||
return grid
|
||||
|
||||
|
||||
class FileSearchApp(App[str]):
|
||||
dark = True
|
||||
|
||||
def on_mount(self) -> None:
|
||||
self.file_table = FileTable(id="file_table", files=list(Path.cwd().iterdir()))
|
||||
self.mount(file_table_wrapper=Widget(self.file_table))
|
||||
|
||||
self.search_bar = TextInput(placeholder="Search for files...")
|
||||
self.search_bar.cursor_blink_enabled = True
|
||||
self.search_bar.focus()
|
||||
|
||||
self.mount(search_bar=self.search_bar)
|
||||
|
||||
def handle_changed(self, event: TextWidgetBase.Changed) -> None:
|
||||
if event.sender == self.search_bar:
|
||||
self.file_table.filter = event.value
|
||||
|
||||
|
||||
app = FileSearchApp(
|
||||
log_path="textual.log", css_path="file_search.scss", watch_css=True, log_verbosity=2
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = app.run()
|
||||
21
sandbox/file_search.scss
Normal file
21
sandbox/file_search.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
Screen {
|
||||
layout: dock;
|
||||
docks: top=top bottom=bottom;
|
||||
}
|
||||
|
||||
#file_table_wrapper {
|
||||
dock: bottom;
|
||||
height: auto;
|
||||
overflow: auto auto;
|
||||
scrollbar-color: $accent-darken-1;
|
||||
}
|
||||
|
||||
#file_table {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#search_bar {
|
||||
dock: bottom;
|
||||
background: $accent;
|
||||
height: 1;
|
||||
}
|
||||
Reference in New Issue
Block a user