diff --git a/lib/shared/mention-utils.js b/lib/shared/mention-utils.js --- a/lib/shared/mention-utils.js +++ b/lib/shared/mention-utils.js @@ -2,7 +2,11 @@ import { oldValidUsernameRegexString } from './account-utils.js'; import SentencePrefixSearchIndex from './sentence-prefix-search-index.js'; -import { threadOtherMembers, chatNameMaxLength } from './thread-utils.js'; +import { + threadOtherMembers, + chatNameMaxLength, + extractThreadID, +} from './thread-utils.js'; import { stringForUserExplicit } from './user-utils.js'; import { threadTypes } from '../types/thread-types-enum.js'; import type { @@ -11,6 +15,7 @@ ResolvedThreadInfo, ChatMentionCandidates, } from '../types/thread-types.js'; +import { ET, entityTextToRawString } from '../utils/entity-text.js'; import { idSchemaRegex } from '../utils/validation-utils.js'; export type TypeaheadMatchedStrings = { @@ -58,8 +63,54 @@ 'g', ); -const chatMentionRegexString = `^(? { + const matches = text.matchAll(globalChatMentionRegex); + if (!matches) { + return []; + } + const result = []; + for (const match of matches) { + result.push({ + threadID: match[2], + defaultText: match[3], + }); + } + return result; +} + +function renderChatMentions( + text: string, + threadInfos: { +[idWithoutKeyserverPrefix: string]: ThreadInfo }, + mentionableThreadIDs: $ReadOnlySet, +): string { + const matches = text.matchAll(globalChatMentionRegex); + if (!matches) { + return text; + } + let newText = text; + for (const match of matches) { + const threadID = extractThreadID(match[2]); + if (mentionableThreadIDs.has(threadID) && threadInfos[threadID]) { + const mentionedThreadInfo = threadInfos[threadID]; + const thread = ET.thread({ + display: 'uiName', + threadInfo: mentionedThreadInfo, + }); + const threadName = entityTextToRawString(ET`${thread}`); + newText = newText.replace(match[0], `@${threadName}`); + } else { + newText = newText.replace(match[0], `@${match[3]}`); + } + } + return newText; +} function encodeChatMentionText(text: string): string { return text.replace(/]/g, '\\]'); @@ -182,4 +233,6 @@ chatMentionRegex, encodeChatMentionText, decodeChatMentionText, + extractChatMentions, + renderChatMentions, }; diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -1810,6 +1810,10 @@ ]; } +function extractThreadID(threadID: string): string { + return threadID.slice(threadID.indexOf('|') + 1); +} + export { threadHasPermission, viewerIsMember, @@ -1882,4 +1886,5 @@ useChatMentionCandidatesObj, useThreadChatMentionCandidates, useThreadChatMentionSearchIndex, + extractThreadID, };