Skip to content

Commit 6bd11b6

Browse files
committed
compose [nfc]: Add param to mention for omitting |<id> when possible
We can use this for @-mention autocomplete, zulip#49.
1 parent 406b7d0 commit 6bd11b6

File tree

2 files changed

+31
-7
lines changed

2 files changed

+31
-7
lines changed

lib/model/compose.dart

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,16 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
177177
return store.account.realmUrl.replace(fragment: fragment.toString());
178178
}
179179

180-
// TODO like web, use just the name, no ID, when that wouldn't be ambiguous.
181-
// It looks nicer while the user's still composing and looking at the source.
182-
String mention(User user, {bool silent = false}) {
183-
return '@${silent ? '_' : ''}**${user.fullName}|${user.userId}**';
180+
/// An @-mention, like @**Chris Bobbe|13313**.
181+
///
182+
/// To omit the user ID part ("|13313") whenever the name part is unambiguous,
183+
/// pass a Map of all users we know about. This means accepting a linear scan
184+
/// through all users; avoid it in performance-sensitive codepaths.
185+
String mention(User user, {bool silent = false, Map<int, User>? users}) {
186+
bool includeUserId = users == null
187+
|| users.values.takeWhile((u) => u.fullName == user.fullName).take(2).length == 2;
188+
189+
return '@${silent ? '_' : ''}**${user.fullName}${includeUserId ? '|${user.userId}' : ''}**';
184190
}
185191

186192
/// https://spec.commonmark.org/0.30/#inline-link
@@ -214,6 +220,7 @@ String quoteAndReplyPlaceholder(PerAccountStore store, {
214220
final url = narrowLink(store,
215221
SendableNarrow.ofMessage(message, selfUserId: store.account.userId),
216222
nearMessageId: message.id);
223+
// See note in [quoteAndReply] about asking `mention` to omit the |<id> part.
217224
return '${mention(sender!, silent: true)} ${inlineLink('said', url)}: ' // TODO(i18n) ?
218225
'*(loading message ${message.id})*\n'; // TODO(i18n) ?
219226
}
@@ -235,6 +242,9 @@ String quoteAndReply(PerAccountStore store, {
235242
final url = narrowLink(store,
236243
SendableNarrow.ofMessage(message, selfUserId: store.account.userId),
237244
nearMessageId: message.id);
245+
// Could ask `mention` to omit the |<id> part unless the mention is ambiguous…
246+
// but that would mean a linear scan through all users, and the extra noise
247+
// won't much matter with the already probably-long message link in there too.
238248
return '${mention(sender!, silent: true)} ${inlineLink('said', url)}:\n' // TODO(i18n) ?
239249
'${wrapWithBacktickFence(content: rawContent, infoString: 'quote')}';
240250
}

test/model/compose_test.dart

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,24 @@ hello
301301
// starred, mentioned; searches; arbitrary
302302
});
303303

304-
test('mention', () {
304+
group('mention', () {
305305
final user = eg.user(userId: 123, fullName: 'Full Name');
306-
check(mention(user, silent: false)).equals('@**Full Name|123**');
307-
check(mention(user, silent: true)).equals('@_**Full Name|123**');
306+
test('not silent', () {
307+
check(mention(user, silent: false)).equals('@**Full Name|123**');
308+
});
309+
test('silent', () {
310+
check(mention(user, silent: true)).equals('@_**Full Name|123**');
311+
});
312+
test('`users` passed; has two users with same fullName', () {
313+
final store = eg.store();
314+
store.addUsers([user, eg.user(userId: 234, fullName: user.fullName)]);
315+
check(mention(user, silent: true, users: store.users)).equals('@_**Full Name|123**');
316+
});
317+
test('`users` passed; user has unique fullName', () {
318+
final store = eg.store();
319+
store.addUsers([user, eg.user(userId: 234, fullName: 'Another Name')]);
320+
check(mention(user, silent: true, users: store.users)).equals('@_**Full Name**');
321+
});
308322
});
309323

310324
test('inlineLink', () {

0 commit comments

Comments
 (0)