From: Christian Heller Date: Thu, 10 Jul 2025 11:32:32 +0000 (+0200) Subject: More prompt management refactoring. X-Git-Url: https://plomlompom.com/repos/day_todos?a=commitdiff_plain;h=HEAD;p=ircplom More prompt management refactoring. --- diff --git a/ircplom/irc_conn.py b/ircplom/irc_conn.py index a9c6c39..30dcaa8 100644 --- a/ircplom/irc_conn.py +++ b/ircplom/irc_conn.py @@ -1,5 +1,6 @@ 'IRC server connection management.' # built-ins +from dataclasses import dataclass from socket import socket, gaierror as socket_gaierror from threading import Thread from typing import Callable, Iterator, NamedTuple, Optional, Self @@ -22,11 +23,13 @@ _IRCSPEC_TAG_ESCAPES = ((r'\:', ';'), (r'\\', '\\')) -class LoginNames(NamedTuple): +@dataclass +class LoginNames: 'Collects the names needed on server connect for USER, NICK commands.' user: str nick: str real: str + nick_confirmed: bool = False class InitConnectEvent(Event, PayloadMixin): @@ -43,16 +46,15 @@ class ConnEvent(Event): class InitConnWindowEvent(ConnEvent, PayloadMixin): - 'Event to trigger TUI making ConnectionWindow, nick in prompt = payload.' - payload: str + 'Event to trigger TUI making ConnectionWindow.' + payload: LoginNames -class _ConnectedEvent(ConnEvent, PayloadMixin): - 'Event to signal opening of connection, with payload login names to send.' - payload: LoginNames +class _ConnectedEvent(ConnEvent): + 'Event to signal opening of connection.' -class DisconnectedEvent(ConnEvent): +class _DisconnectedEvent(ConnEvent): 'Event to signal closing of connection' @@ -65,9 +67,8 @@ class LogConnEvent(ConnEvent, PayloadMixin): payload: str -class NickSetEvent(ConnEvent, PayloadMixin): - 'Event to signal nickname (= payload) having been set server-side.' - payload: str +class NickSetEvent(ConnEvent): + 'Event to signal nickname having been set server-side.' class SendEvent(ConnEvent, PayloadMixin): @@ -105,7 +106,7 @@ class IrcConnection(BroadcastConnMixin): self._socket: Optional[socket] = None self._assumed_open = False self._loop: Optional[_ConnectionLoop] = None - self.broadcast_conn(InitConnWindowEvent, self._login.nick) + self.broadcast_conn(InitConnWindowEvent, self._login) self._start_connecting() def _start_connecting(self) -> None: @@ -124,14 +125,22 @@ class IrcConnection(BroadcastConnMixin): self._assumed_open = True self._loop = _ConnectionLoop(conn_idx=self.conn_idx, q_to_main=self._q_to_main, - bonus_iterator=self._read_lines()) - self.broadcast_conn(_ConnectedEvent, self._login) + bonus_iterator=self._read_lines(), + login=self._login, + set_login=self._set_login) + self.broadcast_conn(_ConnectedEvent) Thread(target=connect, daemon=True, args=(self,)).start() + def _set_login(self, **kwargs) -> None: + for key, val in kwargs.items(): + setattr(self._login, key, val) + self.broadcast_conn(NickSetEvent) + def close(self) -> None: 'Close both _ConnectionLoop and socket.' self._assumed_open = False + self._set_login(nick_confirmed=False) if self._loop: self._loop.stop() self._loop = None @@ -191,7 +200,7 @@ class IrcConnection(BroadcastConnMixin): elif isinstance(event, _ConnectedEvent): assert self._loop is not None self._loop.put(event) - elif isinstance(event, DisconnectedEvent): + elif isinstance(event, _DisconnectedEvent): self.close() elif isinstance(event, SendEvent): self.broadcast_conn(LogConnEvent, f'->: {event.payload.raw}') @@ -301,6 +310,12 @@ class IrcMessage: class _ConnectionLoop(Loop, BroadcastConnMixin): 'Loop receiving and translating socket messages towards main loop.' + def __init__(self, login: LoginNames, set_login: Callable, **kwargs + ) -> None: + super().__init__(**kwargs) + self._login = login + self._set_login = set_login + def _send(self, verb: str, parameters: tuple[str, ...]) -> None: self.broadcast_conn(SendEvent, IrcMessage(verb, parameters)) @@ -309,9 +324,8 @@ class _ConnectionLoop(Loop, BroadcastConnMixin): return False if isinstance(event, _ConnectedEvent): # self._send('CAP', ('LS', '302')) - self._send('USER', (event.payload.user, '0', '*', - event.payload.real)) - self._send('NICK', (event.payload.nick,)) + self._send('USER', (self._login.user, '0', '*', self._login.real)) + self._send('NICK', (self._login.nick,)) # self._send('CAP', ('LIST',)) # self._send('CAP', ('END',)) return True @@ -323,6 +337,6 @@ class _ConnectionLoop(Loop, BroadcastConnMixin): self._send('PONG', (msg.parameters[0],)) elif msg.verb == 'ERROR'\ and msg.parameters[0].startswith('Closing link:'): - self.broadcast_conn(DisconnectedEvent) + self.broadcast_conn(_DisconnectedEvent) elif msg.verb in {'001', 'NICK'}: - self.broadcast_conn(NickSetEvent, msg.parameters[0]) + self._set_login(nick=msg.parameters[0], nick_confirmed=True) diff --git a/ircplom/tui.py b/ircplom/tui.py index c5e7491..fa2fcc7 100644 --- a/ircplom/tui.py +++ b/ircplom/tui.py @@ -13,9 +13,9 @@ from blessed import Terminal as BlessedTerminal from ircplom.events import (BroadcastMixin, Event, EventQueue, Loop, PayloadMixin, QuitEvent) from ircplom.irc_conn import ( - BroadcastConnMixin, ConnEvent, DisconnectedEvent, InitConnectEvent, - InitConnWindowEvent, InitReconnectEvent, IrcMessage, LoginNames, - LogConnEvent, NickSetEvent, SendEvent, TIMEOUT_LOOP) + BroadcastConnMixin, ConnEvent, InitConnectEvent, InitConnWindowEvent, + InitReconnectEvent, IrcMessage, LoginNames, LogConnEvent, NickSetEvent, + SendEvent, TIMEOUT_LOOP) _MIN_HEIGHT = 4 _MIN_WIDTH = 32 @@ -312,25 +312,14 @@ class _PromptWidget(_ScrollableWidget): class _ConnectionPromptWidget(_PromptWidget): 'PromptWidget with attributes, methods for dealing with an IrcConnection.' - _nick: str = '' - _nick_confirmed: bool = False + login: LoginNames @property def _prompt(self) -> str: - return ((' ' if self._nick_confirmed else '?') - + self._nick + return ((' ' if self.login.nick_confirmed else '?') + + self.login.nick + super()._prompt) - def update_prompt(self, - nick_confirmed=False, - nick: Optional[str] = None - ) -> None: - 'Update nickname-relevant knowledge to go into prompt string.' - self.tainted = True - self._nick_confirmed = nick_confirmed - if nick: - self._nick = nick - class _Window(_Widget): 'Collects a log and a prompt meant for the same content stream.' @@ -398,6 +387,10 @@ class _ConnectionWindow(_Window, BroadcastConnMixin): 'Window with attributes and methods for dealing with an IrcConnection.' prompt: _ConnectionPromptWidget + def __init__(self, login: LoginNames, **kwargs) -> None: + super().__init__(**kwargs) + self.prompt.login = login + def cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None: 'Send QUIT command to server.' self.broadcast_conn(SendEvent, IrcMessage('QUIT', (quit_msg, ))) @@ -483,9 +476,8 @@ class _TuiLoop(Loop, BroadcastMixin): conn_win = _ConnectionWindow(q_to_main=self._q_to_main, conn_idx=event.conn_idx, idx=len(self._windows), - term=self._term) - conn_win.prompt.update_prompt(nick_confirmed=False, - nick=event.payload) + term=self._term, + login=event.payload) self._windows += [conn_win] self._conn_windows += [conn_win] self._switch_window(conn_win.idx) @@ -494,10 +486,7 @@ class _TuiLoop(Loop, BroadcastMixin): if isinstance(event, LogConnEvent): conn_win.log.append(event.payload) elif isinstance(event, NickSetEvent): - conn_win.prompt.update_prompt(nick_confirmed=True, - nick=event.payload) - elif isinstance(event, DisconnectedEvent): - conn_win.prompt.update_prompt(nick_confirmed=False) + conn_win.prompt.tainted = True else: return True self.window.draw_tainted()