}
CMD_SHORTCUTS: dict[str, str] = {}
+_UNSET_IDX_NEG = 0
+_UNSET_IDX_POS = -1
+
+
+class _YX(NamedTuple):
+ y: int
+ x: int
+
+
+_SIZE_UNSET = _YX(_UNSET_IDX_POS, _UNSET_IDX_POS)
+
class FormattingString:
'For inserting terminal formatting directives, and escaping their syntax.'
return tuple(self.__class__(text, raw=True) for text in wrapped_lines)
-class _YX(NamedTuple):
- y: int
- x: int
-
-
-_SIZE_UNSET = _YX(-1, -1)
-
-
class _Widget(ABC):
_size = _SIZE_UNSET
self._maxlen_log = maxlen_log
self._len_to_term = len_to_term
self._wrapped: list[_WrappedHistoryLine] = []
- self._lowest_read_history_idx_pos = self._UNSET_IDX_POS
- self._bookmark_idx_neg = self._UNSET_IDX_NEG
+ self._lowest_read_history_idx_pos = _UNSET_IDX_POS
+ self._bookmark_idx_neg = _UNSET_IDX_NEG
self._history_n_lines_cut = 0
- self._history_idx_neg = self._UNSET_IDX_NEG
+ self._history_idx_neg = _UNSET_IDX_NEG
def _add_wrapped_from_offset_history(self,
history_idx_pos: int,
def set_geometry(self, size: _YX) -> None:
super().set_geometry(size)
+ keep_bookmark_at = (
+ _UNSET_IDX_POS
+ if (self._bookmark_idx_neg == _UNSET_IDX_NEG
+ or len(self._wrapped) - 1 < -self._bookmark_idx_neg)
+ else (self._wrapped[self._bookmark_idx_neg - 1].history_idx_pos
+ if self._bookmark_idx_neg != self._BOTTOM_IDX_NEG
+ else (self._len_full_history - 1)))
self._unbookmark()
if self._drawable:
self._y_pgscroll = self._size.y // 2
# ensure that of the full line identified by ._history_idx_neg,
# ._wrapped_idx_neg point to the lowest of its wrap parts
self._wrapped_idx_neg = (
- self._UNSET_IDX_NEG if (not self._wrapped)
+ _UNSET_IDX_NEG if not self._wrapped
else (self._wrapped_top_idx_neg
+ self._bottom_wrapped_for_history_idx_pos(
self._len_full_history + max(self._history_idx_neg,
- self._maxlen_log))))
- self.bookmark()
+ self.bookmark(keep_bookmark_at)
def append_fmt(self, to_append: FormattingString) -> None:
'Wrap .append around FormattingString, update history dependents.'
def start_unset_dec_non_bottom(attr_name: str, grow_by: int) -> None:
full_name = f'_{attr_name}_idx_neg'
cur_val = getattr(self, full_name)
- if cur_val == self._UNSET_IDX_NEG:
+ if cur_val == _UNSET_IDX_NEG:
setattr(self, full_name, self._BOTTOM_IDX_NEG)
elif cur_val < self._BOTTOM_IDX_NEG:
setattr(self, full_name, cur_val - grow_by)
= self._add_wrapped_from_offset_history(len(self._history) - 1,
to_append)
start_unset_dec_non_bottom('wrapped', grow_by=wrapped_growth)
- if self._bookmark_idx_neg != self._UNSET_IDX_NEG:
+ if self._bookmark_idx_neg != _UNSET_IDX_NEG:
self._bookmark_idx_neg -= wrapped_growth
if len(self._history) > self._maxlen_log:
self._history.pop(0)
visible_lines[-1].history_idx_pos)
def _unbookmark(self) -> None:
- if self._bookmark_idx_neg != self._UNSET_IDX_NEG\
+ if self._bookmark_idx_neg != _UNSET_IDX_NEG\
and len(self._wrapped) > -self._bookmark_idx_neg:
del self._wrapped[self._bookmark_idx_neg]
if self._bookmark_idx_neg > self._wrapped_idx_neg:
self._wrapped_idx_neg += 1
- self._bookmark_idx_neg = self._UNSET_IDX_NEG
+ self._bookmark_idx_neg = _UNSET_IDX_NEG
- def bookmark(self) -> None:
+ def bookmark(self, preceding_history_idx_pos=_UNSET_IDX_POS) -> None:
'Store next idx to what most recent line we have (been) scrolled.'
self._unbookmark()
- if self._lowest_read_history_idx_pos < self._history_n_lines_cut:
+ if preceding_history_idx_pos == _UNSET_IDX_POS:
+ preceding_history_idx_pos = self._lowest_read_history_idx_pos
+ if preceding_history_idx_pos < self._history_n_lines_cut:
return
if not self._wrapped:
return
lowest_read_wrapped_idx_neg\
= (self._wrapped_top_idx_neg
+ self._bottom_wrapped_for_history_idx_pos(
- self._lowest_read_history_idx_pos))
+ preceding_history_idx_pos))
if lowest_read_wrapped_idx_neg == self._BOTTOM_IDX_NEG:
self._bookmark_idx_neg = self._BOTTOM_IDX_NEG
self._wrapped += [bookmark]
insert ./lib/req-sasl
insert ./lib/retry-in
insert ./lib/servermsglogged
+# for: servermsglogged-core, servermsglogged
insert ./lib/servernotice
insert ./lib/user-set-to
× nick-increment
-insert servermsglogged : +0 MSG ::*.?.net 433 * NAME_A :Nickname already in use
+insert servermsglogged : + MSG ::*.?.net 433 * NAME_A :Nickname already in use
log 1 $ nickname already in use, trying increment
log 1 > NICK :NAME_B
× conn_init_1
# expect some NOTICE and PING to process/reply during initiation
-insert servernotice : +0 XXX :*** Looking up your ident...
-insert servernotice : +0 XXX :*** Looking up your hostname...
-insert servernotice : +0 XXX :*** Found your hostname (baz.bar.foo)
-insert ping-pong : +0
+insert servernotice : + XXX :*** Looking up your ident...
+insert servernotice : + XXX :*** Looking up your hostname...
+insert servernotice : + XXX :*** Found your hostname (baz.bar.foo)
+insert ping-pong
# handle 433
-insert nick-increment : +0 NAME_A=foo NAME_B :foo0
-insert nick-increment : +0 NAME_A=foo0 NAME_B :foo1
+insert nick-increment : + NAME_A=foo NAME_B :foo0
+insert nick-increment : + NAME_A=foo0 NAME_B :foo1
# collect server capabilities
-insert cap-msg : +0 CAPMSG :* LS : foo bar sasl=IGNORE baz cap-notify
+insert cap-msg : + CAPMSG :* LS : foo bar sasl=IGNORE baz cap-notify
log 1 $ caps:bar:data set to: []
log 1 $ caps:baz:data set to: []
log 1 $ caps:cap-notify:data set to: []
log 1 $ caps:foo:data set to: []
log 1 $ caps:sasl:data set to: [IGNORE]
-insert req-sasl : +0 foo=foo1 REPLY=ACK CAPLIST :cap-notify sasl
+insert req-sasl : + foo=foo1 REPLY=ACK CAPLIST :cap-notify sasl
log 1 $ caps:cap-notify:enabled set to: [True]
log 1 $ caps:sasl:enabled set to: [True]
× conn_init_2
# of all pre-MOTD greeting messages, only process isupports
-insert servermsglogged : +0 MSG ::foo.bar.baz 001 foo1 :Welcome to the foo.bar.baz network
-insert servermsglogged : +0 MSG ::foo.bar.baz 002 foo1 :Your host is foo.bar.baz
-insert servermsglogged : +0 MSG ::foo.bar.baz 003 foo1 :This server was created Jan 1 2020
-insert servermsglogged : +0 MSG ::foo.bar.baz 004 foo1 foo.bar.baz ircserver-1.0 abc def ghi
-insert servermsglogged : +0 MSG ::foo.bar.baz 005 foo1 ABC=DEF GHI :are supported by this server
+insert servermsglogged : + MSG ::foo.bar.baz 001 foo1 :Welcome to the foo.bar.baz network
+insert servermsglogged : + MSG ::foo.bar.baz 002 foo1 :Your host is foo.bar.baz
+insert servermsglogged : + MSG ::foo.bar.baz 003 foo1 :This server was created Jan 1 2020
+insert servermsglogged : + MSG ::foo.bar.baz 004 foo1 foo.bar.baz ircserver-1.0 abc def ghi
+insert servermsglogged : + MSG ::foo.bar.baz 005 foo1 ABC=DEF GHI :are supported by this server
log 1 $ isupport:ABC set to: [DEF]
log 1 $ isupport:GHI set to: []
-insert servermsglogged : +0 MSG ::foo.bar.baz 251 foo1 :There are 10 users and 1000 invisible on 5 servers
-insert servermsglogged : +0 MSG ::foo.bar.baz 252 foo1 7 :IRC Operators online
-insert servermsglogged : +0 MSG ::foo.bar.baz 253 foo1 4 :unknown connection(s)
-insert servermsglogged : +0 MSG ::foo.bar.baz 254 foo1 800 :channels formed
-insert servermsglogged : +0 MSG ::foo.bar.baz 255 foo1 :I have 100 clients and 1 serveres
-insert servermsglogged : +0 MSG ::foo.bar.baz 265 foo1 100 150 :Current local users 100, max 150
-insert servermsglogged : +0 MSG ::foo.bar.baz 266 foo1 1010 1050 :Current global users 1010, max 1050
-insert servermsglogged : +0 MSG ::foo.bar.baz 250 foo1 :Highest connection count: 151 (150 clients) (1080 connections received)
+insert servermsglogged : + MSG ::foo.bar.baz 251 foo1 :There are 10 users and 1000 invisible on 5 servers
+insert servermsglogged : + MSG ::foo.bar.baz 252 foo1 7 :IRC Operators online
+insert servermsglogged : + MSG ::foo.bar.baz 253 foo1 4 :unknown connection(s)
+insert servermsglogged : + MSG ::foo.bar.baz 254 foo1 800 :channels formed
+insert servermsglogged : + MSG ::foo.bar.baz 255 foo1 :I have 100 clients and 1 serveres
+insert servermsglogged : + MSG ::foo.bar.baz 265 foo1 100 150 :Current local users 100, max 150
+insert servermsglogged : + MSG ::foo.bar.baz 266 foo1 1010 1050 :Current global users 1010, max 1050
+insert servermsglogged : + MSG ::foo.bar.baz 250 foo1 :Highest connection count: 151 (150 clients) (1080 connections received)
# collect MOTD into a single output (rather than line-by-line)
-insert servermsglogged : +0 MSG ::foo.bar.baz 375 foo1 :- foo.bar.baz Message of the Day -
-insert servermsglogged : +0 MSG ::foo.bar.baz 372 foo1 :- Howdy! -
-insert servermsglogged : +0 MSG ::foo.bar.baz 372 foo1 :- Welcome! -
-insert servermsglogged : +0 MSG ::foo.bar.baz 372 foo1 :- (to this server) -
-insert servermsglogged : +0 MSG ::foo.bar.baz 376 foo1 :End of /MOTD command
+insert servermsglogged : + MSG ::foo.bar.baz 375 foo1 :- foo.bar.baz Message of the Day -
+insert servermsglogged : + MSG ::foo.bar.baz 372 foo1 :- Howdy! -
+insert servermsglogged : + MSG ::foo.bar.baz 372 foo1 :- Welcome! -
+insert servermsglogged : + MSG ::foo.bar.baz 372 foo1 :- (to this server) -
+insert servermsglogged : + MSG ::foo.bar.baz 376 foo1 :End of /MOTD command
log 1 $ motd set to: [- Howdy! -], [- Welcome! -], [- (to this server) -]
log 2 $ - Howdy! -
log 2 $ - Welcome! -
log 2 $ - (to this server) -
# collect user mode
-insert servermsglogged : +0 MSG ::foo1 MODE foo1 :+Ziw
+insert servermsglogged : + MSG ::foo1 MODE foo1 :+Ziw
log 1 $ users:me:modes set to: [Ziw]
# handle bot query NOTICE
-insert servermsglogged : +0 MSG ::SaslServ!SaslServ@services.bar.baz NOTICE foo1 :Last login from ~baz@foo.bar.baz on Jan 1 22:00:00 2021 +0000.
+insert servermsglogged : + MSG ::SaslServ!SaslServ@services.bar.baz NOTICE foo1 :Last login from ~baz@foo.bar.baz on Jan 1 22:00:00 2021 +0000.
log 3 < (SaslServ) Last login from ~baz@foo.bar.baz on Jan 1 22:00:00 2021 +0000.
# test recoverable 432
insert cmd-nick :2 +1 NEWNICK :@foo
-insert servermsglogged : +0 MSG ::*.?.net 432 foo1 @foo :Erroneous nickname
+insert servermsglogged : + MSG ::*.?.net 432 foo1 @foo :Erroneous nickname
log 1 $ nickname refused for bad format, keeping current one
# rename to easen code-reuse
-insert cmd-nick :4 +0 NUH=foo1!~baz@baz.bar.foo NEWNICK :foo
+insert cmd-nick :4 + NUH=foo1!~baz@baz.bar.foo NEWNICK :foo
log 1 $ users:me:user set to: [~baz]
log 1 $ users:me:host set to: [baz.bar.foo]
insert cmd-nick 4:-2 +1 USER_ID=me NEWNICK :foo
log rename_win_ids $ foo1!~baz@baz.bar.foo renames foo
# join channel with other user
-insert join-channel-0 : +0 CHANNEL=#test RESIDENT_NAMES :foo @baz
+insert join-channel-0 : + CHANNEL=#test RESIDENT_NAMES :foo @baz
insert user-set-to :1 +1 USER_ID=1 USERNICK :baz
log 1 $ channels:#test:prefixes:@ set to: [1]
-insert join-channel-1 : +0 CHANNEL=#test RESIDENT_IDS :[1], [me]
+insert join-channel-1 : + CHANNEL=#test RESIDENT_IDS :[1], [me]
log 4 $ residents: @baz, foo
# process non-self channel JOIN
-insert servermsglogged : +0 MSG ::bar!~bar@bar.bar JOIN :#test
+insert servermsglogged : + MSG ::bar!~bar@bar.bar JOIN :#test
insert user-set-to : +1 USER_ID=2 USERNICK=bar USERNAME=~bar USERHOST :bar.bar
log 1 $ channels:#test:user_ids set to: [1], [2], [me]
log 4 $ bar!~bar@bar.bar joins
# join second channel with partial residents identity to compare distribution of resident-specific messages
-insert join-channel-0 : +0 CHANNEL=#testtest RESIDENT_NAMES :foo bar
-insert join-channel-1 : +0 CHANNEL=#testtest RESIDENT_IDS :[2], [me]
+insert join-channel-0 : + CHANNEL=#testtest RESIDENT_NAMES :foo bar
+insert join-channel-1 : + CHANNEL=#testtest RESIDENT_IDS :[2], [me]
log 5 $ residents: bar, foo
# handle query window with known user
-insert servermsglogged : +0 MSG ::bar!~bar@bar.bar PRIVMSG foo :hi there
+insert servermsglogged : + MSG ::bar!~bar@bar.bar PRIVMSG foo :hi there
log 6 < [bar] hi there
insert privmsg : +1 TARGET_WIN_ID=6 TARGET=bar TXT :hello, how is it going
-insert servermsglogged : +0 MSG ::bar!~bar@bar.bar PRIVMSG foo :fine!
+insert servermsglogged : + MSG ::bar!~bar@bar.bar PRIVMSG foo :fine!
log 6 < [bar] fine!
# handle failure to query absent user
insert privmsg : +1 TARGET_WIN_ID=7 TARGET=barbar TXT :hello!
-insert servermsglogged : +0 MSG ::*.?.net 401 foo barbar :No such nick/channel
+insert servermsglogged : + MSG ::*.?.net 401 foo barbar :No such nick/channel
log 7 $ barbar not online
# handle non-self renaming, even into window of previously not found target
-insert servermsglogged : +0 MSG ::bar!~bar@bar.bar NICK :barbar
+insert servermsglogged : + MSG ::bar!~bar@bar.bar NICK :barbar
log 1 $ users:2:nick set to: [barbar]
log 4,5,6,7 $ bar!~bar@bar.bar renames barbar
# handle non-self QUIT
-insert servermsglogged : +0 MSG ::barbar!~bar@bar.bar QUIT :Client Quit
+insert servermsglogged : + MSG ::barbar!~bar@bar.bar QUIT :Client Quit
log 1 $ users:2:exit_msg set to: [QClient Quit]
log 6,7 $ barbar!~bar@bar.bar quits: Client Quit
insert quit : + CHAN_WIN_ID=4 CHANNEL=#test USER_ID=2 NICK=bar bar!=barbar! REMAINING_IDS :[1], [me]
log 1 $ users:1 deleted
# handle lack of implementation
-insert no-handler : +0 ALERT_WIN_IDS=2,3,4,5,6,7 ? :foo bar baz
+insert no-handler : + ALERT_WIN_IDS=2,3,4,5,6,7 ? :foo bar baz
# handle /disconnect, clear all
insert cmd-disconnect-0 :-1
log 3,6,7 $ foo!~baz@baz.bar.foo quits: Client Quit
insert quits : + CHAN_WIN_ID=5 CHANNEL=#testtest USER_ID=me NICK=foo foo@foo.foo=baz@baz.bar.foo USERIDS_CLEAR :emptied
-insert cmd-disconnect-1 : +0
+insert cmd-disconnect-1
insert disconnect1 :-1 +1 WIN_IDS :2,3,4,5,6,7
log 1 $ motd emptied
log 1 $ users cleared
log 1 # /window.raw VERB [PARAMS_STR]
log 1 # /window.reconnect
-insert during_conn : +0 rename_win_ids :3
+insert during_conn : + rename_win_ids :3
# test setting up second client, but 432 irrecoverably
> /connect baz.bar.foo:6697 ?foo bar:baz
log 9 $ - nickname: ?foo
insert attempting-to-connected 3:-1 +8 WIN_IDS=2 foo.bar.baz :baz.bar.foo
log 8 > NICK :?foo
-servermsg 1 :*.?.net 432 * ?foo :Erroneous nickname
-log 8 < :*.?.net 432 * ?foo :Erroneous nickname
+insert servermsglogged-core : + SERVER_ID=1 WIN_ID=8 MSG ::*.?.net 432 * ?foo :Erroneous nickname
insert isupport-clear : +8
insert disconnect1 1:-1 +8 WIN_IDS :2
log 8 $ nickname refused for bad format, giving up
insert conn_init_2 :2
log 1 > JOIN :#testtest
insert conn_init_2 2:
-insert during_conn : +0 rename_win_ids :3,6,7
+insert during_conn : + rename_win_ids :3,6,7