fix(desktop): support multi-word #channel name highlighting#229
fix(desktop): support multi-word #channel name highlighting#229wesbillman merged 7 commits intomainfrom
Conversation
Channel name highlighting previously only matched the first word after #. This refactors the mention pattern builder into a generic buildPrefixPattern function shared by both @mention and #channel highlighting, enabling multi-word channel names to be matched longest-first. Also updates the composer's channel query detection to scan backwards for # when typing multi-word names, mirroring the existing @mention behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ix detection The remark mention/channel-link plugins had identical walkChildren and split functions, and the useMentions/useChannelLinks hooks had identical detectQuery functions. Extract createRemarkPrefixPlugin factory and detectPrefixQuery helper to eliminate ~200 lines of duplication. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rsing The remarkPlugins array was created inline in JSX on every render, causing ReactMarkdown to re-parse even when plugin inputs hadn't changed. Wrap it in useMemo keyed on mentionNames and channelNames. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@codex review please |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e28197bcb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| const nameAlternatives = sorted.map((name) => escapeRegExp(name)).join("|"); | ||
| return new RegExp(`@(?:${nameAlternatives}|\\S+)`, "g"); | ||
| return new RegExp(`${escapedPrefix}(?:${nameAlternatives}|\\S+)`, "g"); |
There was a problem hiding this comment.
Add delimiter check after known-name prefix matches
buildPrefixPattern emits #(?:<known>|\S+) without requiring a word/punctuation boundary after a known name, so a shorter existing channel can incorrectly capture the start of a longer token (for example, channel gen makes #general match as #gen). In remarkChannelLinks, that produces a clickable link to the wrong channel and leaves the remaining characters as plain text, which is a functional mis-link introduced by the new name-first matching path.
Useful? React with 👍 / 👎.
|
|
||
| const nameAlternatives = sorted.map((name) => escapeRegExp(name)).join("|"); | ||
| return new RegExp(`@(?:${nameAlternatives}|\\S+)`, "g"); | ||
| return new RegExp(`${escapedPrefix}(?:${nameAlternatives}|\\S+)`, "g"); |
There was a problem hiding this comment.
Make multi-word channel regex case-insensitive
This regex is compiled with only the g flag, so known multi-word channel alternatives are matched case-sensitively. If the channel is Build Team and a user types #build team, the known-name branch will not match and the fallback \S+ branch only captures #build, breaking full multi-word highlighting/linking despite downstream channel lookup being case-insensitive. This creates inconsistent behavior for manually typed links.
Useful? React with 👍 / 👎.
…fix pattern Fixes two issues in buildPrefixPattern: 1. Prefix collision: #gen no longer incorrectly matches when typing #general, by adding a lookahead requiring a word boundary after known-name matches. 2. Case sensitivity: #build team now correctly matches channel "Build Team" by adding the `i` flag for case-insensitive matching. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… re-renders The Markdown component's React.memo comparator checked mentionNames but not channelNames. Channel names were derived inside MarkdownInner from useChannelNavigation() context, so when channels loaded async the memo blocked re-renders and the remark plugin never got real channel names — falling back to a regex that stopped at spaces. Move channelNames derivation to each call site (MessageRow, ForumThreadPanel, ChannelCanvas) and pass it as a prop, mirroring the existing mentionNames pattern. Add channelNames to the memo comparator. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ti-word names Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Links hook Expose knownChannelNames from useChannelLinks so MessageComposer can use it directly instead of independently deriving channel names from useChannelNavigation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
#channel namehighlighting now supports multi-word names with spaces (previously only the first word was highlighted)createRemarkPrefixPluginfactory anddetectPrefixQueryhelper to eliminate duplication between@mentionand#channelhighlighting systemsremarkPluginsarray to avoid unnecessary remark re-parsing on context-triggered re-rendersChanges
mentionPattern.ts— GeneralizedbuildMentionPatternintobuildPrefixPattern(prefix, knownNames)that works for any prefix characterremarkChannelLinks.ts— Now acceptschannelNamesoption and uses dynamic pattern matching (likeremarkMentions)remarkMentions.ts— Simplified to use sharedcreateRemarkPrefixPluginfactoryuseChannelLinks.ts— Added multi-word channel name detection in autocomplete (mirroringuseMentions)useMentions.ts— ExtracteddetectMentionQueryinto shareddetectPrefixQuerymarkdown.tsx— Passes channel names to plugin, memoizesremarkPluginsarraycreateRemarkPrefixPlugin.ts— Shared remark plugin factorydetectPrefixQuery.ts— Shared prefix query detection for autocomplete8 files changed, ~234 additions, ~206 deletions (net reduction in duplication)
Test plan
#channel link highlightin a message — full name should be highlighted, not just#channel#generalstill highlight correctly@mentionhighlighting with multi-word names still works#inside code blocks is not highlighted# headingrenders as markdown heading, not a channel link🤖 Generated with Claude Code