Parse and linkify NomadNet page addresses in chat - #38
Conversation
Detect bare NomadNet page addresses (<32-hex-hash>:/path.mu, optionally followed by a backtick `field=value|... query tail) in message bodies and render them as tappable links alongside http(s) URLs. Tapping fires an ACTION_VIEW intent for nomadnetwork://<address>, handed off to an installed NomadNet-capable app (Columba, Sideband); with no handler installed we toast instead of crashing. - New pure ChatLinks.kt: unified web + NomadNet link detection with overlap resolution (NOMADNET_ADDRESS regex + toNomadNetUri()). - ChatScreen LinkifiedText/buildMessageBody render NomadNet spans as a tappable LinkAnnotation.Clickable; http(s) links keep LinkAnnotation.Url. - ChatLinksTest covers the address regex, the backtick field tail, bare-hash rejection, and web/NomadNet coexistence. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR adds detection and tap-to-open support for bare NomadNet page addresses in chat message bodies, bringing parity with Columba's link handling. A new
Confidence Score: 5/5Safe to merge — the change is additive, confined to the chat render path, and carries no risk of data loss or crashes beyond the already-guarded intent dispatch. The regex logic is sound and verified by 12 dedicated unit tests. Overlap resolution in detectChatLinks is greedy and provably correct. The ActivityNotFoundException guard prevents crashes on devices without a NomadNet app. The remember keying in LinkifiedText correctly invalidates the cached AnnotatedString when context changes. No pre-existing paths are altered beyond the URL-detection loop, which is a straight refactor with equivalent cursor accounting. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant LinkifiedText
participant detectChatLinks
participant buildMessageBody
participant openNomadNetLink
participant ExternalApp
User->>LinkifiedText: compose message with NomadNet address
LinkifiedText->>detectChatLinks: text
detectChatLinks-->>LinkifiedText: "List<ChatLink> (WEB + NOMADNET, overlap-resolved)"
LinkifiedText->>buildMessageBody: text, links, nomadnetListener
buildMessageBody-->>LinkifiedText: AnnotatedString (LinkAnnotation.Url / Clickable spans)
User->>LinkifiedText: tap NomadNet link span
LinkifiedText->>openNomadNetLink: nomadnetwork://hash:/path URI
alt NomadNet app installed
openNomadNetLink->>ExternalApp: ACTION_VIEW intent
else no handler
openNomadNetLink-->>User: Toast "No NomadNet app installed"
end
Reviews (2): Last reviewed commit: "address greptile review feedback (greplo..." | Re-trigger Greptile |
- detectChatLinks no longer returns its internal working list for the 0/1-candidate case; the dedup loop now handles those too, so callers always get a freshly-built result list. - Extract the web-URL trailing-trim into a shared, tested helper splitWebUrlTrailing() in ChatLinks.kt (with URL_TRAILING_TRIM), used by buildMessageBody; adds pinning tests for the trim behaviour. (The "No NomadNet app installed" Toast string is left inline to match the codebase, which hardcodes all user-facing Toast strings.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Detect bare NomadNet page addresses in chat message bodies and render them as tappable links alongside http(s) URLs — parity with Columba's chat link handling.
On-wire format (no
nomadnetwork://scheme):<32-hex-hash>:/page/path.mu, optionally followed by a backtick field/query tail, e.g.Behaviour
ChatLinks.ktdoes unified web + NomadNet detection with overlap resolution.NOMADNET_ADDRESSmatches<hash>:/pathincluding the backtick=/|field tail; a bare 32-hex hash with no:/pathis deliberately not linkified (those are commonly pasted destination hashes).ACTION_VIEWintent fornomadnetwork://<address>, handled by an installed NomadNet-capable app (Columba, Sideband). With no handler installed we toast instead of crashing. Web links keepLinkAnnotation.Url→ system browser.Tests
ChatLinksTest(10): the address regex, the backtick field tail (the exact on-wire query form), bare-hash rejection, trailing-punctuation trimming, and web/NomadNet coexistence. Full:appunit suite green.Companion PR
The receiving side (Columba) had a bug parsing these field params on deep-link entry — fixed in torlando-tech/columba#998.
🤖 Generated with Claude Code