The open field sits in the closed block's frame at its size, line
height and weight; headings keep their step. Code and math keep their
panel. Typewriter centering also keys on the ends' room, so a block
opened at the same height still centers.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Headings and strong text share one bold weight, so strong text in a
heading no longer draws lighter. A heading's line height is relative
to its own size, and tests check every level's size against the body,
a larger body and a zoomed document.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bracket and match offsets from the last draw belong to that text's
stamp, so an input-method edit before the next draw no longer splits
a character into font runs. A press past the last glyph's start picks
the nearer of that start and the line end.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sizes follow Typora's steps over the body (2.25, 1.75, 1.5, 1.25, 1, 1)
so levels 3 and 4 stand out; level 6 is muted; line height fits the size.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Carets, selections, presses and the input method box measured the line
as columns times one 'm', so a wide character (CJK, emoji) put the caret
mid-glyph. editor::measure lays out the drawn line; rulers and indent
guides stay on the column grid; whitespace marks hide the rest.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The screen keeps a single line break (Typora's default when writing);
outputs read with Reader::joined, which joins them as GFM does. Heading
titles read on one line.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Panels occlude the rows under them. A submenu without room on the
right opens on the left of its row. A submenu opens after the pointer
rests 150 ms; a row crossed toward an open submenu waits 300 ms.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An emptied bare edge cell writes a pipe so its column stays. The caret
reads the escaped write-back. A right press beside an edited cell keeps
its place. A move that waits on a long read opens once the read lands.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A trailing backslash doubles only before a closing pipe. A write at a
block's start keeps the block, so Tab leaves a first cell without outer
pipes. Padding of the open cell moves its caret to the end, and a right
press there points at the end.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A press inside the open cell stays with its field. Find opens the
cell holding a match. A closing backslash no longer escapes the
next pipe. A right press after typed pipes reads the right byte.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Visual mode opened a pressed table whole, as Markdown source. A press
in a table now opens only that cell, in place, as its source in a
one-line field; the rest of the table stays drawn. Tab and Shift-Tab
walk the cells, Up and Down move a row or leave the table, Enter and
Escape write back in one undo step, and a bare pipe typed in a cell is
escaped on write-back. The table drawing moves to render/table.rs and
presses on a cell's padding name the cell.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
drawn_at aligns each source piece once instead of re-reading the span
for every drawn byte, so a right press near a long paragraph's start
stays linear. A newer press drops an older pending open-block lookup.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The find counts, toggles, replace buttons, the builders' add, join and
direction labels, the filter tests and the password tooltip read the
builtin catalog. Test::label becomes Test::key, the choice's value; its
label is the catalog's. The shipped-copy scan checks button, segment and
match-arm text on every match, and zh-CN render tests cover both.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The open block's target was read at the selection's start and from
the syntax tree only, so a press on the second of two selected links
named the first, and an inline anchor read as its outer link.
point_open now reads the byte under the press and resolves links as
drawing does; delete_image takes that byte.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Select's default placeholder, the clear, close, remove and unpin tooltips,
the completion menu's empty line and the size sample showed English under
zh-CN. A source test now fails on any fixed English literal in them.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A right press in a text field or the code editor keeps a selection it
lands in, else moves the caret. In visual mode a right press in the open
block keeps it open and emits Pointed, read apart from the whole text.
MarkdownDocument::delete_image removes the picture at the caret.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An edit past an open block wrote it back and dropped its input while
it held focus, so focus fell to the window root and Undo reached
nothing. The next render passes such focus to the document.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Typora's Paragraph > Table > Delete Table. It removes the table as the
block command does and refuses outside a table as TableRefusal::Outside.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A menu or dialog took focus, the open block wrote back and closed, and
the overlay handed focus back to a closed input: its command reached
nothing and the selection was gone. The block now waits for the overlay
to let focus go, and writes back only when focus lands elsewhere.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The editor splits lines on LF only, so End can leave the caret
between CR and LF. The edit runner and table insert now settle the
selection before the CR; the line helpers assert they never see a
split instead of guessing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The code editor splits lines on LF only, so End and Right can leave the
caret between CR and LF. line_start and line_end now read that spot as
the end of its line, so insert_table keeps CRLF around a new table.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Table rewrites find their prefix and rows by CR, LF and CRLF alike and
write the table's own line ending; insert_table takes the text's. A
cell's width counts a tab as 4 and a control character as 0, as
Typora's wcswidth does.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Fixes R4.7 round 2: a heading change or split is parsed again and
refused as Misread when its text, formats or kind would change;
closing hashes and block openers are escaped at split ends; task
boxes below a marker stay; indented code is written from its value;
alerts unwrap past blank and lazy lines; delete counts every gone
opener.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Round-1 fixes for R4.7: a caret in heading marks splits at the text; a
split closes and reopens bold, italic and strike, refusing inside links,
code, math and HTML; a task's first text takes no block; retype keeps
task boxes and code indent and takes siblings past the list; an alert
in an item keeps the item's opener; paragraph-before moves a holder's
first text below its opener; delete keeps neighbors from joining; a
heading's text keeps closing hashes and block openers escaped; a heading
level is idempotent, as Typora's menu calls it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
MarkdownDocument::block runs a BlockCommand at the caret: heading
levels, paragraph, promote and demote; quote and list toggles;
rule, code, math, toc, footnote, link definition and front matter
inserts; empty paragraphs before and after; delete. Formats and
block commands share one runner off the UI thread; FormatRefusal
is now EditRefusal.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The format command never parses on the UI thread; refusals past the
size checks come by event. The document's at-once read returns to
128 KiB, so a visual opening between the cutoffs starts at the top.
Timing test takes web_time::Instant.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Unwrapping a style now runs the crossing check on the found node, so an
end in a nested link address or strike mark refuses. Clear keeps an
autolink's backslashes. Block lookups use a sorted search, so the walk
grows linearly. A long format refuses a second one as Busy and reports
refusals, a changed text and a shown preview through FormatRefused.
markdown-rs grows with the square of its nodes, so texts read at once
only up to 16 KiB.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Unwrap and merge check the original ends against marks and link
addresses. Blocks take text up to their end spaces; a cell between its
pipes. Clear also takes inline math's dollars, footnote brackets and
escape backslashes. Underline finds its <u> pair past other tags. Blank
lines split on CR too; a selection across blocks says Across. Past
128 KiB the toggle runs off the UI thread and lands only if text and
selection are unchanged; past the largest read it refuses (TooLong).
Clear and the document command move into format/.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
MarkdownDocument::format toggles bold, italic, code, strike, underline,
link and image at the selection, or clears every inline mark from the
blocks it touches, following Typora's toggleStyle: off inside the style,
wrap a selection, take the caret's word or write an empty pair. Code,
math, HTML and front matter refuse, as does a selection crossing a
block, a link or another mark. An open block keeps its field open.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Round 3 of R4.5 found five ways the reverse reading drifted from
markdown-rs: kept indents and marks were eaten as joins, autolink text
was decoded, table code kept its escaped pipes, decoded white space
could not join or drop, and C0/C1 numeric references kept their
controls. Matching now tries an equal character first, a drawn space
against any line end next, and drops white space decoded or not;
autolinks read as written, table cell code reads \| as |, and numeric
references follow markdown-rs. The reviewer's probes are regressions.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each piece records how its source decodes: Markdown's escapes and
references for text, HTML's for an HTML block's runs, none for code
spans, cut as CommonMark cuts their end spaces. Matching runs from the
piece's end, so quote marks and indents at a line's start are never
taken for text, and an alert's text needs no moved position: alert()
takes no source again.
Lines split on LF, CRLF and CR alike; LineMap matches each drawn line
to the written line it ends once, so an HTML block maps in linear time
and a tab cut to spaces lands on the tab. A write-back refuses the
press when the pressed block's kind, text or drawing changed.
The hostile HTML test measures growth: a fixed 2 s budget failed under
the full suite's load on the old code too.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each drawn character finds its written one, skipping only white
space, escapes and quote marks, so a press lands on the character
itself. Code, front matter and link definitions read back line for
line. An HTML block keeps each text run's source byte, and an alert
keeps its text past the marker; alert() now takes the source.
A secondary press refuses a target its write-back changed, and its
focus no longer opens an empty document. Run's element stack moves to
tree/stack.rs and the HTML-block reader to tree/html_block.rs.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each drawn text piece keeps its written span, so a press maps back to a
source byte. A secondary press opens nothing: it moves the caret there and
emits DocumentEvent::Pointed with the block's kind, link, picture and
whether it lies in a table or code. Block nodes count from their own start.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The writer in ElyMark kept its own copy of the inline reading, which drifted
from the drawing. Reader goes public as MarkdownReader with block, inline,
note and label, and its blocks as MarkdownBlock. Shortcodes, InlineTag,
inline_tag and html_block_text close back to the tree; headings(text) goes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Shortcodes, inline_tag, html_block_text, alert, is_toc and headings are what
the drawing itself calls, so an export that calls them shows the same.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The first `:name:`-shaped run in a text node decides for the whole node:
blank text or a space before it turns every shortcode, else none. Filtered
tags are text and do not split the node. Probed on GitHub's markdown API.
- `fieldset`, `menu` and the rest of HTML5's list end an open `p`.
- `CodeEditor` carries owner anchors through each edit; the document anchors
every heading it reads, and a TOC press goes where its anchor went.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>