home · contact · privacy
Turn server messages into own special window, rather than query chat.
authorChristian Heller <c.heller@plomlompom.de>
Sun, 5 Oct 2025 12:05:48 +0000 (14:05 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 5 Oct 2025 12:05:48 +0000 (14:05 +0200)
src/ircplom/client_tui.py
src/ircplom/msg_parse_expectations.py
src/tests/pingpong.test
src/tests/test.test

index 00ec46fb378005ac54d5300574f4c546354c8358..7b5135040017fd7f5af7aa3318180884704ba17b 100644 (file)
@@ -40,16 +40,17 @@ class _LogScope(Enum):
     CHAT = auto()
     USER = auto()
     USER_NO_CHANNELS = auto()
+    SERVER = auto()
 
 
 class _ClientWindow(Window, ClientQueueMixin):
     _title_separator = ':'
     _logpath_prefix = '!'
+    _title: str
 
     def __init__(self, path_logs: Optional[Path], **kwargs) -> None:
         self._path_logs = path_logs
         super().__init__(**kwargs)
-        self._title = 'DEBUG'
 
     @property
     def title(self) -> str:
@@ -112,6 +113,16 @@ class _ClientWindow(Window, ClientQueueMixin):
         self._send_msg(verb, tuple(params))
 
 
+class _DebugWindow(_ClientWindow):
+    prompt: PromptWidget
+    _title = 'debug'
+
+
+class _ServerWindow(_ClientWindow):
+    prompt: PromptWidget
+    _title = 'server'
+
+
 class _ChatPrompt(PromptWidget):
     _nickname: str = ''
 
@@ -137,12 +148,12 @@ class _ChatWindow(_ClientWindow):
     _title_separator = '/'
     _logpath_prefix = ''
 
-    def __init__(self, chatname: str, get_nick_data: Callable, **kwargs
+    def __init__(self, title: str, get_nick_data: Callable, **kwargs
                  ) -> None:
+        self._title = title
         self._get_nick_data = get_nick_data
-        self.chatname = chatname
         super().__init__(**kwargs)
-        self._title = chatname
+        self.chatname = self._title
         self.set_prompt_prefix()
 
     def set_prompt_prefix(self) -> None:
@@ -344,12 +355,14 @@ class _TuiClientDb(_UpdatingNode, SharedClientDbFields):
                 update.results += [(_LogScope.ALL, [':DISCONNECTED'])]
         elif update.key == 'message' and update.value:
             assert isinstance(update.value, ChatMessage)
+            is_server_msg = not (update.value.sender or update.value.target)
             toks = [':*** '] if update.value.is_notice else []
             toks += [':[']
             toks += [f':{update.value.sender}' if update.value.sender
-                     else 'NICK:me']
+                     else (':server' if is_server_msg else 'NICK:me')]
             toks += [f':] {update.value.content}']
-            update.results += [(_LogScope.CHAT, toks)]
+            update.results += [
+                (_LogScope.SERVER if is_server_msg else _LogScope.CHAT, toks)]
 
 
 class _ClientWindowsManager:
@@ -367,18 +380,18 @@ class _ClientWindowsManager:
         self.db = _TuiClientDb()
         self.windows: list[_ClientWindow] = []
 
-    def _new_win(self, scope: _LogScope, chatname: str = '') -> _ClientWindow:
+    def _new_win(self, scope: _LogScope, title: str = '') -> _ClientWindow:
         if scope == _LogScope.CHAT:
             win = self._tui_new_window(
-                    chatname=chatname, path_logs=self._path_logs,
-                    win_cls=(_ChannelWindow if self.db.is_chan_name(chatname)
+                    title=title, path_logs=self._path_logs,
+                    win_cls=(_ChannelWindow if self.db.is_chan_name(title)
                              else _QueryWindow),
                     get_nick_data=lambda: (self.db.users['me'].nick
                                            if 'me' in self.db.users.keys()
                                            else '?'))
         else:
-            win = self._tui_new_window(win_cls=_ClientWindow,
-                                       path_logs=self._path_logs)
+            win = self._tui_new_window(path_logs=self._path_logs, win_cls=(
+                _ServerWindow if scope == _LogScope.SERVER else _DebugWindow))
         self.windows += [win]
         return win
 
@@ -388,8 +401,10 @@ class _ClientWindowsManager:
         if scope == _LogScope.ALL:
             ret = [w for w in self.windows
                    if w not in self.windows_for(_LogScope.DEBUG)]
+        elif scope == _LogScope.SERVER:
+            ret = [w for w in self.windows if isinstance(w, _ServerWindow)]
         elif scope == _LogScope.DEBUG:
-            ret = [w for w in self.windows if not isinstance(w, _ChatWindow)]
+            ret = [w for w in self.windows if isinstance(w, _DebugWindow)]
         elif scope == _LogScope.CHAT:
             ret = [w for w in self.windows
                    if isinstance(w, _ChatWindow) and w.chatname == id_]
@@ -406,7 +421,8 @@ class _ClientWindowsManager:
         elif scope == _LogScope.USER_NO_CHANNELS:
             ret = [w for w in self.windows_for(_LogScope.USER, id_)
                    if isinstance(w, _QueryWindow)]
-        if (not ret) and scope in {_LogScope.CHAT, _LogScope.DEBUG}:
+        if (not ret) and scope in {_LogScope.CHAT,
+                                   _LogScope.SERVER, _LogScope.DEBUG}:
             ret += [self._new_win(scope, id_)]
         ret.sort(key=lambda w: w.idx)
         return ret
@@ -446,7 +462,8 @@ class _ClientWindowsManager:
             target = ''
             if update.full_path == ('message',):
                 target = update.value.target or update.value.sender
-                out = not bool(update.value.sender)
+                out = not bool(update.value.sender
+                               or scope == _LogScope.SERVER)
             elif scope in {_LogScope.CHAT, _LogScope.USER,
                            _LogScope.USER_NO_CHANNELS}:
                 target = update.full_path[1]
index 158154f8bf10467f343002770136f4cdf2fb2a8c..64c69d80cd496a4720a6a4f4f01e697483388b73 100644 (file)
@@ -498,12 +498,12 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [
         'NOTICE',
         _MsgTok.SERVER,
         ('*',
-         (_MsgTok.ANY, 'setattr_db.messaging. server.to.:notice'))),
+         (_MsgTok.ANY, 'setattr_db.messaging..to.:notice'))),
     _MsgParseExpectation(
         'NOTICE',
         _MsgTok.SERVER,
         ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
-         (_MsgTok.ANY, 'setattr_db.messaging. server.to.:notice'))),
+         (_MsgTok.ANY, 'setattr_db.messaging..to.:notice'))),
 
     _MsgParseExpectation(
         'NOTICE',
index 291680f8eccb22df2b15a97376ccdbd390d07867..065ec78ede56439240ffc607f0ffae5a1364f580 100644 (file)
@@ -39,7 +39,7 @@
 | trigger-ping-out
 :0:1 ..< :*.?.net PONG *.?.net :what's up?
 :0:1 ..< :*.?.net NOTICE * :*** Looking up your ident...
-2 ..< *** [ server] *** Looking up your ident...
+2 ..< *** [server] *** Looking up your ident...
 
 # another timeout instead of pong? disconnect
 repeat trigger-ping-in trigger-ping-out
index 4bff1a7e47ecafbb90d9540533742dfb312d0880..c5b371ba65ba5295457b1d56f21a092bcd192a73 100644 (file)
 
 # expect some NOTICE and PING to process/reply during initiation
 :0:1 ..< :*.?.net NOTICE * :*** Looking up your ident...
-2 ..< *** [ server] *** Looking up your ident...
+2 ..< *** [server] *** Looking up your ident...
 :0:1 ..< :*.?.net NOTICE * :*** Looking up your hostname...
-2 ..< *** [ server] *** Looking up your hostname...
+2 ..< *** [server] *** Looking up your hostname...
 :0:1 ..< :*.?.net NOTICE * :*** Found your hostname (foo.bar.baz)
-2 ..< *** [ server] *** Found your hostname (foo.bar.baz)
+2 ..< *** [server] *** Found your hostname (foo.bar.baz)
 :0:1 ..< PING :?
 1 ..> PONG :?
 
 > /list
 0 ..# windows available via /window:
 0 ..#   0) :start
-0 ..#   1) foo.bar.baz:DEBUG
-0 ..#   2) foo.bar.bazserver
+0 ..#   1) foo.bar.baz:debug
+0 ..#   2) foo.bar.baz:server
 0 ..#   3) foo.bar.baz/SaslServ
 | conn5
 > /window 1
 1 ..> QUIT :ircplom says bye
 :0:1 ..< :foo1!~foobarbaz@baz.bar.foo QUIT :Client Quit
 1 ..$ users:me:exit_msg set to: [QClient Quit]
-2,3,6,7 ..$ foo1!~foobarbaz@baz.bar.foo quits: Client Quit
+3,6,7 ..$ foo1!~foobarbaz@baz.bar.foo quits: Client Quit
 1 ..$ channels:#testtest:exits:me set to: [QClient Quit]
 1 ..$ channels:#testtest:user_ids set to:
 5 ..$ foo1!~foobarbaz@baz.bar.foo quits: Client Quit