You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Text the file keeps literal and text that is live syntax read identically on screen, and there is no character to delete to convert one into the other. Removing an escape today means deleting the whole run and retyping it.
Projecting the escape itself — the backslash and the character it escapes — gives the author the character back. Deleting it converts the run. Nothing is stored to make this work: the escape is derived from the text and the serializer's safety check, so it is available again on every open, including after a save and reopen.
This is the reversal gesture #238 scopes. It replaces a guess about what the author meant with something the author does.
Expected behavior
A caret arriving at a character the file will escape projects two characters, the backslash and that character. Deleting the backslash converts the run to the syntax it describes. Undo reverses it like any other document change.
The projection shows what the file will hold, not what it held when opened.
This is the inverse of a gesture that already exists: a link projects its source, and an edit making that source invalid commits it as literal text.
A caret at an escaped character projects the backslash and that character.
Deleting the backslash converts the run; Undo reverses it.
The caret-time cost is measured and recorded before the design is fixed.
Adapter precedence is settled where an escape abuts a live target.
docs/specification.md Inline Content describes the rule.
Notes
Implementation direction
Blocked on the escaping precision issue and does not work before it. Against today's serializer a file holding \[a](b) saves as \[a]\(b), so an author deleting the first backslash sees no change at all — the run stays literal because \( still breaks it. The gesture is spelled as one deletion but only completes in pairs, and its first half is silent. Precise escaping reduces it to one backslash and one deletion. Before that fix the projection would also surface escapes that should not exist: garden_sensor_name would project \_ twice.
Two properties are accepted rather than solved, both measured in #245:
The escape sits where the syntax needs breaking, not where the author wrote it. Keeping  literal cannot be done by escaping the ! — that leaves a literal ! followed by a live link. The escape belongs on the [.
Nested runs still pair. [](l.md) needs two escapes even minimally, so deleting one yields the image without the link.
Two measured cases place an escape flush against a live projection target and are what adapter precedence has to answer for: \ yields text:"!" beside a link, and \<https://example.com> yields text:"<" beside one.
The symmetry with typing \ into projected link source is read from docs/specification.md rather than observed; confirm it before building on it.
Out of scope
Bare URLs. Typed link source becomes a link #238 records that a bare URL has no literal state, because mdast-util-gfm-autolink-literal decodes escapes after parsing. There is no surviving escape to project, and inline code remains the way to show one as text.
Making the distinction visible before the caret arrives. A projection entered by the caret tells an author what an escape is once they suspect one; it does not distinguish two identical-looking runs on sight. src/features/editor/plugins/markerPresentation.ts already decorates ranges without touching document text and is the cheaper answer if visibility is wanted.
Summary
Text the file keeps literal and text that is live syntax read identically on screen, and there is no character to delete to convert one into the other. Removing an escape today means deleting the whole run and retyping it.
Projecting the escape itself — the backslash and the character it escapes — gives the author the character back. Deleting it converts the run. Nothing is stored to make this work: the escape is derived from the text and the serializer's safety check, so it is available again on every open, including after a save and reopen.
This is the reversal gesture #238 scopes. It replaces a guess about what the author meant with something the author does.
Expected behavior
A caret arriving at a character the file will escape projects two characters, the backslash and that character. Deleting the backslash converts the run to the syntax it describes.
Undoreverses it like any other document change.The projection shows what the file will hold, not what it held when opened.
This is the inverse of a gesture that already exists: a link projects its source, and an edit making that source invalid commits it as literal text.
Related context
Outcomesection of How a Markdown escape should be represented in the editor #245,docs/specification.mdInline Content,docs/architecture.mdSource ProjectionDone when
Undoreverses it.docs/specification.mdInline Content describes the rule.Notes
Implementation direction
Blocked on the escaping precision issue and does not work before it. Against today's serializer a file holding
\[a](b)saves as\[a]\(b), so an author deleting the first backslash sees no change at all — the run stays literal because\(still breaks it. The gesture is spelled as one deletion but only completes in pairs, and its first half is silent. Precise escaping reduces it to one backslash and one deletion. Before that fix the projection would also surface escapes that should not exist:garden_sensor_namewould project\_twice.Two properties are accepted rather than solved, both measured in #245:
literal cannot be done by escaping the!— that leaves a literal!followed by a live link. The escape belongs on the[.[](l.md)needs two escapes even minimally, so deleting one yields the image without the link.Two measured cases place an escape flush against a live projection target and are what adapter precedence has to answer for:
\yieldstext:"!"beside a link, and\<https://example.com>yieldstext:"<"beside one.The symmetry with typing
\into projected link source is read fromdocs/specification.mdrather than observed; confirm it before building on it.Out of scope
mdast-util-gfm-autolink-literaldecodes escapes after parsing. There is no surviving escape to project, and inline code remains the way to show one as text.src/features/editor/plugins/markerPresentation.tsalready decorates ranges without touching document text and is the cheaper answer if visibility is wanted.