home · contact · privacy
Provide for sub-windows per connection client. master
authorChristian Heller <c.heller@plomlompom.de>
Fri, 25 Jul 2025 02:12:40 +0000 (04:12 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Fri, 25 Jul 2025 02:12:40 +0000 (04:12 +0200)
ircplom/irc_conn.py
ircplom/tui.py

index af7cff4160eb394b5557082003cf8d1ad9acfcb9..192c0965a1bbf6035a8cb43e212a207706179363 100644 (file)
@@ -221,7 +221,7 @@ class Client(ABC, ClientQueueMixin):
         Thread(target=connect, daemon=True, args=(self,)).start()
 
     @abstractmethod
         Thread(target=connect, daemon=True, args=(self,)).start()
 
     @abstractmethod
-    def log(self, msg: str) -> None:
+    def log(self, msg: str, chat: str = '') -> None:
         'Write msg into log, whatever shape that may have.'
 
     def send(self, msg: IrcMessage) -> None:
         'Write msg into log, whatever shape that may have.'
 
     def send(self, msg: IrcMessage) -> None:
@@ -293,3 +293,5 @@ class _RecvEvent(ClientEvent, PayloadMixin):
             target.close()
         elif msg.verb in {'001', 'NICK'}:
             target.update_login(nickname=msg.params[0], nick_confirmed=True)
             target.close()
         elif msg.verb in {'001', 'NICK'}:
             target.update_login(nickname=msg.params[0], nick_confirmed=True)
+        elif msg.verb == 'PRIVMSG':
+            target.log(msg=str(msg.params), chat=msg.source)
index fe5df12c9bbfbdce2ceceb6c9533ad64c77522c3..49c6acb106ff99f529506acae690e283e221a787 100644 (file)
@@ -430,6 +430,31 @@ class Tui(QueueMixin):
         'Currently selected _Window.'
         return self.windows[self._window_idx]
 
         'Currently selected _Window.'
         return self.windows[self._window_idx]
 
+    def client_wins(self, client_id: UUID) -> list['_ClientWindow']:
+        'All _ClientWindows matching client_id.'
+        return [win for win in self.windows
+                if isinstance(win, _ClientWindow)
+                and win.client_id == client_id]  # pylint: disable=no-member
+
+    def client_win(self, client_id: UUID, chat: str = '') -> '_ClientWindow':
+        '''That _ClientWindow matching client_id and chat; create if none.
+
+        In case of creation, also switch to window, and if not client's first
+        window, copy prompt prefix from client's first window.
+        '''
+        client_wins = self.client_wins(client_id)
+        candidates = [win for win in client_wins if win.chat == chat]
+        if candidates:
+            return candidates[0]
+        new_idx = len(self.windows)
+        win = _ClientWindow(idx=new_idx, term=self.term, q_out=self._q_out,
+                            client_id=client_id, chat=chat)
+        if client_wins:
+            win.prompt.prefix = client_wins[0].prompt.prefix
+        self.windows += [win]
+        self._switch_window(new_idx)
+        return win
+
     def log(self, msg: str) -> None:
         'Post msg to active window\'s log.'
         self.window.log.append(msg)
     def log(self, msg: str) -> None:
         'Post msg to active window\'s log.'
         self.window.log.append(msg)
@@ -441,14 +466,9 @@ class Tui(QueueMixin):
     def cmd__connect(self, hostname: str, nickname: str, realname: str
                      ) -> None:
         'Create Client and pass it via NewClientEvent.'
     def cmd__connect(self, hostname: str, nickname: str, realname: str
                      ) -> None:
         'Create Client and pass it via NewClientEvent.'
-        client = _ClientKnowingTui(q_out=self._q_out, hostname=hostname,
-                                   nickname=nickname, realname=realname)
-        new_idx = len(self.windows)
-        self.windows += [_ClientWindow(idx=new_idx, term=self.term,
-                                       q_out=self._q_out,
-                                       client_id=client.id_)]
-        self._switch_window(new_idx)
-        self._put(NewClientEvent(client))
+        self._put(NewClientEvent(
+            _ClientKnowingTui(q_out=self._q_out, hostname=hostname,
+                              nickname=nickname, realname=realname)))
 
     def cmd__prompt_enter(self) -> None:
         'Get prompt content from .window.prompt.enter, parse to & run command.'
 
     def cmd__prompt_enter(self) -> None:
         'Get prompt content from .window.prompt.enter, parse to & run command.'
@@ -609,8 +629,9 @@ class Terminal(QueueMixin):
 class _ClientWindow(_Window, ClientQueueMixin):
     client_id_name = 'client_id'
 
 class _ClientWindow(_Window, ClientQueueMixin):
     client_id_name = 'client_id'
 
-    def __init__(self, client_id: UUID, **kwargs) -> None:
+    def __init__(self, client_id: UUID, chat: str = '', **kwargs) -> None:
         self.client_id = client_id
         self.client_id = client_id
+        self.chat = chat
         super().__init__(**kwargs)
 
     def cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None:
         super().__init__(**kwargs)
 
     def cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None:
@@ -630,18 +651,16 @@ class _ClientWindow(_Window, ClientQueueMixin):
 
 class _ClientWindowEvent(TuiEvent, ClientIdMixin):
 
 
 class _ClientWindowEvent(TuiEvent, ClientIdMixin):
 
-    def client_win(self, target: Tui) -> _ClientWindow:
-        'Identifies proper _ClientWindow in target TUI.'
-        return [win for win in target.windows
-                if isinstance(win, _ClientWindow)
-                and win.client_id == self.client_id][0]
+    def __init__(self, chat: str = '', **kwargs) -> None:
+        self.chat = chat
+        super().__init__(**kwargs)
 
 
 class _ClientLogEvent(_ClientWindowEvent, PayloadMixin):
     payload: str
 
     def affect(self, target: Tui) -> None:
 
 
 class _ClientLogEvent(_ClientWindowEvent, PayloadMixin):
     payload: str
 
     def affect(self, target: Tui) -> None:
-        self.client_win(target).log.append(self.payload)
+        target.client_win(self.client_id, self.chat).log.append(self.payload)
         super().affect(target)
 
 
         super().affect(target)
 
 
@@ -649,17 +668,19 @@ class _ClientPromptEvent(_ClientWindowEvent, PayloadMixin):
     payload: tuple[str, str]
 
     def affect(self, target: Tui) -> None:
     payload: tuple[str, str]
 
     def affect(self, target: Tui) -> None:
-        prompt = self.client_win(target).prompt
-        prompt.prefix = ((' ' if self.payload[0] else '?')
-                         + f'{self.payload[1]}{_PROMPT_TEMPLATE}')
-        prompt.tainted = True
+        new_prefix = ((' ' if self.payload[0] else '?')
+                      + f'{self.payload[1]}{_PROMPT_TEMPLATE}')
+        for win in target.client_wins(self.client_id):
+            prompt = win.prompt
+            prompt.prefix = new_prefix
+            prompt.tainted = True
         super().affect(target)
 
 
 class _ClientKnowingTui(Client):
 
         super().affect(target)
 
 
 class _ClientKnowingTui(Client):
 
-    def log(self, msg: str) -> None:
-        self._cput(_ClientLogEvent, payload=msg)
+    def log(self, msg: str, chat: str = '') -> None:
+        self._cput(_ClientLogEvent, chat=chat, payload=msg)
 
     def update_login(self, nick_confirmed: bool, nickname: str = '') -> None:
         super().update_login(nick_confirmed, nickname)
 
     def update_login(self, nick_confirmed: bool, nickname: str = '') -> None:
         super().update_login(nick_confirmed, nickname)