Skip to content

Conversation

@alltheseas
Copy link
Collaborator

@alltheseas alltheseas commented Dec 15, 2025

Summary

  • Fixed NIP-19 nostr links (nprofile, npub, note, nevent, naddr) not rendering as clickable mentions in longform content
  • Links now display human-readable profile names when available, falling back to abbreviated bech32 format (npun123; nprofile123)
  • Supports both nostr: prefixed URIs and bare bech32 entities for consistency with kind1 notes

Checklist

Standard PR Checklist

  • I have read (or I am familiar with) the Contribution Guidelines
  • I have tested the changes in this PR
  • I have profiled the changes to ensure there are no performance regressions, or I do not need to profile the changes.
    • Not needed: This is text preprocessing with simple regex operations, no significant performance impact
  • I have opened or referred to an existing github issue related to this change:
    - [x] My PR is either small, or I have split it into smaller logical commits that are easier to review
  • I have added the signoff line to all my commits. See Signing off your work
  • I have added appropriate changelog entries for the changes in this PR. See Adding changelog entries
  • I have added appropriate Closes: or Fixes: tags in the commit messages wherever applicable, or made sure those are not needed. See Submitting patches

Test report

Device: iPhone 15 Pro (Simulator)

iOS: 18.0

Damus: Current master + this PR

Setup: Longform article containing nprofile, npub, note, and nevent mentions both with and without nostr: prefix

Steps:

  1. Open a longform article (kind 30023) containing nostr:nprofile mentions
  2. Verify mentions render as clickable links with profile names
  3. Test bare npub/nprofile without nostr: prefix
  4. Verify fallback display when profile not cached (shows @npub1abc:xyz format)
  5. Run unit tests: xcodebuild test -scheme damus -destination 'platform=iOS Simulator,name=iPhone 15 Pro'

Results:

  • PASS

Other notes

This fix addresses issue #3426 where nostr:nprofile links in longform articles were rendering as plain text instead of clickable mentions.

The implementation preprocesses markdown content before passing to MarkdownUI, converting nostr entities into standard markdown link syntax that MarkdownUI can render. Profile display names are looked up from the cache, with a fallback to abbreviated bech32 format (e.g., @npub1abc:xyz) when the profile isn't available.

🤖 Generated with Claude Code

MarkdownUI doesn't natively understand the nostr: URI scheme, causing
nprofile/npub/note/nevent/naddr links to render as plain text in
longform articles (kind 30023).

This adds preprocessing that converts nostr entities into markdown link
syntax before passing to MarkdownUI:
- nostr:nprofile1... → [@DisplayName](damus:nostr:nprofile1...)
- nostr:npub1... → [@DisplayName](damus:nostr:npub1...)
- nostr:note1... → [@note1abc:xyz](damus:nostr:note1...)

Key implementation details:

1. preprocessNostrLinksInMarkdown() runs two regex passes:
   - First pass: converts nostr:-prefixed URIs (nostr:npub1...)
   - Second pass: converts bare bech32 entities (npub1...)

   Negative lookbehinds prevent double-processing existing links.

2. getNostrLinkDisplayString() determines display text:
   - For npub/nprofile: looks up profile name, falls back to abbreviated
     bech32 (e.g., @npub1abc:xyz) when not cached
   - For note/nevent/naddr: always uses abbreviated bech32

3. getProfileDisplayNameIfFound() helper returns nil when profile isn't
   cached, allowing callers to fall back to bech32 format.

4. Updated mention_str() to use the same fallback logic for consistency
   between kind1 notes and longform content.

This matches the behavior of kind1 notes where users can paste bare
npub/nprofile identifiers and they're automatically rendered as
clickable profile mentions.

Closes: damus-io#3426

Changelog-Fixed: Fixed NIP-19 nostr links (nprofile, npub, note, nevent) not rendering in longform content

Signed-off-by: alltheseas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@alltheseas
Copy link
Collaborator Author

before PR

image

after PR

image

@danieldaquino danieldaquino added the pr-in-queue This PR is waiting in a queue behind their other PRs marked with the label `pr-active-review`. label Dec 15, 2025
@alltheseas
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

Warning

Rate limit exceeded

@alltheseas has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 50 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between d3a5445 and 29be3f7.

📒 Files selected for processing (3)
  • damus/Features/Events/Models/NoteContent.swift
  • damusTests/NIP19Tests.swift
  • damusTests/NoteContentViewTests.swift

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

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

Labels

longform pr-in-queue This PR is waiting in a queue behind their other PRs marked with the label `pr-active-review`.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants