Skip to content

Commit 7172b8f

Browse files
committed
boxes: Use user_ids in autocomplete for ambiguous user mentions.
Prior to this commit, user mentions through autocomplete used only names in the typeahead. This commit appends `user_id`s to all the multiple instances of the same name to use the **Name|User_id** format of user mentions. This is done by using collections.Counter to check the count of each user name in the users list. The user_id is appended to names that have a count greater than 1. The appended user_id would serve as a distinction between users having the same name. Tests added and updated. Fixes #151.
1 parent 07c4e75 commit 7172b8f

File tree

2 files changed

+71
-15
lines changed

2 files changed

+71
-15
lines changed

tests/ui_tools/test_boxes.py

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,19 @@ def test_generic_autocomplete_set_footer(self, mocker, write_box,
128128
('@Human', 0, '@**Human Myself**'),
129129
('@Human', 1, '@**Human 1**'),
130130
('@Human', 2, '@**Human 2**'),
131-
('@Human', 3, '@**Human Duplicate**'),
132-
('@Human', 4, '@**Human Duplicate**'),
133-
('@Human', -1, '@**Human Duplicate**'),
134-
('@Human', -2, '@**Human Duplicate**'),
131+
('@Human', 3, '@**Human Duplicate|13**'),
132+
('@Human', 4, '@**Human Duplicate|14**'),
133+
('@Human', -1, '@**Human Duplicate|14**'),
134+
('@Human', -2, '@**Human Duplicate|13**'),
135135
('@Human', -3, '@**Human 2**'),
136136
('@Human', -4, '@**Human 1**'),
137137
('@Human', -5, '@**Human Myself**'),
138138
('@Human', -6, None),
139139
('@_Human', 0, '@_**Human Myself**'),
140140
('@_Human', 1, '@_**Human 1**'),
141141
('@_Human', 2, '@_**Human 2**'),
142-
('@_Human', 3, '@_**Human Duplicate**'),
143-
('@_Human', 4, '@_**Human Duplicate**'),
142+
('@_Human', 3, '@_**Human Duplicate|13**'),
143+
('@_Human', 4, '@_**Human Duplicate|14**'),
144144
('@H', 1, '@**Human 1**'),
145145
('@Hu', 1, '@**Human 1**'),
146146
('@Hum', 1, '@**Human 1**'),
@@ -167,8 +167,8 @@ def test_generic_autocomplete_set_footer(self, mocker, write_box,
167167
('@', 0, '@**Human Myself**'),
168168
('@', 1, '@**Human 1**'),
169169
('@', 2, '@**Human 2**'),
170-
('@', 3, '@**Human Duplicate**'),
171-
('@', 4, '@**Human Duplicate**'),
170+
('@', 3, '@**Human Duplicate|13**'),
171+
('@', 4, '@**Human Duplicate|14**'),
172172
('@', 5, '@*Group 1*'),
173173
('@', 6, '@*Group 2*'),
174174
('@', 7, '@*Group 3*'),
@@ -179,8 +179,8 @@ def test_generic_autocomplete_set_footer(self, mocker, write_box,
179179
('@**', 0, '@**Human Myself**'),
180180
('@**', 1, '@**Human 1**'),
181181
('@**', 2, '@**Human 2**'),
182-
('@', 3, '@**Human Duplicate**'),
183-
('@', 4, '@**Human Duplicate**'),
182+
('@', 3, '@**Human Duplicate|13**'),
183+
('@', 4, '@**Human Duplicate|14**'),
184184
('@**', 5, None), # Reached last match
185185
('@**', 6, None), # Beyond end
186186
# Expected sequence of autocompletes from '@*' (only groups)
@@ -194,11 +194,11 @@ def test_generic_autocomplete_set_footer(self, mocker, write_box,
194194
('@_', 0, '@_**Human Myself**'), # NOTE: No silent group mention
195195
('@_', 1, '@_**Human 1**'),
196196
('@_', 2, '@_**Human 2**'),
197-
('@_', 3, '@_**Human Duplicate**'),
198-
('@_', 4, '@_**Human Duplicate**'),
197+
('@_', 3, '@_**Human Duplicate|13**'),
198+
('@_', 4, '@_**Human Duplicate|14**'),
199199
('@_', 5, None), # Reached last match
200200
('@_', 6, None), # Beyond end
201-
('@_', -1, '@_**Human Duplicate**'),
201+
('@_', -1, '@_**Human Duplicate|14**'),
202202
# Complex autocomplete prefixes.
203203
('(@H', 0, '(@**Human Myself**'),
204204
('(@H', 1, '(@**Human 1**'),
@@ -242,6 +242,51 @@ def test_generic_autocomplete_mentions_subscribers(self, write_box, text,
242242
typeahead_string = write_box.generic_autocomplete(text, state)
243243
assert typeahead_string == required_typeahead
244244

245+
@pytest.mark.parametrize('text', [
246+
prefix + 'Human'[:index + 1] for index in range(len('Human'))
247+
for prefix in ['@', '@**']
248+
] + ['@**'])
249+
def test_generic_autocomplete_user_mentions(self, write_box, text, mocker,
250+
state=1):
251+
_process_typeaheads = mocker.patch(BOXES
252+
+ '.WriteBox._process_typeaheads')
253+
254+
matching_users = [
255+
'Human Myself', 'Human 1', 'Human 2', 'Human Duplicate',
256+
'Human Duplicate',
257+
]
258+
distinct_matching_users = [
259+
'@**Human Myself**', '@**Human 1**', '@**Human 2**',
260+
'@**Human Duplicate|13**', '@**Human Duplicate|14**',
261+
]
262+
263+
write_box.generic_autocomplete(text, state)
264+
265+
_process_typeaheads.assert_called_once_with(distinct_matching_users,
266+
state, matching_users)
267+
268+
@pytest.mark.parametrize('text', [
269+
'@_' + 'Human'[:index] for index in range(len('Human') + 1)
270+
])
271+
def test_generic_autocomplete_silent_user_mentions(self, write_box, text,
272+
mocker, state=1):
273+
_process_typeaheads = mocker.patch(BOXES
274+
+ '.WriteBox._process_typeaheads')
275+
276+
matching_users = [
277+
'Human Myself', 'Human 1', 'Human 2', 'Human Duplicate',
278+
'Human Duplicate',
279+
]
280+
distinct_matching_users = [
281+
'@_**Human Myself**', '@_**Human 1**', '@_**Human 2**',
282+
'@_**Human Duplicate|13**', '@_**Human Duplicate|14**',
283+
]
284+
285+
write_box.generic_autocomplete(text, state)
286+
287+
_process_typeaheads.assert_called_once_with(distinct_matching_users,
288+
state, matching_users)
289+
245290
@pytest.mark.parametrize('text, state, required_typeahead, to_pin', [
246291
# With no streams pinned.
247292
('#Stream', 0, '#**Stream 1**', []), # 1st-word startswith match.

zulipterminal/ui_tools/boxes.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re
22
import typing
33
import unicodedata
4-
from collections import OrderedDict, defaultdict
4+
from collections import Counter, OrderedDict, defaultdict
55
from datetime import date, datetime, timedelta
66
from sys import platform
77
from time import sleep, time
@@ -445,11 +445,22 @@ def autocomplete_users(self, text: str, prefix_string: str
445445
reverse=True)
446446

447447
user_names = [user['full_name'] for user in sorted_matching_users]
448+
449+
user_names_counter = Counter(user_names)
450+
451+
# Append user_id's to users with the same names.
452+
user_names_with_distinct_duplicates = [
453+
f"{user['full_name']}|{user['user_id']}"
454+
if user_names_counter[user['full_name']] > 1
455+
else user['full_name']
456+
for user in sorted_matching_users
457+
]
458+
448459
extra_prefix = "{}{}".format(
449460
'*' if prefix_string[-1] != '*' else '',
450461
'*' if prefix_string[-2:] != '**' else '',
451462
)
452-
user_typeahead = format_string(user_names,
463+
user_typeahead = format_string(user_names_with_distinct_duplicates,
453464
prefix_string + extra_prefix + '{}**')
454465

455466
return user_typeahead, user_names

0 commit comments

Comments
 (0)