Skip to content

feat(document): split, merge and insert a paragraph - #874

Merged
andiwand merged 1 commit into
mainfrom
feat/text-edit-paragraphs
Sep 10, 2026
Merged

feat(document): split, merge and insert a paragraph#874
andiwand merged 1 commit into
mainfrom
feat/text-edit-paragraphs

Conversation

@andiwand

@andiwand andiwand commented Sep 10, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Third of five; #873 is merged, so this now sits on main. See
docs/design/document-editing.md.

What this one does

  • splitParagraph moves what follows the element it names into a new paragraph
    carrying the same style.
  • mergeParagraph takes the children of the paragraph after this one and
    removes it.
  • insertParagraph puts an empty one after it.

With the run operations, Enter, Backspace at the start of a paragraph
and a delete spanning paragraphs are all replayable.
Document::split_paragraph, merge_paragraphs and insert_paragraph_after
are the same three in the C++ API — on the document rather than on a handle,
for the reason the run operations are: a handle says what an element holds,
the document what the tree holds. Each refuses an element of another document.

A split names a descendant, not a direct child

The caret sits in a run and the run sits in a span, so the split walks from
that run up to the paragraph and splits every element on the way: a run
inside a span leaves the span in both halves, and the tail keeps the formatting
it had. The same holds for a link, so the tail is still a link to the same
place.

Only a span and a link are split through. Anything else — a frame
between the run and the paragraph — refuses with UnsupportedOperation,
because what a copy of it would mean is the format's question rather than this
one's.

A copy carries the original's attributes and the property children the format
writes ahead of the content
w:pPr on a paragraph, w:rPr on a run. Those
sit before the first child the registry knows about, which is how the copy
finds them without naming a tag. ODF states the same thing as an attribute, so
one rule covers both.

Verified

Headless LibreOffice reads the split paragraph out of both a saved .odt and a
saved .docx as two paragraphs, the second keeping the style of the first.

@andiwand
andiwand force-pushed the feat/text-edit-paragraphs branch from 4210894 to 5e1f351 Compare September 10, 2026 12:56
@andiwand
andiwand force-pushed the feat/text-edit-runs branch 4 times, most recently from d0a4632 to 07199f0 Compare September 10, 2026 13:27
Base automatically changed from feat/text-edit-runs to main September 10, 2026 13:27
@andiwand
andiwand force-pushed the feat/text-edit-paragraphs branch from 5e1f351 to 267399e Compare September 10, 2026 13:33
`splitParagraph` moves what follows the element it names into a new
paragraph carrying the same style, `mergeParagraph` takes the children of
the paragraph after this one and removes it, and `insertParagraph` puts an
empty one after it. With the run operations, Enter, Backspace at the start
of a paragraph and a delete spanning paragraphs are all replayable.

`Document::split_paragraph`, `merge_paragraphs` and `insert_paragraph_after`
are the same three in the C++ API, on the document rather than on a handle
for the reason the run operations are.

A split names a descendant rather than a direct child, because the caret
sits in a run and the run sits in a span. So it splits every element from
that run up to the paragraph: a run inside a span leaves the span in both
halves, and the tail keeps the formatting it had. Only a span and a link
are split through; anything else refuses, because what a copy of it would
mean is the format's question rather than this one's.

A copy carries the original's attributes and the property children the
format writes ahead of the content - `w:pPr`, `w:rPr`. Those sit before
the first child the registry knows, which is how the copy finds them
without naming a tag.

Verified with headless LibreOffice: it reads the split paragraph out of
both a saved `.odt` and a saved `.docx` as two paragraphs, the second
keeping the style of the first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKFKbUVCYF2VhujdmjhhPW
@andiwand
andiwand force-pushed the feat/text-edit-paragraphs branch from 267399e to 7c538eb Compare September 10, 2026 13:44
@andiwand
andiwand merged commit 38d047b into main Sep 10, 2026
9 checks passed
@andiwand
andiwand deleted the feat/text-edit-paragraphs branch September 10, 2026 13:45
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.

1 participant