mirror of
https://github.com/block/buzz.git
synced 2026-11-06 01:11:33 +00:00
codex/buzz-271-draft-prep
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
54ca2a3cc6 |
fix(mobile): render Markdown backslash escapes (#8925)
Mobile showed Markdown backslash escapes literally. A message linking a channel as `[\#buzz-mobile](buzz://channel/…)` rendered as `\#buzz-mobile`, and `\[text\]` rendered as LaTeX math. gpt_markdown has no backslash escapes. Outside code, each escaped ASCII punctuation character is now held as a stand-in (an invisible word joiner plus the character's fullwidth form) before parsing, so no other syntax (links, emphasis, mentions, channel tokens, math) matches it. A new inline component and the link and image builders restore the original character. The inbox/search preview builder already handled escapes this way; its helpers moved to a shared `markdown_escapes.dart`. Two edge cases found in review are covered: shielding runs after trailing-gallery extraction so carousel URLs and labels stay as authored, and a bare link no longer takes a trailing backslash into its destination. Codex review added: escaped backticks stay literal instead of opening code, authored word joiners are not mistaken for stand-ins, Buzz URL punctuation peeling keeps a trailing backslash, gallery semantic labels drop escapes, the trailing-backslash peel is linear and reruns after delimiter stripping, an escaped `\<url>` is not treated as an autolink, `~~~` fences are skipped like backtick fences, an autolink containing `\` keeps it in both label and destination, and the stand-ins use fullwidth characters so the one gpt_markdown fallback that shows raw text (multi-line strikethrough) still reads right. Later review: fence detection looks back only over blanks and `>` markers, so it stays linear on long lines (security review) and treats an unclosed fence inside a quote or list as code, like the renderer (Carl). Behavior change: `\(x\)` and `\[x\]` now show as `(x)` and `[x]` instead of math, per CommonMark. Desktop (buzz-app) doesn't render math either. `$…$` math is unchanged. ### Validation - Added tests: a `MessageContent` table covering escapes in prose, bold, link labels (HTTP and `buzz://channel`), fenced and inline code (left literal), a bare link ending in `\`, and escaped backticks, authored word joiners and fullwidth characters, a `~~~` fence, a multi-line strikethrough, `<https://example.com/a\>`, a Buzz URL ending in `.\`, an emphasized bare URL ending in `\*`, an escaped `\<url>`, and a trailing image gallery with escaped labels (including its semantics label), in plain and bubble layouts. Each row also asserts no stand-in reaches visible text or semantics. Reverting any one of these fixes fails it. - `flutter analyze` is clean and the full mobile suite passes, except for 11 `notification_toggle_test.dart` tests. Those fail locally on the Studio at the CI-green |
||
|
|
20742a236d |
fix(mobile): only render known channels as #channel chips (#8862)
Follows [#8860](https://github.com/block/buzz/pull/8860) (merged). On mobile, any `#token` rendered as a channel chip, so GitHub-style references like `#8700` turned into inert chips for channels that don't exist. Desktop already avoids this by only linking names in the known channel list. This makes mobile's message body and one-line preview do the same. With no known names (channels still loading, or none visible), nothing becomes a chip. An open channel the reader hasn't joined stays plain text until the directory has loaded; before this change it was an inert, untappable chip. messages rebuild with chips once channel names arrive. Unlike desktop, there's no "any `#token` while empty" fallback, because an empty map can't distinguish loading from an account with no visible channels. The known names come from the existing `channelIdsByNameProvider` (the reader's channels, plus open directory channels once Browse channels or invite recovery has loaded the directory), so there is no new fetch, subscription or sync change. When the list is non-empty, the regex has one alternative fewer than before. ### Validation Added tests: - Preview: `#8700`, `#8774's`, a known-name prefix (`#gen` vs `general`) and `#eng-ios` with only `eng` known stay text, while `#general` and a longer known `#eng-ios` are chips. With no channel names, nothing chips. - Message body: `Took over #8700 from #general` renders one chip (`general`) and keeps `#8700` as text. - Message body: with no channel names, `#unknown` stays text. The new assertions fail with the previous always-generic pattern. The full mobile test suite passed in pre-push. Simulator render on an iPhone 18 Pro (iOS 27): real message-body and preview widgets with channels `general` and `eng` loaded, rendered with both stacked PRs applied. | Before (`main`) | After ([#8860](https://github.com/block/buzz/pull/8860) + [#8862](https://github.com/block/buzz/pull/8862)) | | --- | --- | | <img src="https://raw.githubusercontent.com/block/buzz/5afead6a162d5c8554ad17175fc2dccff93bf2af/pr-8862--01-before-main.png" width="300"> | <img src="https://raw.githubusercontent.com/block/buzz/5afead6a162d5c8554ad17175fc2dccff93bf2af/pr-8862--02-after-both-prs.png" width="300"> | Human app test: not applicable under the mobile-client testing exception; agent review and simulator validation above. buzz-review-completed 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Tom Brow <tomb@squareup.com> Co-authored-by: Tom Brow <tomb@squareup.com> |
||
|
|
b80217de32 |
fix(mobile): end #channel tokens at apostrophes, quotes and dashes (#8860)
Mobile renders `#channel` tokens as chips, but a token followed by an apostrophe, quote, ellipsis or dash stayed plain text: `#general's`, `"#general"`, `#general…` and `#general—` all lost their chip because the token only ended at whitespace or `, ; . ! ? : ) ] }`. This ends channel tokens at those characters too (`' " ‘ ’ “ ” » … – —`). The message body and the one-line preview each had their own copy of the channel regex; they now share one `channelTokenPattern`, so they can't drift apart again. `@mention` boundaries are unchanged on purpose: on mobile and desktop the same boundary also decides which mentions are bound and tagged when sending, so changing it is a separate, cross-surface decision. ### Validation Added tests: - Preview table covering each new trailing character (and matching opening quotes). - Message body: `#general's` keeps the chip and renders the `'s` suffix. Both fail with the previous boundary. The full mobile test suite passed in pre-push. Simulator render on an iPhone 18 Pro (iOS 27): real message-body and preview widgets with channels `general` and `eng` loaded, rendered with both stacked PRs applied. | Before (`main`) | After ([#8860](https://github.com/block/buzz/pull/8860) + [#8862](https://github.com/block/buzz/pull/8862)) | | --- | --- | | <img src="https://raw.githubusercontent.com/block/buzz/5afead6a162d5c8554ad17175fc2dccff93bf2af/pr-8862--01-before-main.png" width="300"> | <img src="https://raw.githubusercontent.com/block/buzz/5afead6a162d5c8554ad17175fc2dccff93bf2af/pr-8862--02-after-both-prs.png" width="300"> | Human app test: not applicable under the mobile-client testing exception; agent review and simulator validation above. buzz-review-completed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Tom Brow <tomb@squareup.com> Co-authored-by: Tom Brow <tomb@squareup.com> |
||
|
|
be1ac392e8 |
perf(mobile): render inbox and search previews as plain text (#8675)
### Summary Inbox rows and search results show each message as a 2-line preview. That preview was a capped `MessageContent`, so gpt_markdown parsed and laid out the whole source (syntax-highlighted code blocks and measured tables included), even though only two lines are painted. A native trace on an iPhone 12 mini attributed a 102 ms inbox-open frame mostly to this work. Previews now skip Markdown entirely. `messagePreviewSource` takes only the leading lines a preview can show, and at most the first 4,000 characters of a single long line, so link normalization, mention binding and emoji lookup never scan the rest of a long message. `messagePreviewPieces` is then a linear pass over those lines, similar to desktop's `getMarkdownPreviewText`. It drops block syntax (headings, quotes, list markers, rules, table dividers, code fences) and unwraps inline emphasis and `<u>`, honoring backslash escapes and keeping inline (including multi-backtick) and fenced code as literal text. It also replaces links with their label. The new `MessagePreview` widget renders the result as a single `Text.rich` with `maxLines` and an ellipsis. Tokens keep the look they have in the thread view: - A bound mention is the same `MessageMentionPill` chip, with the bot icon for agents. An ambiguous mention stays as text. - `#channel` tokens and `buzz://channel/...` links are the same channel token chip. - A `buzz://message`, repo, PR or issue link that shows its own URL previews with the thread view's short label, such as `general · abcdef01`. Both use the shared `buzzLinkLabel` helper. - Custom emoji render as inline images. Only shortcodes the message names are looked up in the palette. - Media links show as "Image", "Video" or "Audio". Chips in previews are not tappable, and tapping the row opens the message. Bold, italic, inline code and link styling are no longer shown in previews. The timeline and thread view are unchanged, and so is the profile status line, which still uses `MessageContent`. This replaces this PR's earlier approach of cutting the Markdown source before parsing. That approach needed delimiter-balance heuristics, and a security review found a real case (`**` inside a link label) where the heuristic misfired. ### Validation - `preview_text_test.dart` is a table test of the parser: block syntax, emphasis that must and must not unwrap (`snake_case`, a lone `*`), inline and fenced code, unpaired backticks, links, tables, the line limit and the long-line cap. It also covers mentions (bound, ambiguous, inside emphasis, link labels and code), custom emoji (including adjacent `🅰️b:`), channel tokens and links, message and repo link labels, and media. The long-line row also asserts that `messagePreviewSource` returns a bounded prefix. - `message_preview_test.dart` checks the widget: no `GptMarkdown`, one capped and ellipsized paragraph, mention chip, custom emoji image, channel chip, media label and empty content. - Existing inbox and search tests updated to find `MessagePreview`, including the agent-chip test in search. - `flutter analyze` and the full mobile test suite pass at |
||
|
|
1ac0a1271b |
fix(mobile): preserve Markdown attachment destinations (#8168)
## Summary Fix mobile “Image unavailable” errors caused by angle-bracketed Markdown URLs. Preserve attachment destinations across images, galleries, videos, and file links, including spaces, parentheses, and optional titles. ### Related issue Related: #8086 (attachment filenames). ### Testing - `just mobile-install mobile-check mobile-test` - Regression coverage decodes PNG/JPEG/GIF/WebP/BMP and verifies gallery viewers, video routing, and authenticated file links. - Native device playback not tested. --------- Signed-off-by: kenny lopez <klopez4212@gmail.com> |
||
|
|
5ddf23d700 |
feat(mobile-messages): render compact Buzz permalink chips (#5639)
**Category:** improvement **User Impact:** Buzz channel, message, repository, pull request, and issue links now display recognizable context and navigate reliably in the mobile app. **Problem:** Bare Buzz permalinks appeared as raw or ambiguous URLs on mobile, while channel and message links were not handled consistently across Markdown forms and startup states. **Solution:** Normalize eligible bare Buzz URLs without consuming Markdown syntax, render them as semantic icon-prefixed chips, and route channel/message targets through the mobile deep-link dispatcher while preserving authored Markdown labels as ordinary links. <details> <summary>File changes</summary> **mobile/lib/features/channels/deep_link_dispatcher.dart** Routes parsed channel and message links through the appropriate in-app navigation callbacks. **mobile/lib/features/channels/message_content.dart** Presents all bare Buzz permalinks as semantic icon chips and keeps authored labels as ordinary links. **mobile/lib/features/channels/message_content/link_normalizer.dart** Normalizes bare and autolinked Buzz URLs without consuming Markdown delimiters, code, or punctuation. **mobile/lib/shared/deeplink/deep_link.dart** Adds strict channel and project-entity parsing alongside message deep links. **mobile/lib/shared/deeplink/pending_deep_link_provider.dart** Preserves pending navigation until the mobile routing surface is ready. **mobile/test/features/channels/channel_detail_page_test.dart** Updates navigation integration coverage for icon-prefixed channel chips. **mobile/test/features/channels/deep_link_dispatcher_test.dart** Covers channel/message dispatch and missing-target behavior. **mobile/test/features/channels/message_content/link_normalizer_test.dart** Exercises Markdown-safe normalization across the full Buzz link suite. **mobile/test/features/channels/message_content_test.dart** Verifies chip labels, icons, semantics, authored-label opt-out, and navigation callbacks. **mobile/test/shared/deeplink/deep_link_test.dart** Covers strict parsing for channel, message, repository, pull-request, and issue links. </details> ## Reproduction steps 1. Run the mobile app and open a channel containing bare `buzz://channel`, `buzz://message`, `buzz://repo`, `buzz://pr`, and `buzz://issue` URLs. 2. Confirm each bare URL renders as one cohesive chip with a type icon, a useful name or shortened identifier, and no duplicated channel `#` character. 3. Add an authored Markdown link such as `[design discussion](buzz://issue?...)` and confirm the supplied label remains an ordinary link rather than becoming a chip. 4. Select channel and message links and confirm they navigate correctly from inline and autolinked forms. ## Screenshots / demos **iOS Simulator — channel, message, repository, pull request, and issue permalink chips** Real app build (`37b2cb5eb`) running on an iPhone 17 Pro simulator.  --------- Signed-off-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz> Co-authored-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> |