diff --git a/lib/shared/markdown.js b/lib/shared/markdown.js --- a/lib/shared/markdown.js +++ b/lib/shared/markdown.js @@ -2,8 +2,16 @@ import invariant from 'invariant'; -import { markdownMentionRegex } from './mention-utils.js'; -import type { RelativeMemberInfo } from '../types/thread-types.js'; +import { + markdownMentionRegex, + chatMentionRegex, + decodeChatMentionText, +} from './mention-utils.js'; +import type { + RelativeMemberInfo, + ResolvedThreadInfo, + ChatMentionCandidates, +} from '../types/thread-types.js'; // simple-markdown types export type State = { @@ -218,6 +226,34 @@ return match; } +function matchChatMentions(): MatchFunction { + return (source: string, state: State) => { + if (!state.inline) { + return null; + } + const result = chatMentionRegex.exec(source); + return result; + }; +} + +function parseChatMention( + chatMentionCandidates: ChatMentionCandidates, + capture: Capture, +): { + threadInfo: ?ResolvedThreadInfo, + content: string, + hasAccessToChat: boolean, +} { + const threadInfo = chatMentionCandidates[capture[2]]; + const threadName = threadInfo?.uiName ?? decodeChatMentionText(capture[3]); + const content = `@${threadName}`; + return { + threadInfo, + content, + hasAccessToChat: !!threadInfo, + }; +} + const blockQuoteRegex: RegExp = /^( *>[^\n]+(?:\n[^\n]+)*)(?:\n|$)/; const blockQuoteStripFollowingNewlineRegex: RegExp = /^( *>[^\n]+(?:\n[^\n]+)*)(?:\n|$){2}/; @@ -317,4 +353,6 @@ matchMentions, stripSpoilersFromNotifications, stripSpoilersFromMarkdownAST, + matchChatMentions, + parseChatMention, }; 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,10 @@ import { oldValidUsernameRegexString } from './account-utils.js'; import SearchIndex from './search-index.js'; -import { threadOtherMembers } from './thread-utils.js'; +import { + threadOtherMembers, + validChatNameRegexString, +} from './thread-utils.js'; import { stringForUserExplicit } from './user-utils.js'; import { threadTypes } from '../types/thread-types-enum.js'; import { @@ -35,6 +38,13 @@ 'g', ); +const chatMentionRegexString = `^(? matches[2]); @@ -117,4 +127,6 @@ getNewTextAndSelection, getTypeaheadRegexMatches, getMentionsCandidates, + chatMentionRegex, + decodeChatMentionText, }; 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 @@ -111,8 +111,8 @@ const chatNameMaxLength = 191; const chatNameMinLength = 0; const secondCharRange = `{${chatNameMinLength},${chatNameMaxLength}}`; -const validChatNameRegexString = `^.${secondCharRange}$`; -const validChatNameRegex: RegExp = new RegExp(validChatNameRegexString); +const validChatNameRegexString = `.${secondCharRange}`; +const validChatNameRegex: RegExp = new RegExp(`^${validChatNameRegexString}$`); function threadHasPermission( threadInfo: ?(ThreadInfo | RawThreadInfo), @@ -1820,6 +1820,7 @@ getAvailableThreadMemberActions, threadMembersWithoutAddedAshoat, validChatNameRegex, + validChatNameRegexString, chatNameMaxLength, patchThreadInfoToIncludeMentionedMembersOfParent, threadInfoInsideCommunity,