Skip to content

fix(composer): open @, # and : suggestions after CJK punctuation - #2768

Open
cheng-block wants to merge 2 commits into
block:mainfrom
cheng-block:cheng/fix-completion-after-cjk-punctuation
Open

cheng-block wants to merge 2 commits into
block:mainfrom
cheng-block:cheng/fix-completion-after-cjk-punctuation

Conversation

@cheng-block

@cheng-block cheng-block commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Why

Chinese and Japanese text puts no space after fullwidth punctuation, as in 你好,@alice. Typing @, # or : there never opened the mention, channel or emoji suggestions. All three queries opened only at the start of the text or after whitespace, (, [ or {.

What

The @, # and : suggestions now also open right after fullwidth and CJK punctuation.

How

  • mention-query.ts exports one TRIGGER_BOUNDARY set, and all three queries use it.
  • The set adds the 44 punctuation marks from fix(messages): stop bare links at fullwidth and CJK punctuation #2404's bare-link rule. It has no letters or digits, so a@host and 12:30 stay text.
  • Sending and rendering need no change. A picked person carries the recipient tag, and a picked channel is a link.
  • Left alone on purpose: fullwidth @ # : triggers, IME composition, and a trigger right after CJK letters (谢谢@alice).

Risk

Only when three composer menus open changes. The portable mention rules (README §2, new after_fullwidth_punctuation fixture) change too, so this needs a maintainer OK.

Testing

No manual testing beyond the in-app check.

Screenshots

Debug build of this PR: typing #cheng right after a Chinese comma opens the channel suggestions.

Composer with Chinese text, a Chinese comma and #cheng, with a channel suggestion for cheng-pr-test above it.

Debug build of this PR: typing :smi right after a Chinese comma opens the emoji suggestions.

Composer with Chinese text, a Chinese comma and :smi, with an emoji list starting with :smile: above it.

In-app check

Verified in the macOS app by Cheng.

Build: this PR at 5602a2241, merged locally with my other open PRs onto main at c037057a1, run as a debug app bundle (BUZZ_DEV_VIEWER= just desktop-bundle).

