Skip to content

A formatting command drops the authored form of the block it changes #359

Description

@Azganoth

Summary

Leafdown records the form a block was authored in and writes it back, but the formatting commands have no rule for that form. Two commands that make the same change to a heading disagree about whether it survives: Increase heading level carries the node's attributes through and keeps the form, while Heading 1 through Heading 6 rebuild the block from the level alone and drop it.

The file then gains the unrequested rewrite the preservation program exists to prevent, arriving one gesture later than a save would have delivered it. Neither behavior is a decision about form; the difference is which ProseMirror helper each command reached for.

Steps to reproduce

  1. Open a document containing Setext one on one line and === on the next.
  2. Run Heading 2.
  3. Save the document and read the file.

Expected behavior

Setext one over ---. That is the form the heading was authored in, at the level the command asked for, and it is what Increase heading level already writes for the same change.

Whatever rule is chosen, the two paths to one level change agree.

Actual behavior

## Setext one. The authored form is gone.

Measured by driving the editor mount on main at 71897f80, the merge of #358, which is where a heading first carries a form:

Document Command Saved
Setext one / === Increase heading level Setext one / ---
Setext one / === Heading 2 ## Setext one
# Closed atx # Heading 3 ### Closed atx

adjustSelectedHeadingLevels dispatches setNodeMarkup(pos, undefined, { ...node.attrs, level }, node.marks), which carries every attribute the node holds. toggleHeading reaches setSelectionTextBlockType(view, "heading", { level }), which builds the block from the named attributes alone and leaves every other attribute at its schema default.

Related context

Done when

  • A stated rule for what a formatting command does with the authored form of the block it changes: preserve it, reset it, or recompute it.
  • Heading 1 through Heading 6 agree with Increase heading level and Decrease heading level on a heading's form.
  • The commands that rebuild a block from named attributes are audited, and the ones that drop a preserved form are named here whether or not each is changed under this issue.
  • Regression coverage asserts the rule in both directions, so preserving a form through one command cannot silently reset it through another.
  • The specification records what a formatting command does to an authored form.

Notes, logs, screenshots

The list commands were probed alongside the headings and the result was inconclusive: the caret landed inside the existing list and toggled it off rather than acting on the trailing paragraph. Whether format.unorderedList and format.orderedList drop a list's recorded marker is unmeasured and part of the audit above.

Typora was measured on the same question for comparison. It preserves a construct's authored form through an edit to that construct, including a level-three heading closed by a single hash and a setext heading whose underline is far shorter than its text. Its three markdown preferences do not reformat an existing construct.

Implementation direction

setNodeMarkup with the node's own attributes spread is already the preserving form, so the smaller half of the work is making the toggle path match it. The rule is the larger half, because a level change and a paragraph-to-heading conversion are not obviously the same question: the first has a form to keep and the second has none.

Out of scope

  • What form a construct with no authored form takes, which is its own issue.
  • Undo and redo, which restore the attributes the history holds.
  • Whether a formatting preference should exist at all.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

BugSomething isn't working

Projects

  • Status
    Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions