import os import sys from rich.console import RenderableType from rich.syntax import Syntax from rich.traceback import Traceback from textual import events from textual.app import App from textual.widgets import Header, Footer, FileClick, ScrollView, DirectoryTree class MyApp(App): """An example of a very simple Textual App""" async def on_load(self, event: events.Load) -> None: """Sent before going in to application mode.""" # Bind our basic keys await self.bind("b", "view.toggle('sidebar')", "Toggle sidebar") await self.bind("q", "quit", "Quit") # Get path to show try: self.path = sys.argv[1] except IndexError: self.path = os.path.abspath( os.path.join(os.path.basename(__file__), "../../") ) async def on_mount(self, event: events.Mount) -> None: """Call after terminal goes in to application mode""" # Create our widgets # In this a scroll view for the code and a directory tree self.body = ScrollView() self.directory = DirectoryTree(self.path, "Code") # Dock our widgets await self.view.dock(Header(), edge="top") await self.view.dock(Footer(), edge="bottom") # Note the directory is also in a scroll view await self.view.dock( ScrollView(self.directory), edge="left", size=32, name="sidebar" ) await self.view.dock(self.body, edge="top") async def message_file_click(self, message: FileClick) -> None: """A message sent by the directory tree when a file is clicked.""" syntax: RenderableType try: # Construct a Syntax object for the path in the message syntax = Syntax.from_path( message.path, line_numbers=True, word_wrap=True, indent_guides=True, theme="monokai", ) except Exception: # Possibly a binary file # For demonstration purposes we will show the traceback syntax = Traceback(theme="monokai", width=None, show_locals=True) self.app.sub_title = os.path.basename(message.path) await self.body.update(syntax) # Run our app class MyApp.run(title="Code Viewer", log="textual.log")