Use a test channel with a running agent, since it replies only to a real mention. Type @, # and : in English input.

  1. Type 你好,@ and the start of your agent's name. Suggestions open. Press Enter.
  2. Keep the space after the name and send. The mention shows after ,, and the agent replies.
  3. Type 看看,# and a channel name start. Pick one and send. The link opens that channel.
  4. Type 好的,:smi. Emoji suggestions open.
  5. (@, 「@, 。@, !# and 」:sm each open their menu.
  6. email@host, word#tag, 12:30 and 谢谢@ open nothing, as before.

buzz-review-completed

cheng-block and others added 2 commits November 6, 2026 00:01
Chinese and Japanese prose puts no space after fullwidth punctuation, so
你好,@alice, (@alice and 看看,#general are ordinary text. The mention,
channel and emoji queries only opened at the start of the text or after
whitespace, (, [ or {, so none of those menus opened there.

The three queries now share TRIGGER_BOUNDARY from mention-query.ts, which
adds the fullwidth and CJK punctuation that ends a bare link since block#2404.
Letters and digits still never count, so a@host and word#tag stay text.
Mention rules section 2 and its query fixtures now say the same.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Cheng Peng <cheng@block.xyz>
Co-authored-by: Cursor <cursoragent@cursor.com>
… case

The mention query test repeated the portable fixture's 你好,@ho, so that
case now lives only in the fixture. Mention rules section 2 calls the list
punctuation marks rather than fullwidth or CJK punctuation, since “”‘’… are
general punctuation. The agent help guide says the @, # and : suggestions
open right after CJK punctuation without a space.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Cheng Peng <cheng@block.xyz>
Co-authored-by: Cursor <cursoragent@cursor.com>
@tellaho

tellaho commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

🤖 Design review at 5602a2241fd8c728d48698b18f3358a76b010280: no design blocker found. People can open the existing mention, channel and emoji suggestions after CJK punctuation without inserting a space. This fits the launch bug-fix policy.

Exact-source query diagnostics matched all 13 portable query fixtures and confirmed 你好,@Ho, 看看,#ge and 好的,:sm open, while email, word fragments, times and 谢谢@ stay closed. The added composer test covers recipient inclusion after choosing a person; I inspected it but did not run it.

Evidence: shared trigger boundary, composer coverage. Fullwidth trigger characters, IME behavior and punctuation after a picked name remain outside this change.

Unchecked: native app/IME, keyboard/focus and screen-reader integration, themes, widths, enlarged text and many-agent states. No attached screenshots; no app run or package test suite in this review.

@tellaho

tellaho commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

🤖 Could you add a screenshot or short video of the change to the PR? Design uses these for faster reviews.

@cheng-block

Copy link
Copy Markdown
Contributor Author

Could you add a screenshot or short video of the change to the PR? Design uses these for faster reviews.

Added under Screenshots in the description. They come from the debug build I tested.

cheng-block added a commit that referenced this pull request Nov 11, 2026
…#2834)

## Why

Edit turns a name inside literal Markdown (HTML, link titles, reference
definitions) into a mention link, so saving changes text you never
touched. `[ref]: https://example.com "Ask @sam"` is saved as `[ref]:
https://example.com "Ask [@sam](nostr:npub1…)"`. The timeline and Copy
show those names as plain text.

`messageEditText` links every name `profileMentionParts` finds, and that
finder skips only code, links and URLs
(`src/features/messages/profile-mentions.ts:99`). The timeline drops a
name that overlaps a range from `literalRanges`
(`src/features/messages/markdown-preparation.ts:39`). Edit had no such
check.

## What

Edit now leaves a name as written when it sits inside literal Markdown,
using the timeline's ranges. Names outside literal Markdown still become
mention links.

## How

- `messageEditText` parses the text it edits (`sourceContent`, which
keeps attachment Markdown) with `scanMarkdown` and takes
`literalRanges(tree, true)`. `literalRanges` is now exported.
- It walks the ranges in order beside the names, like the timeline, so
it checks each range once.
- No second Markdown heuristic. Copy's own walk is left alone.

## Risk

Low. Only the text Edit loads changes. Recipients stay the same: an
edited message keeps the original event's `p` tags, so a name left as
text drops no one.

- Copy and the timeline read a body over 100,000 characters or 100
levels deep as plain text. Edit has no such guard, but it opens only
your own messages, and Buzz sends at most 32 KiB. Another client can
send more.
- Known limit: the timeline repairs a pasted `[Hi
@sam]\(https://example.com)` into a link and shows no mention. Edit and
Copy read it as written and still link that `@Sam`, same as on `main`.
- Out of scope: bare URL ends (#2777), suggestions after CJK punctuation
(#2768), picked name ends (#2713), `protectedTextEnd` time on unmatched
brackets.
- With #2777 merged in, this also closes the Edit limit #2777 lists:
`[ref]: https://example.com/a,@Sam` stays as written.

## Testing

- No browser cases added or removed. The change is text only.
- A one-off script compared names linked by the timeline, Copy and Edit
on 55 bodies. All three agree on 54; the other is the known limit. On
`main`, Edit linked more than Copy on 20.
- The 8 new Edit test texts pass through the composer's load and save
helpers unchanged.
- `messageEditText` runs once when Edit opens (Node and jsdom, median of
five runs). A body that alternates names and code spans took about 72 ms
at 16,000 characters and 270 ms at 32 KiB before the in-order check.
After it, 8 ms and 16 ms.

## Screenshots

Debug build of this PR: Edit shows the real mention as a chip and leaves
`@BeeBee` inside the span title as plain text.

<img width="760" alt="Composer in Editing message mode with Hi `@BeeBee`
on line one and a literal span tag with title \"`@BeeBee`\" below."
src="https://github.com/user-attachments/assets/26434d42-f342-4007-a9b3-382d1627742e"
/>

After saving, the message keeps the real mention and the literal span
exactly as written.

<img width="744" alt="Edited message reading Hello with a BeeBee mention
chip and the literal span tag below."
src="https://github.com/user-attachments/assets/4abdf2a0-6162-482c-84ca-c90f24f445a0"
/>

## In-app check

Verified in the macOS app by Cheng.

Build: this PR at `bcc62911e`, merged locally with my other open PRs
onto `main` at `c037057a1`, run as a debug app bundle. Later commits
only merge `main`.

Use a test channel with a person or agent in it. The steps call them
Name.

1. Type `Hi @`, pick Name, press Shift+Enter twice, then paste `<span
title="@name">hi</span>` with their exact name. Send.
2. The message shows `Hi`, the mention, then `<span
title="@name">hi</span>` as typed.
3. Open Edit. The second line still reads `<span
title="@name">hi</span>`. On `main`, Edit put a profile link inside the
quotes.
4. Change `Hi` to `Hello` and save. The message shows `Hello`, the
mention, and the same `<span>` line.

buzz-review-completed

---------

Signed-off-by: Cheng Peng <cheng@block.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

This branch has not been deployed

No deployments
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.

2 participants