From: Christian Heller Date: Wed, 6 Aug 2025 21:52:33 +0000 (+0200) Subject: Add _ClientWindowsManager for better control of Client-TUI relations. X-Git-Url: https://plomlompom.com/repos/booking/%7B%7B%20web_path%20%7D%7D/decks/static/blog?a=commitdiff_plain;h=0e49c1e8627471efb9e68145268bac5a0a52e543;p=ircplom Add _ClientWindowsManager for better control of Client-TUI relations. --- diff --git a/ircplom/client_tui.py b/ircplom/client_tui.py index 6a48a1e..5b7feda 100644 --- a/ircplom/client_tui.py +++ b/ircplom/client_tui.py @@ -1,7 +1,8 @@ 'TUI adaptions to Client.' # built-ins from getpass import getuser -from typing import Any, Optional +from inspect import signature +from typing import Callable, Optional # ourselves from ircplom.tui_base import (BaseTui, PromptWidget, TuiEvent, Window, CMD_SHORTCUTS) @@ -76,69 +77,77 @@ class _PrivmsgWindow(_ClientWindow): self.cmd__privmsg(self.stream, msg) -class ClientTui(BaseTui): - 'TUI expanded towards Client features.' +class _ClientWindowsManager: + nick_confirmed: bool = False + nickname: str = '?' + windows: list[_ClientWindow] = [] - def __init__(self, **kwargs) -> None: - super().__init__(**kwargs) - self._clients_data: dict[str, dict[str, Any]] = {} + def __init__(self, new_window: Callable) -> None: + self._tui_new_window = new_window + self.windows += [self._new_window(stream) + for stream in (STREAM_SERVER, STREAM_RAW)] - def _new_client_window(self, client_id: str, stream: str) -> _ClientWindow: - new_idx = len(self._windows) + def _new_window(self, stream: str) -> _ClientWindow: win_class = (_PrivmsgWindow if stream[0:1] != STREAM_PREFIX_META else _ClientWindow) - win = win_class(idx=new_idx, term=self._term, _q_out=self._q_out, - client_id=client_id, stream=stream) + win = self._tui_new_window(win_class, stream=stream) if isinstance(win, _PrivmsgWindow): - win.prompt.update_prefix(**{k: self._clients_data[client_id][k] - for k in _PROMPT_UPDATE_TRIGGER_KEYS}) - self._windows += [win] - self._switch_window(new_idx) + win.prompt.update_prefix( + **{k: getattr(self, k) for k in _PROMPT_UPDATE_TRIGGER_KEYS}) + self.windows += [win] return win - @property - def _all_client_wins(self) -> list[_ClientWindow]: - return [win for win in self._windows if isinstance(win, _ClientWindow)] - - def client_wins(self, client_id: str = '') -> list[_ClientWindow]: - 'All _ClientWindows matching client_id; if none, create basics.' - wins = [w for w in self._all_client_wins if client_id == w.client_id] - if not wins: - for stream in (STREAM_SERVER, STREAM_RAW): - wins += [self._new_client_window(client_id, stream)] - return wins - - def client_win(self, client_id: str, stream: str) -> _ClientWindow: - 'That _ClientWindow matching client_id and stream; if none, create.' - client_wins = self.client_wins(client_id) - candidates = [win for win in client_wins if win.stream == stream] - if candidates: - return candidates[0] - win = self._new_client_window(client_id=client_id, stream=stream) - return win + def window(self, stream: str) -> _ClientWindow: + 'Return client window of stream.' + for win in [w for w in self.windows if w.stream == stream]: + return win + return self._new_window(stream) - def log_for_client(self, client_id: str, stream: str, msg: str) -> None: - 'To stream of client_id, log msg.' + def log(self, msg: str, stream: str) -> None: + 'Log msg to stram.' if stream == STREAM_GLOB: - for win in self.client_wins(client_id): + for win in self.windows: win.log.append(msg) else: - self.client_win(client_id, stream).log.append(msg) - self.redraw_affected() - - def update_client_data(self, client_id: str, **kwargs) -> None: - 'Apply kwargs settings to client data, update representation.' - if client_id not in self._clients_data: - self._clients_data[client_id] = {} - clients_data = self._clients_data[client_id] + self.window(stream).log.append(msg) + + def update(self, **kwargs) -> bool: + 'Apply settings in kwargs, follow represntation update triggres.' for k, v in kwargs.items(): - clients_data[k] = v + setattr(self, k, v) if _PROMPT_UPDATE_TRIGGER_KEYS & set(kwargs.keys()): - for prompt in [w.prompt for w in self.client_wins(client_id) + for prompt in [w.prompt for w in self.windows if isinstance(w.prompt, _PrivmsgPromptWidget)]: - assert isinstance(prompt, _PrivmsgPromptWidget) - prompt.update_prefix(**{k: clients_data[k] + prompt.update_prefix(**{k: getattr(self, k) for k in _PROMPT_UPDATE_TRIGGER_KEYS}) + return True + return False + + +class ClientTui(BaseTui): + 'TUI expanded towards Client features.' + + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) + self._client_mngrs: dict[str, _ClientWindowsManager] = {} + + def _new_window(self, win_class, **kwargs) -> Window: + new_idx = len(self._windows) + win = win_class(idx=new_idx, term=self._term, _q_out=self._q_out, + **kwargs) + self._windows += [win] + self._switch_window(new_idx) + return win + + def for_client_do(self, client_id: str, todo: str, **kwargs) -> None: + 'Forward todo to appropriate ClientTuiMgr.' + if client_id not in self._client_mngrs: + self._client_mngrs[client_id] = _ClientWindowsManager( + new_window=lambda cls, **kwargs: self._new_window( + cls, client_id=client_id, **kwargs)) + client_data = self._client_mngrs[client_id] + method = getattr(client_data, todo) + if method(**kwargs) or signature(method).return_annotation is None: self.redraw_affected() def cmd__connect(self, @@ -149,7 +158,7 @@ class ClientTui(BaseTui): 'Create Client and pass it via NewClientEvent.' split = host_port.split(':', maxsplit=1) hostname = split[0] - if hostname in self._clients_data: + if hostname in self._client_mngrs: return f'already set up connection to {hostname}' port = -1 if len(split) > 1: @@ -178,9 +187,10 @@ class _ClientKnowingTui(Client): ).kw(**kwargs)) def _log(self, msg: str, stream: str = STREAM_SERVER) -> None: - self._ctput('log_for_client', stream=stream, msg=msg) + self._ctput('for_client_do', todo='log', stream=stream, msg=msg) def update_login(self, nick_confirmed: bool, nickname: str = '') -> None: super().update_login(nick_confirmed, nickname) - self._ctput('update_client_data', nick_confirmed=self.nick_confirmed, + self._ctput('for_client_do', todo='update', + nick_confirmed=self.nick_confirmed, nickname=self.conn_setup.nickname)