Skip to content

Add @mention support to messaging (compose autocomplete, tappable render, self-mention notification)#2044

Draft
garthvh with Copilot wants to merge 2 commits into
mainfrom
copilot/add-mention-support-to-messaging
Draft

Add @mention support to messaging (compose autocomplete, tappable render, self-mention notification)#2044
garthvh with Copilot wants to merge 2 commits into
mainfrom
copilot/add-mention-support-to-messaging

Conversation

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Implements cross-platform @mention feature per meshtastic/design#21. Wire format is @!<8-hex-id> (e.g. @!deadbeef) matching Android/Web exactly.

Core parser — Meshtastic/Helpers/MentionParser.swift

  • activeMentionQuery(in:) — detects in-progress @<query> at end of text; returns nil if followed by ! (resolved) or whitespace (ended)
  • insertMentionToken(into:user:) — replaces @<partial> suffix with @!<hexId> using Int64.toHex()
  • resolveMentions(in:context:) — at render time, converts @!<hex> tokens to [@DisplayName](meshtastic:///nodes?nodenum=<num>) markdown links; resolves live from SwiftData — name changes reflect without re-sending
  • containsMention(of:in:) — exact wire-format self-mention check for notifications

Compose — TextMessageField.swift + MentionAutocomplete.swift

  • MentionAutocomplete overlay queries all NodeInfoEntity via @Query, filters by long name / short name / user ID, caps at 10 results, shows CircleText + name
  • Integrated into both the iOS 17 TextField path and the iOS 18+ FormattingComposeArea (TextEditor) path
  • Selection inserts the hex token; state clears on send/dismiss/position-request

Render — MessageText.swift

  • Calls resolveMentions before AttributedString(markdown:) — mentions render as tappable underlined links showing current node display name
  • handleURL intercepts meshtastic:///nodes?nodenum= and calls appState.router.navigateToNodeDetail(nodeNum:) for deep-link navigation

Notifications — MeshPackets.swift

  • Channel messages always trigger a local notification when the connected node's own ID is mentioned, regardless of per-channel mute setting

Docs — docs/user/messages.md

  • Added ## @Mentions section covering compose flow, tappable links, notification behaviour, and wire-format note

How is this tested?

MeshtasticTests/MentionParserTests.swift — 23 unit tests using Swift Testing covering all MentionParser functions: regex matching, node-num extraction, active-query detection edge cases (resolved token, trailing space, empty string), token insertion, and self-mention detection.

Screenshots/Videos (when applicable)

UI changes are in the compose field (autocomplete list on @) and message bubbles (tappable mention links). Screenshots to be added by reviewer if needed.

Checklist

  • My code adheres to the project's coding and style guidelines.
  • I have conducted a self-review of my code.
  • I have commented my code, particularly in complex areas.
  • I have verified whether these changes require updates to the in-app documentation under docs/user/ or docs/developer/, and updated accordingly (see copilot-instructions.md for the view → doc page mapping). If no doc update is needed, add the skip-docs-check label.
  • I have tested the change to ensure that it works as intended.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 475d24c5-a250-49ed-b953-d2e653cb8e63

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

Copilot AI linked an issue Jul 5, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Add @mention with deep-link to node detail Add @mention support to messaging (compose autocomplete, tappable render, self-mention notification) Jul 5, 2026
Copilot AI requested a review from garthvh July 5, 2026 21:40

@RCGV1 RCGV1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a compile-blocker plus two mention handling issues that look worth fixing before this is ready. Details inline.

} else {
VStack(spacing: 0) {
if let query = mentionQuery {
MentionAutocomplete(query: query) { user in

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR currently does not compile. Running xcodebuild test -project Meshtastic.xcodeproj -scheme Meshtastic -destination 'platform=iOS Simulator,name=iPhone 17' -only-testing:MeshtasticTests/MentionParserTests fails with Cannot find 'MentionAutocomplete' in scope and Cannot find 'MentionParser' in scope. I also checked Meshtastic.xcodeproj/project.pbxproj and it has no references to MentionAutocomplete, MentionParser, or MentionParserTests, so the new source/test files are never added to the Xcode targets. Please add these files to the Meshtastic and MeshtasticTests targets; otherwise the app target fails before the mention tests can run.

enum MentionParser {

/// Pattern matching a mention token: `@!` followed by exactly 8 lowercase hex digits.
private static let mentionRegex = try! NSRegularExpression(pattern: "@!([0-9a-f]{8})")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex still matches the prefix of a longer token, e.g. @!deadbeef00 is treated as a mention of @!deadbeef, even though the documented wire format above says exactly 8 lowercase hex digits. The same prefix problem exists in containsMention via text.contains, so a malformed longer token can trigger a self-mention notification for the wrong node. Please require a non-hex/token boundary after the eighth digit, or reuse parsed bounded ranges for notification detection, and update the tooLongHex_matchesFirst8 test to reject this case.

for (range, hexId) in ranges.reversed() {
guard let num = nodeNum(from: hexId) else { continue }
let displayName = resolveDisplayName(nodeNum: num, context: context)
let link = "[@\(displayName)](meshtastic:///nodes?nodenum=\(num))"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

displayName comes from mesh data, so it can contain Markdown control characters such as ], [, (, ), or \. Interpolating it directly into Markdown link text can make AttributedString(markdown:) fail or create unintended Markdown/link structure for every message that mentions that node. Please escape the link text before interpolation, or build the attributed link without round-tripping through Markdown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add @mention with deep-link to node detail

3 participants