Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion lua/markview/renderers/markdown/tostring.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ md_str.update_cache = function ()
footnotes = spec.get({ "markdown_inline", "footnotes" }, { fallback = nil }),
internal_links = spec.get({ "markdown_inline", "internal_links" }, { fallback = nil }),
uri_autolinks = spec.get({ "markdown_inline", "uri_autolinks" }, { fallback = nil }),
tags = spec.get({ "markdown_inline", "tags" }, { fallback = nil }),
};

---|fE
Expand Down Expand Up @@ -361,6 +362,50 @@ md_str.footnote = function (match)
---|fE
end

---@param match string
---@return string
md_str.tag = function (match)
---|fS

local label = string.gsub(match, "^#", "");

if md_str.cached_config and md_str.cached_config.tags then
---@type markview.config.__inline?
local config = require("markview.utils").match(md_str.cached_config.tags, label, {
eval_args = {
md_str.buffer,
{
class = "inline_tag",
text = { match },

label = label,
}
}
});

if config then
--- NOTE: The tag renderer conceals the leading `#` and adds
--- corner/padding/icon around the label. Mirror that here so the
--- table column-width calculation matches what is drawn; otherwise a
--- tag in a cell drifts the right border by the padding width.
return table.concat({
config.corner_left or "",
config.padding_left or "",

config.icon or "",
label,

config.padding_right or "",
config.corner_right or "",
}, "");
end
end

return match;

---|fE
end

---@param match string
---@return string
md_str.escape = function (match)
Expand Down Expand Up @@ -795,11 +840,19 @@ local hl = lpeg.C( lpeg.P("==") * hl_content^1 * lpeg.P("==") ) / md_str.highlig
local strike_content = lpeg.P("\\~") + ( 1 - lpeg.P("~") );
local strike = lpeg.C( lpeg.P("~~") * strike_content^1 * lpeg.P("~~") ) / md_str.strikethrough;

-- Obsidian-style tag: `#` followed by tag characters, only at the start of a
-- token position (start-of-string or after whitespace, via `at_valid`) and not
-- part of an internal-link `#^section` (guarded by the trailing `-]]`). Mirrors
-- the tag parser in `parsers/markdown_inline.lua` so the width computed here
-- matches what the tag renderer draws (concealed `#` + paddings).
local tag_char = lpeg.R("09", "az", "AZ") + lpeg.S("_-");
local tag = lpeg.C( at_valid * lpeg.P("#") * tag_char^1 * -lpeg.P("]]") ) / md_str.tag;

local any = lpeg.P(1);

local token = escape +
emoji + entity +
hl + strike + block_ref + embed + internal +
hl + strike + tag + block_ref + embed + internal +
email + auto +
footnote + img + hyperlink +
code +
Expand Down
59 changes: 59 additions & 0 deletions test/table_ref_tag_drift.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
; Tags/refs in table cells — right-border drift
A `#`-prefixed token in a table cell (`#foo`, `#bug`, `#51`, `#107`) is parsed
as an Obsidian-style tag. The tag renderer conceals the leading `#` and injects
`padding_left` + `padding_right` (and, if configured, `corner`/`icon`) as inline
virtual text. That decoration changes the rendered cell width, but the table's
column-width calculation is computed via `renderers/markdown/tostring.lua`, which
has NO tag handler — it measures the raw cell text (`#foo` = 4 columns) and is
blind to the conceal + padding. The mismatch drifts the cell's right border
(about +1 per tag cell with the default padding; more if an icon is configured).

This is NOT limited to numeric refs: `#foo` drifts exactly like `#51`. The cause
is the missing tag-width accounting in `tostring`, not whether the tag body is
numeric.

Fix: teach `tostring` about tags so the computed column width matches what the
renderer draws (conceal the `#`, add the paddings).

Open this file with hybrid/preview mode and check every right border lines up.
Each tag cell must align with the plain control cell of equal rendered width.

### Non-numeric tags drift too (primary repro)

| Ref | Note | Plain |
|------|---------------|-------|
| #foo | word ref | XXXX |
| #bug | word tag | XXXX |
| #wip | word tag | XXXX |
| Xctl | plain control | XXXX |

### Numeric refs drift the same way

| Ref | Note | Plain |
|------|---------------|-------|
| #51 | first ref | XXX |
| #107 | second ref | XXXX |
| #26 | third ref | XXX |
| #1 | single digit | XX |
| Xctl | plain control | XXXX |

### Varied tag bodies (digits, letters, _ and -)

| Kind | Value |
|------------------|----------|
| Word tag | #bug |
| Version tag | #v2 |
| Mixed (digits+) | #123abc |
| Underscore | #wip_now |
| Hyphen | #in-prog |
| Numeric only | #123 |

### Mixed content — refs and tags side by side

| When | Ref | Tag | Cancel |
|----------|------|--------|----------|
| 11:38:13 | #51 | #bug | 14:54:27 |
| 06:34:40 | #107 | #v2 | 07:51:34 |
| 08:28:44 | #26 | #wip | 08:30:15 |

<!-- vim: set nowrap: -->
Loading