Skip to content

Convert emphasis, code, and the other escaped forms through the escape gesture #272

Description

@Azganoth

Summary

#255 offers the escape gesture only where a conversion exists, and today that is one inline link and one image. Text the file escaped to keep emphasis, strong, strikethrough, inline code, a heading marker, or a list marker literal shows no escape at all, because a backslash whose deletion changes nothing is the silent gesture #245 blocked #255 on.

So for every form but a link, removing an unwanted escape still means deleting the run and retyping it, which is the problem #238 was opened to solve. This issue supplies the missing half: the conversion those runs need before the gesture can be offered on them.

Measured against 621866a8: *not emphasis* saves as \*not emphasis\* and # not a heading as \# not a heading, but findLiteralSourceCommit returns nothing at either escape, because findLinkNodeBounds matches node.type === "link" and nothing else.

Expected behavior

A caret arriving at a character the file will escape projects the escape for every supported form, not only a link. Deleting the backslash converts the run to the syntax it describes, and Undo reverses it like any other document change.

Nothing is stored to make this work. The escape stays derived from the text and the serializer's safety check, as #245 settled and #255 implements.

Related context

Done when

  • An escaped emphasis, strong, strikethrough, or inline-code run projects its escape, and deleting the backslash converts the run.
  • An escaped heading marker and list marker do the same, or are split out with the reason recorded.
  • Undo reverses each conversion, and a run left alone stays literal across a save and reopen.
  • Regression coverage per form, and the corpus round trip stays green.
  • docs/specification.md Inline Content describes the widened rule.

Notes

Implementation direction

The mechanism is a generalization of findLiteralLinkSourceCommit in src/features/editor/utils/sourceProjectionLinkAdapter.ts: parse the block's text and replace the matched run with whatever it now spells, rather than matching one mdast type. The two families behave differently enough to be worth separating before starting.

  • Inline marks rehydrate as marks over text that stays in place, rather than as a replacement node. The commit has to reconcile with marks the run already carries, and isPlainTextRange, which every literal-source commit is gated on today, rejects any marked range outright.
  • Block markers#, -, >, and an ordered-list marker — change the block's type rather than its inline content, so they sit outside the projection engine's inline commit path entirely. They may deserve their own issue rather than a shared one.

Blocked in practice by #271: until precise escaping reaches inside a mark, a run nested in one would project an escape that does not match what the file writes, which is the failure mode this whole line of work exists to avoid.

Out of scope

Metadata

Metadata

Assignees

Labels

FeatureNew feature or request

Projects

Status
Ready

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions