From 30ae752f097a4fd4bf6de9c6bee26df4cf7588c4 Mon Sep 17 00:00:00 2001 From: Immanuel Haffner Date: Wed, 18 Mar 2026 21:23:11 +0100 Subject: [PATCH 1/2] fix(tostring): handle strikethrough markers in visual width calculation Add strikethrough handler to strip ~~ markers when computing visual text width. Without this, ~~text~~ in table cells inflated column widths by 4 extra characters (2 per marker pair). - Add md_str.strikethrough() to strip ~~ delimiters - Add LPEG strike pattern for ~~content~~ syntax - Register strike in the token alternatives --- lua/markview/renderers/markdown/tostring.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lua/markview/renderers/markdown/tostring.lua b/lua/markview/renderers/markdown/tostring.lua index d1fc4de5..8f8e7c5c 100644 --- a/lua/markview/renderers/markdown/tostring.lua +++ b/lua/markview/renderers/markdown/tostring.lua @@ -368,6 +368,21 @@ md_str.escape = function (match) return char; end +---@param match string +---@return string +md_str.strikethrough = function (match) + ---|fS + + if string.match(match, "%s+%~%~$") then + return match; + end + + local removed = string.gsub(match, "^%~%~", ""):gsub("%~%~$", ""); + return removed; + + ---|fE +end + ---@param match string ---@return string md_str.italic = function (match) @@ -777,11 +792,14 @@ local emoji = lpeg.C( lpeg.P(":") * emoji_char^1 * lpeg.P(":") ) / md_str.emoji; local hl_content = lpeg.P("\\=") + ( 1 - lpeg.P("=") ); local hl = lpeg.C( lpeg.P("==") * hl_content^1 * lpeg.P("==") ) / md_str.highlight; +local strike_content = lpeg.P("\\~") + ( 1 - lpeg.P("~") ); +local strike = lpeg.C( lpeg.P("~~") * strike_content^1 * lpeg.P("~~") ) / md_str.strikethrough; + local any = lpeg.P(1); local token = escape + emoji + entity + - hl + block_ref + embed + internal + + hl + strike + block_ref + embed + internal + email + auto + footnote + img + hyperlink + code + From 9d35287064d163031b22814097bcbb269157679e Mon Sep 17 00:00:00 2001 From: Immanuel Haffner Date: Fri, 3 Jul 2026 14:50:50 +0000 Subject: [PATCH 2/2] test: add tostring strikethrough column-width fixture Repro for the strikethrough width fix: without stripping ~~ markers in renderers/markdown/tostring.lua, each ~~text~~ span inflated the computed column width by 4, drifting the right border. This fixture mirrors test/tostring_word_attached_emphasis.md: strikethrough rows should align with the plain control rows. Covers single/multiple spans, mixing with bold/italic/code, and escaped/single tildes staying literal. --- test/tostring_strikethrough_width.md | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/tostring_strikethrough_width.md diff --git a/test/tostring_strikethrough_width.md b/test/tostring_strikethrough_width.md new file mode 100644 index 00000000..213abd59 --- /dev/null +++ b/test/tostring_strikethrough_width.md @@ -0,0 +1,34 @@ +; Strikethrough markers in tables — tostring column width +Strikethrough delimiters (`~~text~~`) are concealed by the renderer, so the +column-width calculation in `renderers/markdown/tostring.lua` must strip them +too. If it doesn't, each `~~` pair adds 2 characters (4 per `~~text~~` span) to +the computed width, so the calculated width is larger than what is drawn and the +right border drifts to the right. +Open this file and check that every right border lines up. The strikethrough +rows should align exactly with the plain control rows below them. +### Single strikethrough span +| Case | Example | +|--------------------------|----------------------| +| Strikethrough word | ~~gone~~ text | +| Strikethrough phrase | ~~all of this~~ here | +| Plain (control, same len)| xxxxxxx text | +| Plain (control) | just normal text | +### Multiple spans in one cell +| Case | Example | +|-------------------------|----------------------------| +| Two spans | ~~one~~ and ~~two~~ done | +| Span at end of cell | keep ~~this dropped~~ | +| Plain (control) | one and two done | +### Strikethrough mixed with other emphasis +| Case | Example | +|----------------------------|--------------------------| +| Strike + bold | ~~old~~ **new** | +| Strike + italic | ~~old~~ *new* | +| Strike + code | ~~old~~ `new()` | +| Plain (control) | old new | +### Escaped tildes stay literal (not strikethrough) +| Case | Example | +|-----------------------|--------------------| +| Escaped tilde pair | a \~\~literal\~\~ b | +| Single tilde (approx) | about ~5 items | +| Plain (control) | just normal text |