From 9d1211a262a13371ebe89e7cae024604655a0526 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Thu, 11 Sep 2025 16:23:40 +0200 Subject: [PATCH] Split set_and_check_for_change into recursive node-walk end end-node processing. --- ircplom/client_tui.py | 66 +++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/ircplom/client_tui.py b/ircplom/client_tui.py index 7a5a092..d1f026d 100644 --- a/ircplom/client_tui.py +++ b/ircplom/client_tui.py @@ -45,24 +45,28 @@ class _UpdatingNode(AutoAttrMixin): scopes = c.log_scopes | scopes return scopes.get(path, scopes['']) - def set_and_check_for_change(self, update: _Update - ) -> Optional[tuple[LogScope, Any]]: + def recursive_set_and_report_change( + self, update: _Update) -> Optional[tuple[LogScope, Any]]: 'Apply update, return if that actually made a difference.' - key = update.path[0] - node = self._get(key) - scope = self._scope(key) - if len(update.path) == 1: - if update.value is None: - if not self._is_set(key): - return None - self._unset(key) - return (scope, None) - if node == update.value: + node = self._get(update.path[0]) + if len(update.path) > 1: + return node.recursive_set_and_report_change( + _Update(update.path[1:], update.value)) + return self._focused_set_and_report_change(node, update) + + def _focused_set_and_report_change( + self, old_value: '_UpdatingNode', update: _Update + ) -> Optional[tuple[LogScope, Any]]: + scope = self._scope(update.path[0]) + if update.value is None: + if not self._is_set(update.path[0]): return None - self._set(key, update.value) - return (scope, update.value) - return node.set_and_check_for_change(_Update(update.path[1:], - update.value)) + self._unset(update.path[0]) + return (scope, None) + if old_value == update.value: + return None + self._set(update.path[0], update.value) + return (scope, update.value) def _get(self, key: str): return getattr(self, key) @@ -200,20 +204,21 @@ class _UpdatingChannel(_UpdatingNode): topic: Topic = Topic() log_scopes = {'': LogScope.CHAT} - def set_and_check_for_change(self, update: _Update - ) -> Optional[tuple[LogScope, Any]]: + def _focused_set_and_report_change( + self, old_value: '_UpdatingNode', update: _Update + ) -> Optional[tuple[LogScope, Any]]: scope = self._scope(update.path[0]) - if update.path[-1] == 'topic': - if super().set_and_check_for_change(update): + if update.path[0] == 'topic': + if super()._focused_set_and_report_change(old_value, update): return (scope, f'RAW:{self.topic.who} set topic: {self.topic.what}') return None - assert update.path[-1] == 'user_ids' + assert update.path[0] == 'user_ids' assert isinstance(update.value, tuple) d = {'NUHS:joining': tuple(id_ for id_ in update.value if id_ not in self.user_ids) } if self.user_ids else {'NICKS:residents': tuple(update.value)} - if super().set_and_check_for_change(update): + if super()._focused_set_and_report_change(old_value, update): return scope, d return None @@ -224,17 +229,18 @@ class _UpdatingUser(_UpdatingNode, NickUserHost): modes = '?' exit_msg = '' - def set_and_check_for_change(self, update: _Update - ) -> Optional[tuple[LogScope, Any]]: + def _focused_set_and_report_change( + self, old_value: '_UpdatingNode', update: _Update + ) -> Optional[tuple[LogScope, Any]]: assert isinstance(update.value, str) - if update.path[-1] == 'modes': - return super().set_and_check_for_change(update) - if super().set_and_check_for_change(update): + if update.path[0] == 'modes': + return super()._focused_set_and_report_change(old_value, update) + if super()._focused_set_and_report_change(old_value, update): scope = self._scope(update.path[0]) msg = 'RAW: ' - if update.path[-1] == 'nick': + if update.path[0] == 'nick': return scope, msg + f'{self.prev} renames {update.value}' - if update.path[-1] == 'exit_msg' and update.value: + if update.path[0] == 'exit_msg' and update.value: msg += f'{self}' msg += 'quits' if update.value[0] == 'Q' else 'parts' if len(update.value) > 1: @@ -339,7 +345,7 @@ class _ClientWindowsManager: if isinstance(update.value, get_original_bases(cls)[1])]: update.value = cls(**dc_asdict(update.value)) # type: ignore break - result = self.db.set_and_check_for_change(update) + result = self.db.recursive_set_and_report_change(update) if result is None: return False scope, value = result -- 2.30.2