Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support new Textual footer #613

Merged
merged 3 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion news/597.bugfix.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Fix dynamic toggling between descriptions like "Pause" vs "Unpause" or "Show" vs "Hide" in the footer of the live-mode TUI and tree reporter. This was broken by changes introduced in Textual 0.61.
Fix dynamic toggling between descriptions like "Pause" vs "Unpause" or "Show" vs "Hide" in the footer of the live-mode TUI and tree reporter. This was broken by changes introduced in Textual 0.61 (and again by Textual 0.63).
14 changes: 14 additions & 0 deletions src/memray/reporters/_textual_hacks.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import dataclasses
from typing import Any
from typing import Dict
from typing import Tuple
from typing import Union

from textual import binding
from textual.app import App
from textual.binding import Binding
from textual.dom import DOMNode
from textual.widgets import Footer

# In Textual 0.61, `App.namespace_bindings` was removed in favor of
# `Screen.active_bindings`. The two have a slightly different interface:
Expand All @@ -24,3 +27,14 @@ def update_key_description(bindings: Bindings, key: str, description: str) -> No
bindings[key] = val[:1] + (binding,) + val[2:] # type: ignore
else:
bindings[key] = val._replace(binding=binding) # type: ignore


def redraw_footer(app: App[Any]) -> None:
footer = app.query_one(Footer)
if hasattr(footer, "recompose"):
# Added in Textual v0.53
footer.refresh(recompose=True)
else: # pragma: no cover
# Hack: trick the Footer into redrawing itself
footer.highlight_key = "q" # type: ignore[attr-defined]
footer.highlight_key = None # type: ignore[attr-defined]
10 changes: 3 additions & 7 deletions src/memray/reporters/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from memray import AllocationRecord
from memray._memray import size_fmt
from memray.reporters._textual_hacks import Bindings
from memray.reporters._textual_hacks import redraw_footer
from memray.reporters._textual_hacks import update_key_description
from memray.reporters.frame_tools import is_cpython_internal
from memray.reporters.frame_tools import is_frame_from_import_system
Expand Down Expand Up @@ -367,7 +368,7 @@ def action_toggle_import_system(self) -> None:
else:
self.import_system_filter = None

self.redraw_footer()
redraw_footer(self.app)
self.repopulate_tree(self.query_one(FrameTree))

def action_toggle_uninteresting(self) -> None:
Expand All @@ -376,14 +377,9 @@ def action_toggle_uninteresting(self) -> None:
else:
self.uninteresting_filter = None

self.redraw_footer()
redraw_footer(self.app)
self.repopulate_tree(self.query_one(FrameTree))

def redraw_footer(self) -> None:
# Hack: trick the Footer into redrawing itself
self.app.query_one(Footer).highlight_key = "q"
self.app.query_one(Footer).highlight_key = None

def rewrite_bindings(self, bindings: Bindings) -> None:
if self.import_system_filter is not None:
update_key_description(bindings, "i", "Show import system")
Expand Down
14 changes: 5 additions & 9 deletions src/memray/reporters/tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
from memray import SocketReader
from memray._memray import size_fmt
from memray.reporters._textual_hacks import Bindings
from memray.reporters._textual_hacks import redraw_footer
from memray.reporters._textual_hacks import update_key_description

MAX_MEMORY_RATIO = 0.95
Expand Down Expand Up @@ -535,8 +536,8 @@ class TUI(Screen[None]):
thread_idx = reactive(0)
threads = reactive(_DUMMY_THREAD_LIST, always_update=True)
snapshot = reactive(_EMPTY_SNAPSHOT)
paused = reactive(False)
disconnected = reactive(False)
paused = reactive(False, init=False)
disconnected = reactive(False, init=False)

def __init__(self, pid: Optional[int], cmd_line: Optional[str], native: bool):
self.pid = pid
Expand Down Expand Up @@ -566,7 +567,7 @@ def action_toggle_pause(self) -> None:
"""Toggle pause on keypress"""
if self.paused or not self.disconnected:
self.paused = not self.paused
self.redraw_footer()
redraw_footer(self.app)
if not self.paused:
self.display_snapshot()

Expand All @@ -592,7 +593,7 @@ def watch_threads(self, threads: List[int]) -> None:

def watch_disconnected(self) -> None:
self.update_label()
self.redraw_footer()
redraw_footer(self.app)

def watch_paused(self) -> None:
self.update_label()
Expand Down Expand Up @@ -664,11 +665,6 @@ def update_sort_key(self, col_number: int) -> None:
body = self.query_one(AllocationTable)
body.sort_column_id = col_number

def redraw_footer(self) -> None:
# Hack: trick the Footer into redrawing itself
self.app.query_one(Footer).highlight_key = "q"
self.app.query_one(Footer).highlight_key = None

def rewrite_bindings(self, bindings: Bindings) -> None:
if "space" in bindings and bindings["space"][1].description == "Pause":
if self.paused:
Expand Down
Loading
Loading