home · contact · privacy
Record prefix memberships in Channel.prefixes dictionary.
authorChristian Heller <c.heller@plomlompom.de>
Fri, 21 Nov 2025 22:27:24 +0000 (23:27 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Fri, 21 Nov 2025 22:27:24 +0000 (23:27 +0100)
src/ircplom/client.py
src/ircplom/client_tui.py
src/ircplom/db_primitives.py
src/tests/channels.test
src/tests/isupports.test
src/tests/lib/part
src/tests/test.test

index 23accb62463d058bdcbc9e8a98c6276a17c39607..514e4103777145e70ac9d1e39496ac90dc8143aa 100644 (file)
@@ -123,6 +123,7 @@ class Channel:
     'Collects .topic, and in .user_ids inhabitant IDs.'
     topic: Topic
     user_ids: Iterable[str]
+    prefixes: Dict[tuple[str, ...]]
     exits: Dict[str]
 
 
@@ -187,10 +188,17 @@ class _Channel(Channel):
 
     def add_from_namreply(self, items: tuple[str, ...]) -> None:
         'Add to .user_ids items assumed as nicknames with membership prefixes.'
+        prefixes = self._get_membership_prefixes()
         for item in items:
-            n_u_h = NickUserHost(item.lstrip(self._get_membership_prefixes()))
+            prefix = ''.join([pfx for pfx in prefixes if item.startswith(pfx)])
+            n_u_h = NickUserHost(item.lstrip(prefix))
             user_id = self._userid_for_nickuserhost(n_u_h, create_if_none=True)
             self.user_ids.completable_add(user_id, on_complete=False)
+            if prefix:
+                if prefix in self.prefixes.keys():
+                    self.prefixes[prefix] += (user_id,)
+                else:
+                    self.prefixes[prefix] = (user_id,)
 
     def add_user(self, user: '_User') -> None:
         'To .user_ids add user.nickname, keep .user_ids declared complete.'
@@ -200,6 +208,9 @@ class _Channel(Channel):
 
     def remove_user(self, user: '_User', msg: str) -> None:
         'From .user_ids remove .nickname, keep .user_ids declared complete.'
+        for prefix in self.prefixes.keys():
+            self.prefixes[prefix] = tuple(id_ for id_ in self.prefixes[prefix]
+                                          if id_ != user.id_)
         self.exits[user.id_] = msg
         self.user_ids.completable_remove(user.id_, on_complete=True)
         del self.exits[user.id_]
@@ -332,6 +343,7 @@ class _UpdatingChannel(UpdatingAttrsMixin, _Channel):
     user_ids: UpdatingCompletableStringsSet
     topic: _UpdatingCompletableTopic
     exits: UpdatingDict[str]
+    prefixes: UpdatingDict[tuple[str, ...]]
 
 
 class _UpdatingUser(UpdatingAttrsMixin, _User):
index 14e7d9456644693ed4642928cc1ece5c2ba5b212..63e0779d145b0ad701d0c9daa9f13050eff7c5a6 100644 (file)
@@ -284,6 +284,7 @@ class _UpdatingDict(Dict[DictItem], _UpdatingNode):
 class _UpdatingChannel(_UpdatingNode, Channel):
     user_ids: set[str]
     exits: _UpdatingDict[str]
+    prefixes: _UpdatingDict[tuple[str, ...]]
 
     def recursive_set_and_report_change(self, update: _Update) -> None:
         super().recursive_set_and_report_change(update)
index 76d2c85ec01017a6b3fe0687d734dd871834d1e9..38b1939761459d938f3f517ab1129bbd50f49f04 100644 (file)
@@ -60,7 +60,6 @@ class Dict(Clearable, Generic[DictItem]):
     # for Clearable.clear.
 
     def __setitem__(self, key: str, val: DictItem) -> None:
-        assert isinstance(val, self._item_cls), (type(val), self._item_cls)
         self._dict[key] = val
 
     def __getitem__(self, key: str) -> DictItem:
index 31838a8833ce903a48e539cca0ec5b7141d004fc..657188f0c87b21cd5399cfa5bc009a96a672633c 100644 (file)
@@ -40,9 +40,17 @@ insert join-empty : + CHAN_WIN_ID=3 CHANNEL :#ch_test0
 > /join TARGET
 log LOG_WIN_ID $ already in that channel
 
-× part-other
-insert servermsglogged : + MSG ::NICK!~NICK@NICK.NICK PART :#ch_test0
-insert parts-core : + exitMSG= exitPREFIX= USERIDS_CLEAR=set§to:§REMAINING_IDS CHANNEL=#ch_test0 CHAN_WIN_ID=3 § : 
+× part-other-0
+insert servermsglogged : + MSG ::NICK!~NICK@NICK.NICK PART ARGS
+
+× part-other-0-no-msg
+insert part-other-0 : + ARGS ::#ch_test0
+
+× part-other-1
+insert parts-core : + USERIDS_CLEAR=set§to:§REMAINING_IDS CHANNEL=#ch_test0 CHAN_WIN_ID=3 § : 
+
+× part-other-1-no-msg
+insert part-other-1 : + exitMSG= exitPREFIX :
 
 × ×--------------------------
 
@@ -106,11 +114,14 @@ insert part : + CHANNEL=#ch_test0 CHAN_WIN_ID=3 USERIDS_CLEAR :set to: [1]
 log 1 $ users:1 deleted
 
 # check /join into channel with many other users, with multi-line 353
-insert join-channel-0 : + CHANNEL=#ch_test0 RESIDENT_NAMES :foo baz oof
+insert join-channel-0 : + CHANNEL=#ch_test0 RESIDENT_NAMES :foo @baz +oof
 insert user-set-to :1 + USER_ID=2 USERNICK :baz
+log 1 $ channels:#ch_test0:prefixes:@ set to: [2]
 insert user-set-to :1 + USER_ID=3 USERNICK :oof
-insert servermsglogged : + MSG ::foo.bar.baz 353 foo = #ch_test0 :rab zab
+log 1 $ channels:#ch_test0:prefixes:+ set to: [3]
+insert servermsglogged : + MSG ::foo.bar.baz 353 foo = #ch_test0 :+rab zab
 insert user-set-to :1 + USER_ID=4 USERNICK :rab
+log 1 $ channels:#ch_test0:prefixes:+ set to: [3], [4]
 insert user-set-to :1 + USER_ID=5 USERNICK :zab
 insert join-channel-1 : + CHANNEL=#ch_test0 RESIDENT_IDS :[2], [3], [4], [5], [me]
 log 3 $ residents: baz, oof, rab, zab, foo
@@ -148,14 +159,18 @@ insert servermsglogged : + MSG ::*.?.net NOTICE #ch_test0 :msg_test6 msg_test7
 log 3 < (*.?.net) msg_test6 msg_test7
 
 # check part of user visible, and of user NOT visible in other channel
-insert part-other : + NICK=baz USER_ID=2 REMAINING_IDS :[3], [4], [5], [me]
-insert part-other : + NICK=oof USER_ID=3 REMAINING_IDS :[4], [5], [me]
+insert part-other-0-no-msg : + NICK :baz
+log 1 $ channels:#ch_test0:prefixes:@ emptied
+insert part-other-1-no-msg : + USER_ID=2 NICK=baz REMAINING_IDS :[3], [4], [5], [me]
+insert part-other-0-no-msg : + NICK :oof
+log 1 $ channels:#ch_test0:prefixes:+ set to: [4]
+insert part-other-1-no-msg : + USER_ID=3 NICK=oof REMAINING_IDS :[4], [5], [me]
 log 1 $ users:3 deleted
 
 # check other-user part with exit message
-insert servermsglogged : + MSG ::zab!~zab@zab.zab PART #ch_test0 :goodbye
+insert part-other-0 : + NICK=zab ARGS :#ch_test0 :goodbye
 insert user-set-to 1: + USER_ID=5 USERNAME=~zab USERHOST :zab.zab
-insert parts-core : + CHAN_WIN_ID=3 CHANNEL=#ch_test0 USER_ID=5 NICK=zab exitPREFIX=:§ exitMSG=goodbye USERIDS_CLEAR=set§to:§[4],§[me] § : 
+insert part-other-1 : + USER_ID=5 NICK=zab exitPREFIX=:§ exitMSG=goodbye REMAINING_IDS=[4],§[me] § : 
 log 1 $ users:5 deleted
 
 # check re-join of user kept visible in other channel
index 8b9bd1b7862d34e25eb14b18ba0a6b1098d25c2f..69e0546a68fb17ad024a2ea5d80cde69ae2292a1 100644 (file)
@@ -84,14 +84,18 @@ insert join-empty : + CHAN_WIN_ID=6 CHANNEL :#ch_test5
 # test effect of PREFIX
 insert join-channel-0 : +0 CHANNEL=#ch_test6 RESIDENT_NAMES :foo @bar +baz =quux
 insert user-set-to :1 +1 USER_ID=1 USERNICK :bar
+log 1 $ channels:#ch_test6:prefixes:@ set to: [1]
 insert user-set-to :1 +1 USER_ID=2 USERNICK :baz
+log 1 $ channels:#ch_test6:prefixes:+ set to: [2]
 insert user-set-to :1 +1 USER_ID=3 USERNICK :=quux
 insert join-channel-1 : +0 CHANNEL=#ch_test6 RESIDENT_IDS :[1], [2], [3], [me]
 log 7 $ residents: bar, baz, =quux, foo
 insert un-default : +0 KEY=PREFIX VALUE :(vE)+=
 insert join-channel-0 : +0 CHANNEL=#ch_test7 RESIDENT_NAMES :foo @bar +baz =quux
 insert user-set-to :1 +1 USER_ID=4 USERNICK :@bar
+log 1 $ channels:#ch_test7:prefixes:+ set to: [2]
 insert user-set-to :1 +1 USER_ID=5 USERNICK :quux
+log 1 $ channels:#ch_test7:prefixes:= set to: [5]
 insert join-channel-1 : +0 CHANNEL=#ch_test7 RESIDENT_IDS :[2], [4], [5], [me]
 log 8 $ residents: baz, @bar, quux, foo
 
index fc214d8d98747a9674e1ac950ab64857b86a79bd..e6b5e92a6867e679dd3ed7f7dc3f70a4dddab087 100644 (file)
@@ -9,7 +9,6 @@ log 1 $ channels:CHANNEL:exits:USER_ID deleted
 × parts-core
 insert exit-channel : + exitTYPE=P exitDESC :parts
 
-× part-1
 × part
 > /part
 log 1 > PART :CHANNEL
index 3e776eb896886f1aed3a3505a4f329ed811db8b5..6400cc26d9db1adb2fa58a00f6f24ef092735221 100644 (file)
@@ -113,6 +113,7 @@ 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 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]
 log 4 $ residents: baz, foo