diff --git a/sandbox/will/calculator.py b/sandbox/will/calculator.py index 7c06c4d54..dabf99376 100644 --- a/sandbox/will/calculator.py +++ b/sandbox/will/calculator.py @@ -72,6 +72,8 @@ class CalculatorApp(App): def on_key(self, event: events.Key) -> None: """Called when the user presses a key.""" + print(f"KEY {event} was pressed!") + def press(button_id: str) -> None: self.query_one(f"#{button_id}", Button).press() self.set_focus(None) diff --git a/src/textual/_log.py b/src/textual/_log.py index cc870e00d..73c549a6d 100644 --- a/src/textual/_log.py +++ b/src/textual/_log.py @@ -7,6 +7,7 @@ class LogGroup(Enum): INFO = auto() WARNING = auto() ERROR = auto() + PRINT = auto() class LogVerbosity(Enum): diff --git a/src/textual/cli/cli.py b/src/textual/cli/cli.py index 178f3f66e..bf73c45b8 100644 --- a/src/textual/cli/cli.py +++ b/src/textual/cli/cli.py @@ -20,14 +20,15 @@ def run(): @run.command(help="Run the Textual Devtools console.") @click.option("-v", "verbose", help="Enable verbose logs.", is_flag=True) -def console(verbose: bool = False): +@click.option("-x", "--exclude", "exclude", help="Exclude log group(s)", multiple=True) +def console(verbose: bool, exclude: list[str]) -> None: from rich.console import Console console = Console() console.clear() console.show_cursor(False) try: - _run_devtools(verbose=verbose) + _run_devtools(verbose=verbose, exclude=exclude) finally: console.show_cursor(True) diff --git a/src/textual/devtools/redirect_output.py b/src/textual/devtools/redirect_output.py index cf4c78642..e18cf872b 100644 --- a/src/textual/devtools/redirect_output.py +++ b/src/textual/devtools/redirect_output.py @@ -1,12 +1,13 @@ from __future__ import annotations import inspect -from io import TextIOWrapper + from typing import TYPE_CHECKING, cast -from textual.devtools.client import DevtoolsLog +from .client import DevtoolsLog +from .._log import LogGroup, LogVerbosity, LogSeverity if TYPE_CHECKING: - from textual.devtools.client import DevtoolsClient + from .devtools.client import DevtoolsClient class StdoutRedirector: @@ -96,4 +97,9 @@ class StdoutRedirector: # that the log message content is a string. The cast below tells mypy this. batched_log = "".join(cast(str, log.objects_or_string) for log in log_batch) batched_log = batched_log.rstrip() - self.devtools.log(DevtoolsLog(batched_log, caller=log_batch[-1].caller)) + self.devtools.log( + LogGroup.PRINT, + LogVerbosity.NORMAL, + LogSeverity.NORMAL, + DevtoolsLog(batched_log, caller=log_batch[-1].caller), + ) diff --git a/src/textual/devtools/renderables.py b/src/textual/devtools/renderables.py index 35d7eb943..511d86670 100644 --- a/src/textual/devtools/renderables.py +++ b/src/textual/devtools/renderables.py @@ -18,9 +18,9 @@ from rich.markup import escape from rich.rule import Rule from rich.segment import Segment, Segments from rich.style import Style +from rich.styled import Styled from rich.table import Table from rich.text import Text - from textual._log import LogGroup DevConsoleMessageLevel = Literal["info", "warning", "error"] @@ -90,18 +90,24 @@ class DevConsoleLog: file_and_line = escape(f"{Path(self.path).name}:{self.line_number}") group = LogGroup(self.group).name time = local_time.time() + message = Text( + f":warning-emoji: [{time}] {group}" + if self.severity + else f"[{time}] {group}" + ) + message.stylize("dim") + table.add_row( - ( - f":warning-emoji: [dim]{time} {group}" - if self.severity - else f"[dim][{time}] ({group.lower()})" - ), + message, Align.right( Text(f"{file_and_line}", style=Style(dim=True, link=file_link)) ), ) yield table - yield Segments(self.segments) + if group == "PRINT": + yield Styled(Segments(self.segments), "bold") + else: + yield Segments(self.segments) class DevConsoleNotice: diff --git a/src/textual/devtools/server.py b/src/textual/devtools/server.py index 2f296362c..b2bddf821 100644 --- a/src/textual/devtools/server.py +++ b/src/textual/devtools/server.py @@ -36,8 +36,8 @@ async def _on_startup(app: Application) -> None: await service.start() -def _run_devtools(verbose: bool = False) -> None: - app = _make_devtools_aiohttp_app(verbose=verbose) +def _run_devtools(verbose: bool, exclude: list[str]) -> None: + app = _make_devtools_aiohttp_app(verbose=verbose, exclude=exclude) def noop_print(_: str): return None @@ -46,6 +46,7 @@ def _run_devtools(verbose: bool = False) -> None: def _make_devtools_aiohttp_app( + exclude: list[str], size_change_poll_delay_secs: float = DEFAULT_SIZE_CHANGE_POLL_DELAY_SECONDS, verbose: bool = False, ) -> Application: @@ -56,7 +57,7 @@ def _make_devtools_aiohttp_app( app["verbose"] = verbose app["service"] = DevtoolsService( - update_frequency=size_change_poll_delay_secs, verbose=verbose + update_frequency=size_change_poll_delay_secs, verbose=verbose, exclude=exclude ) app.add_routes( diff --git a/src/textual/devtools/service.py b/src/textual/devtools/service.py index bdfa06d84..da5419150 100644 --- a/src/textual/devtools/service.py +++ b/src/textual/devtools/service.py @@ -16,6 +16,7 @@ from rich.console import Console from rich.markup import escape import msgpack +from textual._log import LogGroup from textual.devtools.renderables import ( DevConsoleLog, DevConsoleNotice, @@ -30,15 +31,22 @@ class DevtoolsService: responsible for tracking connected client applications. """ - def __init__(self, update_frequency: float, verbose: bool = False) -> None: + def __init__( + self, + update_frequency: float, + verbose: bool = False, + exclude: list[str] | None = None, + ) -> None: """ Args: update_frequency (float): The number of seconds to wait between sending updates of the console size to connected clients. verbose (bool): Enable verbose logging on client. + exclude (list[str]): List of log groups to exclude from output. """ self.update_frequency = update_frequency self.verbose = verbose + self.exclude = set(name.upper() for name in exclude) if exclude else set() self.console = Console() self.shutdown_event = asyncio.Event() self.clients: list[ClientHandler] = [] @@ -92,7 +100,7 @@ class DevtoolsService: { "type": "server_info", "payload": { - "width": self.console.width, + "width": self.console.width - 4, "height": self.console.height, "verbose": self.verbose, }, @@ -173,6 +181,8 @@ class ClientHandler: type = message["type"] if type == "client_log": payload = message["payload"] + if LogGroup(payload["group"]).name in self.service.exclude: + continue encoded_segments = payload["segments"] segments = pickle.loads(encoded_segments) message_time = time() diff --git a/src/textual/events.py b/src/textual/events.py index b106a2556..e868eedab 100644 --- a/src/textual/events.py +++ b/src/textual/events.py @@ -337,12 +337,12 @@ class MouseMove(MouseEvent, bubble=True, verbose=True): @rich.repr.auto -class MouseDown(MouseEvent, bubble=True): +class MouseDown(MouseEvent, bubble=True, verbose=True): pass @rich.repr.auto -class MouseUp(MouseEvent, bubble=True): +class MouseUp(MouseEvent, bubble=True, verbose=True): pass @@ -407,11 +407,11 @@ class Blur(Event, bubble=False): pass -class DescendantFocus(Event, bubble=True): +class DescendantFocus(Event, bubble=True, verbose=True): pass -class DescendantBlur(Event, bubble=True): +class DescendantBlur(Event, bubble=True, verbose=True): pass