Skip to content

feat(rust): @lexical/file, the devtools tree view and @lexical/text's root helpers - #153

Open
tmm wants to merge 1 commit into
rust-plan-swift-parityfrom
rust-file-devtools-text
Open

tmm wants to merge 1 commit into
rust-plan-swift-parityfrom
rust-file-devtools-text

Conversation

@tmm

@tmm tmm commented Nov 14, 2026

Copy link
Copy Markdown
Member

The Rust port had no @lexical/file, no @lexical/devtools-core tree
view and none of @lexical/text's root helpers, so file/export,
file/import and devtools/tree were reported as not implemented.

This adds them, each behind its own Cargo feature:

  • file: serializedDocumentFromEditorState,
    editorStateFromSerializedDocument, and importFile/exportFile, with
    the file picking and saving left to the app through callbacks, as Swift
    does.
  • devtools: generateContent (the tree view). Its link branch is built
    with link.
  • text: $rootTextContent, $isRootTextContentEmpty,
    $canShowPlaceholder (with their curried forms) and
    $findTextIntersectionFromCharacters.
  • Core: NodeRef::is_selected, NodeRef::is_before, Editor::VERSION,
    get_namespace, is_editable/set_editable, and a namespace field on
    CreateEditorArgs that defaults to a createUID()-style id. The meta
    suite checks that Editor::VERSION is lexical-rust@<UPSTREAM_VERSION>.

No vector reached the root helpers, so packages/lexical-conformance gains
four script actions that call the real @lexical/text functions and a
JS-recorded scripts/text vector (13 cases: empty documents, whitespace
String#trim does and doesn't remove, text outside the BMP, blocks, indent,
line breaks, tabs, headings, quotes, nested lists and decorators). Swift
replays it too; Swift's LexicalText already matched JS.

Not ported, each listed in PARITY.md: the devtools exportDOM form (needs
@lexical/html), its mark and table branches, slots and the
compositionKey line, and the DOM halves of importFile/exportFile.

$ cargo run -q --locked --release -p lexical-conformance
| `devtools/tree` | – | – | – | – | – | not implemented |
| `file/export` | – | – | – | – | – | not implemented |
| `file/import` | – | – | – | – | – | not implemented |
| **Total** | 569 | 569 | 0 | 0 | 0 | |
$ cargo run -q --locked --release -p lexical-conformance
| `devtools/tree` | 38 | 38 | 0 | 0 | 0 | pass |
| `file/export` | 8 | 8 | 0 | 0 | 0 | pass |
| `file/import` | 3 | 3 | 0 | 0 | 0 | pass |
| `scripts/text` | 13 | 13 | 0 | 0 | 0 | pass |
| **Total** | 631 | 631 | 0 | 0 | 0 | |

Mutation checks (each reverted): devtools ^ padding off by one fails 10
devtools/tree cases; is_selected always false fails 25; an undefaulted
empty source fails 2 file/export cases; Rust's trim() instead of JS's
whitespace fails 1 scripts/text case; >= for > in
find_text_intersection_from_characters fails 9; a wrong Editor::VERSION
fails meta.

cargo fmt --all --check, cargo clippy --workspace --all-targets --all-features --locked -- -D warnings, cargo test --workspace --all-features --locked, cargo doc with -D warnings, cargo +1.88 check -p lexical-editor --all-features, --no-default-features alone and
with file, devtools, text and devtools,link, and the Rune app's
clippy all pass. UPDATE_VECTORS=1 pnpm exec vitest run src/scripts.test.ts: 19 passed, and no other vector changed (md5).
Swift: ScriptTests, FileTests and TreeViewTests pass.

… root helpers

The Rust port had no `@lexical/file`, no `@lexical/devtools-core` tree
view and none of `@lexical/text`'s root helpers, so `file/export`,
`file/import` and `devtools/tree` were reported as not implemented.

This adds them, each behind its own Cargo feature:

- `file`: `serializedDocumentFromEditorState`,
  `editorStateFromSerializedDocument`, and `importFile`/`exportFile`, with
  the file picking and saving left to the app through callbacks, as Swift
  does.
- `devtools`: `generateContent` (the tree view). Its link branch is built
  with `link`.
- `text`: `$rootTextContent`, `$isRootTextContentEmpty`,
  `$canShowPlaceholder` (with their curried forms) and
  `$findTextIntersectionFromCharacters`.
- Core: `NodeRef::is_selected`, `NodeRef::is_before`, `Editor::VERSION`,
  `get_namespace`, `is_editable`/`set_editable`, and a `namespace` field on
  `CreateEditorArgs` that defaults to a `createUID()`-style id. The `meta`
  suite checks that `Editor::VERSION` is `lexical-rust@<UPSTREAM_VERSION>`.

No vector reached the root helpers, so `packages/lexical-conformance` gains
four script actions that call the real `@lexical/text` functions and a
JS-recorded `scripts/text` vector (13 cases: empty documents, whitespace
`String#trim` does and doesn't remove, text outside the BMP, blocks, indent,
line breaks, tabs, headings, quotes, nested lists and decorators). Swift
replays it too; Swift's `LexicalText` already matched JS.

Not ported, each listed in PARITY.md: the devtools `exportDOM` form (needs
`@lexical/html`), its mark and table branches, slots and the
`compositionKey` line, and the DOM halves of `importFile`/`exportFile`.

```
$ cargo run -q --locked --release -p lexical-conformance
| `devtools/tree` | – | – | – | – | – | not implemented |
| `file/export` | – | – | – | – | – | not implemented |
| `file/import` | – | – | – | – | – | not implemented |
| **Total** | 569 | 569 | 0 | 0 | 0 | |
```

```
$ cargo run -q --locked --release -p lexical-conformance
| `devtools/tree` | 38 | 38 | 0 | 0 | 0 | pass |
| `file/export` | 8 | 8 | 0 | 0 | 0 | pass |
| `file/import` | 3 | 3 | 0 | 0 | 0 | pass |
| `scripts/text` | 13 | 13 | 0 | 0 | 0 | pass |
| **Total** | 631 | 631 | 0 | 0 | 0 | |
```

Mutation checks (each reverted): devtools `^` padding off by one fails 10
`devtools/tree` cases; `is_selected` always false fails 25; an undefaulted
empty `source` fails 2 `file/export` cases; Rust's `trim()` instead of JS's
whitespace fails 1 `scripts/text` case; `>=` for `>` in
`find_text_intersection_from_characters` fails 9; a wrong `Editor::VERSION`
fails `meta`.

`cargo fmt --all --check`, `cargo clippy --workspace --all-targets
--all-features --locked -- -D warnings`, `cargo test --workspace
--all-features --locked`, `cargo doc` with `-D warnings`, `cargo +1.88
check -p lexical-editor --all-features`, `--no-default-features` alone and
with `file`, `devtools`, `text` and `devtools,link`, and the Rune app's
clippy all pass. `UPDATE_VECTORS=1 pnpm exec vitest run
src/scripts.test.ts`: 19 passed, and no other vector changed (md5).
Swift: `ScriptTests`, `FileTests` and `TreeViewTests` pass.

Amp-Thread-ID: https://ampcode.com/threads/T-16d45229-bfa8-417a-a091-d3e3888d830d

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