Skip to content

fix(composer): scope multiline block formatting - #3246

Merged
tellaho merged 8 commits into
mainfrom
tho/composer-block-formatting
Jul 28, 2026
Merged

fix(composer): scope multiline block formatting#3246
tellaho merged 8 commits into
mainfrom
tho/composer-block-formatting

Conversation

@tellaho

@tellaho tellaho commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Category: fix
User Impact: Composer block formatting now applies to the intended line or selection without collapsing multiline content.

Problem: Block formatting from a Shift+Enter line could convert the entire draft, selected visual lines could collapse into one list item, and code conversion could lose line breaks. Solution: Scope caret formatting to its hard-break-delimited line and normalize explicit selections for the destination block type while preserving neighboring content and visual line boundaries.

File changes

desktop/src/features/messages/lib/selectionBlockFormatting.ts
Scopes collapsed-caret block actions to the active visual line and normalizes multiline selections for lists and code blocks.

desktop/src/features/messages/lib/selectionBlockFormatting.test.mjs
Adds unit coverage for caret-line isolation across line positions and selection directions.

desktop/src/features/messages/ui/FormattingToolbar.tsx
Routes list, quote, and code-block actions through the selection-aware formatting transaction.

desktop/tests/e2e/composer-selection-formatting.spec.ts
Covers caret-only formatting, multiline list conversion, list-to-code conversion, preserved hard breaks, Markdown output, and backward selections.

Reproduction steps

  1. In the desktop composer, enter several lines using Shift+Enter and place the caret on one line.
  2. Apply a bullet list, ordered list, quote, or code block; only the caret line should change.
  3. Select several Shift+Enter lines and apply a list; each visual line should become its own item.
  4. Select several list items and apply Code block; they should become one multiline code block while unselected neighbors remain intact.
  5. Select several Shift+Enter lines and apply Code block; each line break should remain visible.

Screenshots/Demos

Screen Recording 2026-07-27 at 5 29 19 PM

Expected multiline code-block result: https://buzz.block.builderlab.xyz/media/d2e2668093af3b67d896a32e9799daccd236da9fc9e24ec56ddb4ebf7d01dd96.png

npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w and others added 2 commits July 27, 2026 17:07
Block-format toolbar buttons (bullet list, ordered list, quote, code
block) reformatted the entire draft when clicked with a collapsed caret,
because Shift+Enter lines are hardBreak nodes inside one paragraph and
ProseMirror block toggles operate on whole textblocks.

Extend isolateSelectionForBlockFormatting so a collapsed caret isolates
its hard-break-delimited line — replacing the bordering hard breaks with
block splits — before the toggle runs, keeping isolation and toggle one
undoable transaction. Route the quote button through the same isolation
path it previously skipped.

Explicit selections keep their existing behavior: format only the
selected lines.

Adds unit coverage for the caret-line isolation and E2E coverage for
caret-only formatting (new line, middle line, serialized Markdown) plus
quote in the selection matrix.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Split selected hard-break lines before list wrapping so each visual line becomes its own item. Merge selected textblocks into one code block while preserving visual line breaks, unselected list neighbors, and caret-only behavior.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho
tellaho marked this pull request as ready for review July 28, 2026 00:30
@tellaho
tellaho requested a review from a team as a code owner July 28, 2026 00:30
@tellaho
tellaho enabled auto-merge (squash) July 28, 2026 00:32

@wpfleger96 wpfleger96 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.

🤖 Thanks for the fix — the caret-line isolation is nicely done (first/middle/last/empty trailing lines all covered, backward selections restored, single undo unit) and the serialized-Markdown e2e assertions are the right end-to-end check.

That said, we found two selection shapes where unselected content gets structurally reformatted, plus a branch that I think defeats the toolbar's own WKWebView selection workaround, so requesting changes. Details inline on the relevant lines.

A couple of non-blocking notes while you're in here:

  • selectionBlockFormatting.test.mjs only covers isolateSelectionForBlockFormattingsplitSelectedLinesForListFormatting and mergeSelectedTextblocksIntoCodeBlock are e2e-only. They're pure transaction logic so unit cases should be cheap to add.
  • textblockTextForCode() drops any leaf node that doesn't implement leafText, so mentions/custom emoji could silently disappear when converted to code. Probably fine as a contract, but worth a unit case or a comment saying it's intentional.

Comment thread desktop/src/features/messages/lib/selectionBlockFormatting.ts Outdated
Comment thread desktop/src/features/messages/ui/FormattingToolbar.tsx Outdated
Comment thread desktop/src/features/messages/ui/FormattingToolbar.tsx Outdated
npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w and others added 6 commits July 27, 2026 22:13
Normalize exact textblock boundary selections inward before isolation and collect selected textblocks from the exact range so visually unselected endpoint blocks are not reformatted.

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho

