Skip to content

Commit 9280f09

Browse files
prah23neiljp
authored andcommitted
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 zulip#151.
1 parent 7e01b3a commit 9280f09

File tree

2 files changed

+65
-15
lines changed

2 files changed

+65
-15
lines changed

tests/ui_tools/test_boxes.py

+48-13
Original file line numberDiff line numberDiff line change
@@ -221,19 +221,19 @@ def test_generic_autocomplete_set_footer(
221221
("@Human", 0, "@**Human Myself**"),
222222
("@Human", 1, "@**Human 1**"),
223223
("@Human", 2, "@**Human 2**"),
224-
("@Human", 3, "@**Human Duplicate**"),
225-
("@Human", 4, "@**Human Duplicate**"),
226-
("@Human", -1, "@**Human Duplicate**"),
227-
("@Human", -2, "@**Human Duplicate**"),
224+
("@Human", 3, "@**Human Duplicate|13**"),
225+
("@Human", 4, "@**Human Duplicate|14**"),
226+
("@Human", -1, "@**Human Duplicate|14**"),
227+
("@Human", -2, "@**Human Duplicate|13**"),
228228
("@Human", -3, "@**Human 2**"),
229229
("@Human", -4, "@**Human 1**"),
230230
("@Human", -5, "@**Human Myself**"),
231231
("@Human", -6, None),
232232
("@_Human", 0, "@_**Human Myself**"),
233233
("@_Human", 1, "@_**Human 1**"),
234234
("@_Human", 2, "@_**Human 2**"),
235-
("@_Human", 3, "@_**Human Duplicate**"),
236-
("@_Human", 4, "@_**Human Duplicate**"),
235+
("@_Human", 3, "@_**Human Duplicate|13**"),
236+
("@_Human", 4, "@_**Human Duplicate|14**"),
237237
("@H", 1, "@**Human 1**"),
238238
("@Hu", 1, "@**Human 1**"),
239239
("@Hum", 1, "@**Human 1**"),
@@ -260,8 +260,8 @@ def test_generic_autocomplete_set_footer(
260260
("@", 0, "@**Human Myself**"),
261261
("@", 1, "@**Human 1**"),
262262
("@", 2, "@**Human 2**"),
263-
("@", 3, "@**Human Duplicate**"),
264-
("@", 4, "@**Human Duplicate**"),
263+
("@", 3, "@**Human Duplicate|13**"),
264+
("@", 4, "@**Human Duplicate|14**"),
265265
("@", 5, "@*Group 1*"),
266266
("@", 6, "@*Group 2*"),
267267
("@", 7, "@*Group 3*"),
@@ -272,8 +272,8 @@ def test_generic_autocomplete_set_footer(
272272
("@**", 0, "@**Human Myself**"),
273273
("@**", 1, "@**Human 1**"),
274274
("@**", 2, "@**Human 2**"),
275-
("@", 3, "@**Human Duplicate**"),
276-
("@", 4, "@**Human Duplicate**"),
275+
("@", 3, "@**Human Duplicate|13**"),
276+
("@", 4, "@**Human Duplicate|14**"),
277277
("@**", 5, None), # Reached last match
278278
("@**", 6, None), # Beyond end
279279
# Expected sequence of autocompletes from '@*' (only groups)
@@ -287,11 +287,11 @@ def test_generic_autocomplete_set_footer(
287287
("@_", 0, "@_**Human Myself**"), # NOTE: No silent group mention
288288
("@_", 1, "@_**Human 1**"),
289289
("@_", 2, "@_**Human 2**"),
290-
("@_", 3, "@_**Human Duplicate**"),
291-
("@_", 4, "@_**Human Duplicate**"),
290+
("@_", 3, "@_**Human Duplicate|13**"),
291+
("@_", 4, "@_**Human Duplicate|14**"),
292292
("@_", 5, None), # Reached last match
293293
("@_", 6, None), # Beyond end
294-
("@_", -1, "@_**Human Duplicate**"),
294+
("@_", -1, "@_**Human Duplicate|14**"),
295295
# Complex autocomplete prefixes.
296296
("(@H", 0, "(@**Human Myself**"),
297297
("(@H", 1, "(@**Human 1**"),
@@ -340,6 +340,41 @@ def test_generic_autocomplete_mentions_subscribers(
340340
typeahead_string = write_box.generic_autocomplete(text, state)
341341
assert typeahead_string == required_typeahead
342342

343+
@pytest.mark.parametrize(
344+
"text, expected_distinct_prefix",
345+
# Add 3 different lists of tuples, with each tuple containing a combination
346+
# of the text to be autocompleted and the corresponding typeahead prefix to
347+
# be added to the typeahead suggestions. Only the "@" case has to be ignored
348+
# while building the parameters, because it includes group suggestions too.
349+
[("@" + "Human"[: index + 1], "@") for index in range(len("Human"))]
350+
+ [("@**" + "Human"[:index], "@") for index in range(len("Human") + 1)]
351+
+ [("@_" + "Human"[:index], "@_") for index in range(len("Human") + 1)],
352+
)
353+
def test_generic_autocomplete_user_mentions(
354+
self, write_box, mocker, text, expected_distinct_prefix, state=1
355+
):
356+
_process_typeaheads = mocker.patch(BOXES + ".WriteBox._process_typeaheads")
357+
358+
write_box.generic_autocomplete(text, state)
359+
360+
matching_users = [
361+
"Human Myself",
362+
"Human 1",
363+
"Human 2",
364+
"Human Duplicate",
365+
"Human Duplicate",
366+
]
367+
distinct_matching_users = [
368+
expected_distinct_prefix + "**Human Myself**",
369+
expected_distinct_prefix + "**Human 1**",
370+
expected_distinct_prefix + "**Human 2**",
371+
expected_distinct_prefix + "**Human Duplicate|13**",
372+
expected_distinct_prefix + "**Human Duplicate|14**",
373+
]
374+
_process_typeaheads.assert_called_once_with(
375+
distinct_matching_users, state, matching_users
376+
)
377+
343378
@pytest.mark.parametrize(
344379
"text, state, required_typeahead, to_pin",
345380
[

zulipterminal/ui_tools/boxes.py

+17-2
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
@@ -457,12 +457,27 @@ def autocomplete_users(
457457
)
458458

459459
user_names = [user["full_name"] for user in sorted_matching_users]
460+
461+
# Counter holds a count of each name in the list of users' names in a
462+
# dict-like manner, which is a more efficient approach when compared to
463+
# slicing the original list on each name.
464+
# FIXME: Use a persistent counter rather than generate one on each autocomplete.
465+
user_names_counter = Counter(user_names)
466+
467+
# Append user_id's to users with the same names.
468+
user_names_with_distinct_duplicates = [
469+
f"{user['full_name']}|{user['user_id']}"
470+
if user_names_counter[user["full_name"]] > 1
471+
else user["full_name"]
472+
for user in sorted_matching_users
473+
]
474+
460475
extra_prefix = "{}{}".format(
461476
"*" if prefix_string[-1] != "*" else "",
462477
"*" if prefix_string[-2:] != "**" else "",
463478
)
464479
user_typeahead = format_string(
465-
user_names, prefix_string + extra_prefix + "{}**"
480+
user_names_with_distinct_duplicates, prefix_string + extra_prefix + "{}**"
466481
)
467482

468483
return user_typeahead, user_names

0 commit comments

Comments
 (0)