From: Christian Heller Date: Mon, 11 Aug 2025 01:54:16 +0000 (+0200) Subject: Make .tainted hierarchical, disallow direct unsetting except on self. X-Git-Url: https://plomlompom.com/repos/booking/%7B%7B%20web_path%20%7D%7D/day?a=commitdiff_plain;h=1707cbed878c4048d254baea25ae66aa1865ac07;p=ircplom Make .tainted hierarchical, disallow direct unsetting except on self. --- diff --git a/ircplom/client_tui.py b/ircplom/client_tui.py index 1df12ce..ea6d9f3 100644 --- a/ircplom/client_tui.py +++ b/ircplom/client_tui.py @@ -67,7 +67,7 @@ class _PrivmsgPromptWidget(PromptWidget): 'Update prompt prefix with nickname data.' self._nickname = nickname self._nick_confirmed = nick_confirmed - self.tainted = True + self._tainted = True @classmethod def prefix_update_keys(cls) -> set: @@ -159,13 +159,11 @@ class _ClientWindowsManager: f'changing {key}: [{vals[0]}] -> [{vals[1]}]', scope=LogScope.ALL if key == 'nickname' else LogScope.SERVER) setattr(self, key, vals[1]) - tainteds = False if _PrivmsgPromptWidget.prefix_update_keys() | set(to_change): for win in [w for w in self.windows if isinstance(w, _PrivmsgWindow)]: self._prompt_update(win) - tainteds |= win.prompt.tainted - return tainteds + return bool([w for w in self.windows if w.tainted]) class ClientTui(BaseTui): diff --git a/ircplom/tui_base.py b/ircplom/tui_base.py index c829bbf..97b5404 100644 --- a/ircplom/tui_base.py +++ b/ircplom/tui_base.py @@ -55,13 +55,22 @@ class _Widget(ABC): @abstractmethod def __init__(self, **kwargs) -> None: super().__init__(**kwargs) - self.tainted = True + self._tainted = True self._drawable = False + def taint(self) -> None: + 'Declare as in need of re-drawing.' + self._tainted = True + + @property + def tainted(self) -> bool: + 'If in need of re-drawing.' + return self._tainted + @abstractmethod def set_geometry(self, measurements: _YX) -> bool: 'Update widget\'s measurements, re-generate content where necessary.' - self.tainted = True + self._tainted = True self._drawable = len([m for m in measurements if m < 0]) == 0 return self._drawable @@ -70,7 +79,7 @@ class _Widget(ABC): 'Print widget\'s content in shape appropriate to set geometry.' if not self._drawable: return False - self.tainted = False + self._tainted = False return True @@ -88,7 +97,7 @@ class _ScrollableWidget(_Widget, ABC): @abstractmethod def _scroll(self, up=True) -> None: - self.tainted = True + self._tainted = True def cmd__scroll(self, direction: str) -> None: 'Scroll through stored content/history.' @@ -131,7 +140,7 @@ class _HistoryWidget(_ScrollableWidget): def append(self, to_append: str) -> None: super().append(to_append) - self.tainted = True + self._tainted = True if self._history_idx < -1: self._history_idx -= 1 if not self._drawable: @@ -194,7 +203,7 @@ class PromptWidget(_ScrollableWidget): @_input_buffer.setter def _input_buffer(self, content) -> None: - self.tainted = True + self._tainted = True self._input_buffer_unsafe = content def set_geometry(self, measurements: _YX) -> bool: @@ -275,7 +284,7 @@ class PromptWidget(_ScrollableWidget): self._cursor_x += 1 else: return - self.tainted = True + self._tainted = True def _reset_buffer(self, content: str) -> None: self._input_buffer = content @@ -304,6 +313,15 @@ class Window(_Widget): if hasattr(self._term, 'size'): self.set_geometry() + def taint(self) -> None: + super().taint() + self.history.taint() + self.prompt.taint() + + @property + def tainted(self) -> bool: + return super().tainted or self.history.tainted or self.prompt.tainted + def set_geometry(self, _=None) -> bool: assert _ is None if self._term.size.y < _MIN_HEIGHT or self._term.size.x < _MIN_WIDTH: @@ -341,23 +359,20 @@ class Window(_Widget): title_box = f'{self.status_title}]' status_line = title_box + '=' * (self._term.size.x - len(title_box)) self._term.write(status_line, self._y_status) - self.history.draw() - self.prompt.draw() return True def cmd__paste(self) -> None: 'Write OSC 52 ? sequence to get encoded clipboard paste into stdin.' self._term.write(f'\033{_OSC52_PREFIX.decode()}?{_PASTE_DELIMITER}', self._y_status) - self.tainted = True + self._tainted = True def draw_tainted(self) -> None: 'Draw tainted parts of self.' - if self.tainted: - self.draw() - return for widget in [w for w in (self.history, self.prompt) if w.tainted]: widget.draw() + if self.tainted: + self.draw() class TuiEvent(AffectiveEvent): @@ -416,8 +431,8 @@ class BaseTui(QueueMixin): return self._windows[self._window_idx] def _switch_window(self, idx: int) -> None: + self.window.taint() self._window_idx = idx - self.window.tainted = True @property def _commands(self) -> dict[str, tuple[Callable[..., None | Optional[str]],