tellaho commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@wpfleger96 We also closed out both non-blocking notes from your review:

  • 21987a8d2fb772be2580933f53762b8f6dc0d925 preserves meaningful inline-atom text during code-block conversion, documents the fallback semantics, and adds focused unit coverage for schema leafText, mention labels, custom-emoji shortcodes, hard breaks, and safe dropping of unknown leaves.
  • fb91387616f93e38eda66f7e6c410f255614195f tightens the partial-list Playwright regression to assert exact top-level structure, item contents, and preserved neighbors for code, bullet, ordered, and quote outcomes.

Validated with 3,731 desktop unit tests, typecheck/check, and focused composer Playwright 24/24.

— AI-generated response on behalf of Taylor Ho

@tellaho
tellaho requested a review from wpfleger96 July 28, 2026 15:41
@tellaho
tellaho merged commit 5457c94 into main Jul 28, 2026
47 of 49 checks passed
@tellaho
tellaho deleted the tho/composer-block-formatting branch July 28, 2026 17:31
LordMelkor added a commit to LordMelkor/buzz that referenced this pull request Jul 28, 2026
* origin/main:
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
  feat(chart): add relay pod extension points (block#3322)
  Refine mobile attachment picking (block#3313)
  Polish mobile message and search layouts (block#3121)
  Add mobile message image galleries (block#3312)

Signed-off-by: LordMelkor <kray@squareup.com>
tlongwell-block pushed a commit that referenced this pull request Jul 28, 2026
* origin/main:
  fix(desktop): paint community rail full height (#3382)
  fix(acp): disable goose cron scheduler in managed agent children (#3144)
  feat(desktop): add custom harness inline from agent dialogs (#3252)
  chore(compose): remove stale typesense env vars (#3332)
  feat(desktop): refine agent catalog sharing (#2439)
  fix(desktop): keep drafts out of the Inbox All view (#3217)
  docs: restructure DCO guidance into scannable subsection (#3337)
  Unify mobile loading spinners (#3314)
  fix(desktop): restore the inbox icon in the sidebar (#3341)
  fix(desktop): gate codex-acp on a minimum supported version (#3254)
  feat(cli): add users set-status command for NIP-38 profile status (#3253)
  fix(composer): scope multiline block formatting (#3246)
  feat(chart): add relay pod extension points (#3322)
  Refine mobile attachment picking (#3313)
  Polish mobile message and search layouts (#3121)
  Add mobile message image galleries (#3312)

Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>

# Conflicts:
#	desktop/src-tauri/src/commands/personas/snapshot/import.rs
#	desktop/src-tauri/src/managed_agents/agent_snapshot.rs
#	desktop/src/features/agents/ui/AgentSnapshotImportDialog.tsx
dophsquare pushed a commit to sailt-k/buzz that referenced this pull request Jul 28, 2026
Pull in nostr 0.44.6 (patched NIP-44 v2 DoS advisory) to clear the
Security/cargo-deny failure. No conflicts.

Co-authored-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>
Signed-off-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>

* origin/main: (74 commits)
  chore(ci): bump desktop smoke E2E timeout to 30 minutes (block#3409)
  release(chart): publish 0.1.7 (block#3393)
  feat(acp): steer claude-code and codex agents via _session/steering (block#3007)
  feat(desktop): apply WebKit rendering workarounds at startup on Linux (block#3271)
  fix(desktop): stabilize flaky DM expansion E2E ordering assertions (block#2004)
  docs(contributing): document the Linux system libraries just ci requires (block#3396)
  fix(desktop): paint community rail full height (block#3382)
  fix(acp): disable goose cron scheduler in managed agent children (block#3144)
  feat(desktop): add custom harness inline from agent dialogs (block#3252)
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
  feat(chart): add relay pod extension points (block#3322)
  Refine mobile attachment picking (block#3313)
  ...
dophsquare pushed a commit to SHL0MS/buzz that referenced this pull request Jul 28, 2026
Co-authored-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>
Signed-off-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>

* origin/main:
  chore(ci): bump desktop smoke E2E timeout to 30 minutes (block#3409)
  release(chart): publish 0.1.7 (block#3393)
  feat(acp): steer claude-code and codex agents via _session/steering (block#3007)
  feat(desktop): apply WebKit rendering workarounds at startup on Linux (block#3271)
  fix(desktop): stabilize flaky DM expansion E2E ordering assertions (block#2004)
  docs(contributing): document the Linux system libraries just ci requires (block#3396)
  fix(desktop): paint community rail full height (block#3382)
  fix(acp): disable goose cron scheduler in managed agent children (block#3144)
  feat(desktop): add custom harness inline from agent dialogs (block#3252)
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
  feat(chart): add relay pod extension points (block#3322)
  Refine mobile attachment picking (block#3313)
dophsquare pushed a commit to linxule/buzz that referenced this pull request Jul 28, 2026
Co-authored-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>
Signed-off-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>

* origin/main:
  chore(ci): bump desktop smoke E2E timeout to 30 minutes (block#3409)
  release(chart): publish 0.1.7 (block#3393)
  feat(acp): steer claude-code and codex agents via _session/steering (block#3007)
  feat(desktop): apply WebKit rendering workarounds at startup on Linux (block#3271)
  fix(desktop): stabilize flaky DM expansion E2E ordering assertions (block#2004)
  docs(contributing): document the Linux system libraries just ci requires (block#3396)
  fix(desktop): paint community rail full height (block#3382)
  fix(acp): disable goose cron scheduler in managed agent children (block#3144)
  feat(desktop): add custom harness inline from agent dialogs (block#3252)
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
dophsquare pushed a commit to bhargavms/buzz that referenced this pull request Jul 28, 2026
Co-authored-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>
Signed-off-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>

* origin/main: (111 commits)
  chore(ci): bump desktop smoke E2E timeout to 30 minutes (block#3409)
  release(chart): publish 0.1.7 (block#3393)
  feat(acp): steer claude-code and codex agents via _session/steering (block#3007)
  feat(desktop): apply WebKit rendering workarounds at startup on Linux (block#3271)
  fix(desktop): stabilize flaky DM expansion E2E ordering assertions (block#2004)
  docs(contributing): document the Linux system libraries just ci requires (block#3396)
  fix(desktop): paint community rail full height (block#3382)
  fix(acp): disable goose cron scheduler in managed agent children (block#3144)
  feat(desktop): add custom harness inline from agent dialogs (block#3252)
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
  feat(chart): add relay pod extension points (block#3322)
  Refine mobile attachment picking (block#3313)
  ...
dophsquare pushed a commit to darox/buzz that referenced this pull request Jul 28, 2026
Co-authored-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>
Signed-off-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>

* origin/main: (84 commits)
  chore(ci): bump desktop smoke E2E timeout to 30 minutes (block#3409)
  release(chart): publish 0.1.7 (block#3393)
  feat(acp): steer claude-code and codex agents via _session/steering (block#3007)
  feat(desktop): apply WebKit rendering workarounds at startup on Linux (block#3271)
  fix(desktop): stabilize flaky DM expansion E2E ordering assertions (block#2004)
  docs(contributing): document the Linux system libraries just ci requires (block#3396)
  fix(desktop): paint community rail full height (block#3382)
  fix(acp): disable goose cron scheduler in managed agent children (block#3144)
  feat(desktop): add custom harness inline from agent dialogs (block#3252)
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
  feat(chart): add relay pod extension points (block#3322)
  Refine mobile attachment picking (block#3313)
  ...
dophsquare pushed a commit to skyerus/buzz that referenced this pull request Jul 28, 2026
Co-authored-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>
Signed-off-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>

* origin/main: (111 commits)
  chore(ci): bump desktop smoke E2E timeout to 30 minutes (block#3409)
  release(chart): publish 0.1.7 (block#3393)
  feat(acp): steer claude-code and codex agents via _session/steering (block#3007)
  feat(desktop): apply WebKit rendering workarounds at startup on Linux (block#3271)
  fix(desktop): stabilize flaky DM expansion E2E ordering assertions (block#2004)
  docs(contributing): document the Linux system libraries just ci requires (block#3396)
  fix(desktop): paint community rail full height (block#3382)
  fix(acp): disable goose cron scheduler in managed agent children (block#3144)
  feat(desktop): add custom harness inline from agent dialogs (block#3252)
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
  feat(chart): add relay pod extension points (block#3322)
  Refine mobile attachment picking (block#3313)
  ...
dophsquare pushed a commit to arisgysel-design/buzz that referenced this pull request Jul 28, 2026
Co-authored-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>
Signed-off-by: Phuoc (Phu) Do <91568955+dophsquare@users.noreply.github.com>

* origin/main: (126 commits)
  chore(ci): bump desktop smoke E2E timeout to 30 minutes (block#3409)
  release(chart): publish 0.1.7 (block#3393)
  feat(acp): steer claude-code and codex agents via _session/steering (block#3007)
  feat(desktop): apply WebKit rendering workarounds at startup on Linux (block#3271)
  fix(desktop): stabilize flaky DM expansion E2E ordering assertions (block#2004)
  docs(contributing): document the Linux system libraries just ci requires (block#3396)
  fix(desktop): paint community rail full height (block#3382)
  fix(acp): disable goose cron scheduler in managed agent children (block#3144)
  feat(desktop): add custom harness inline from agent dialogs (block#3252)
  chore(compose): remove stale typesense env vars (block#3332)
  feat(desktop): refine agent catalog sharing (block#2439)
  fix(desktop): keep drafts out of the Inbox All view (block#3217)
  docs: restructure DCO guidance into scannable subsection (block#3337)
  Unify mobile loading spinners (block#3314)
  fix(desktop): restore the inbox icon in the sidebar (block#3341)
  fix(desktop): gate codex-acp on a minimum supported version (block#3254)
  feat(cli): add users set-status command for NIP-38 profile status (block#3253)
  fix(composer): scope multiline block formatting (block#3246)
  feat(chart): add relay pod extension points (block#3322)
  Refine mobile attachment picking (block#3313)
  ...
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