Repository navigation
Conversation
…unds
## Description
The Rune and GPUI playgrounds drew every block as a plain paragraph, read
only paragraphs at the root, and had no way to make a heading, quote, list
or link, though lexical-editor now has rich-text, list and link.
`lexical-playground-core` now:
- reads the tree recursively: list items with their list's type, depth,
number and `checked`, headings, quotes, indents, and links' text runs with
their URL; selection points map through undrawn elements (the root, lists),
and the tree view shows lists above their items;
- registers rich-text, list, check list and link in the session, and sends
Enter, Shift-Enter and formatting as the commands a browser dispatches;
- adds `set_block_type` (lists through their commands, the same list again
makes paragraphs; other types through `$setBlocksType`), `indent`, `tab`
(`$indentOverTab`), `toggle_link`, `toggle_checked`, `block_type_at`,
`link_at` and `format_at`;
- gives the selection the format a browser's `selectionchange` gives it
(`onSelectionChange`: a caret takes its text node's format and style, a
range the format all its text shares) in the select step before an edit,
and the toolbar reads it from the selection the app shows, so a click into
bold text shows bold and typing there stays bold, as in a browser;
- gets an example with a heading, a bullet list with a link, a check list
and a quote.
Rune maps list items to its field's bullets and numbers at their depth, a
quote to its quote block, links to `Mark::Link`, headings to larger, bolder
decorations and a checked item to strikethrough. GPUI shapes each line on
its own, at its block's size and indent, and draws list markers (•, 1., ☐/☑),
a quote's bar, links in the JS playground's blue, and checked items struck
through; a click on a box toggles it. Both get a second toolbar row (Normal,
H1-H3, Quote, the three lists, Link, Outdent, Indent, and a check toggle in a
check item), and Tab and Shift-Tab indent and outdent.
The GPUI end-to-end run now also makes a heading and a list, nests the item
with Tab, unnests it with Shift-Tab and ends the list; CI replays that
session in JS.
## Test plan
### Before
The block-menu test in `lexical-playground-core`, before `$setBlocksType`:
```
test tests::the_block_menu_converts_blocks_and_toggles_lists ... FAILED
```
Without the selectionchange format in the select step:
```
thread 'tests::a_click_gives_the_selection_the_format_there_as_selectionchange_does' panicked
left: ("Ru", true)
right: ("Ruyst", true)
```
### After
```
$ cargo test --workspace --all-features --locked (rust/)
test result: ok. 19 passed; 0 failed (lexical-playground-core)
$ cargo test --locked (apps/lexical-playground-rune)
test result: ok. 9 passed; 0 failed
$ cargo build --locked --features e2e && LEXICAL_PLAYGROUND_E2E=/tmp/gpui-e2e.json ./target/debug/lexical-playground-gpui (macOS 27, a real window)
e2e: passed
$ LEXICAL_REPLAY=/tmp/gpui-e2e.json pnpm exec vitest run src/replay.test.ts
Tests 1 passed (1)
```
The GPUI session has 26 steps, including INSERT_UNORDERED_LIST_COMMAND,
INDENT_CONTENT_COMMAND and OUTDENT_CONTENT_COMMAND. A 26-step session from
`lexical-playground-core` (block menu, lists, Tab, links, a check box, undo
and redo) also replays in JS, and changing one character of one recorded
result makes the replay fail.
fmt, clippy `-D warnings` and rustdoc `-D warnings` pass for the workspace;
clippy passes for Rune and, on macOS, for GPUI with `--features e2e`.
Screenshots of both apps were inspected: Rune headless (`--snap`), GPUI on
macOS 27.
Amp-Thread-ID: https://ampcode.com/threads/T-16d45229-bfa8-417a-a091-d3e3888d830d
## Description Typing Markdown in the Rust playgrounds left it as text: the playground editor never registered the markdown shortcuts, and Return called `insertParagraph` directly, so the Enter-triggered transformers (code fences) could not run. - `lexical-playground-core` registers `register_markdown_shortcuts` with the default transformers. Its script flags become `["richText","list","link","code","markdown"]`, so an exported session replays in JS with the same shortcuts. Return now dispatches `KEY_ENTER_COMMAND`, as a browser keydown does; rich text's handler then dispatches `INSERT_PARAGRAPH_COMMAND` unless the shortcuts or the code block took it. - GPUI draws code blocks with a monospace font, padding and a tinted background, so a typed code fence is visible. Its e2e run types a heading, bold text, a list item and a code fence. - Both READMEs list the shortcuts. - This branch merges `rust-playground-blocks` (#141), which the playgrounds' block rendering needs. ## Test plan ### Before ``` $ cd rust/apps/lexical-playground-core && cargo test --locked markdown thread 'tests::markdown_shortcuts_turn_typed_markdown_into_rich_text' panicked at apps/lexical-playground-core/src/tests.rs:497:5: assertion `left == right` failed left: "paragraph" right: "h1" test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 19 filtered out ``` ### After ``` $ cd rust/apps/lexical-playground-core && cargo test --locked test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out $ cd rust/apps/lexical-playground-rune && cargo test --locked # macOS test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out $ cd rust/apps/lexical-playground-gpui && cargo build --locked --features e2e && \ LEXICAL_PLAYGROUND_E2E=/tmp/s.json ./target/debug/lexical-playground-gpui # macOS e2e: passed $ cd packages/lexical-conformance && LEXICAL_REPLAY=/tmp/s.json pnpm exec vitest run src/replay.test.ts Test Files 1 passed (1) ``` On macOS, real keystrokes typed into GPUI through System Events (a heading, lists, a quote, inline formats, a link, a code fence, then ⌘Z) produced a 163-step session that replays in JS, and the in-app Replay vectors shows 655/655. Real keystrokes could not be delivered to the Rune app on the Mac satellite (it does not redraw for synthetic events, also without this change), so Rune is covered by its runtime tests only. Amp-Thread-ID: https://ampcode.com/threads/T-01a1daf1-150e-709b-aaed-996443a64459
tmm
force-pushed
the
rust-playground-markdown
branch
from
November 14, 2026 18:15
1730dea to
7bfbfca
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Typing Markdown in the Rust playgrounds left it as text: the playground
editor never registered the markdown shortcuts, and Return called
insertParagraphdirectly, so the Enter-triggered transformers (codefences) could not run.
lexical-playground-coreregistersregister_markdown_shortcutswiththe default transformers. Its script flags become
["richText","list","link","code","markdown"], so an exported sessionreplays in JS with the same shortcuts. Return now dispatches
KEY_ENTER_COMMAND, as a browser keydown does; rich text's handlerthen dispatches
INSERT_PARAGRAPH_COMMANDunless the shortcuts or thecode block took it.
background, so a typed code fence is visible. Its e2e run types a
heading, bold text, a list item and a code fence.
rust-playground-blocks(feat(rust): headings, quotes, lists, links and indent in both playgrounds #141), which theplaygrounds' block rendering needs.
Test plan
Before
After
On macOS, real keystrokes typed into GPUI through System Events (a
heading, lists, a quote, inline formats, a link, a code fence, then ⌘Z)
produced a 163-step session that replays in JS, and the in-app Replay
vectors shows 655/655. Real keystrokes could not be delivered to the Rune
app on the Mac satellite (it does not redraw for synthetic events, also
without this change), so Rune is covered by its runtime tests only.
Stacked on #157 (markdown shortcuts) and merges #141 (playground blocks), so it carries both until they land.