From 2a34b90d1e47dfdcdf513f0bfc3baa914baaffd8 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Fri, 16 Oct 2026 18:04:13 -1000 Subject: Keep underscores inside words out of emphasis --- custom/extensions/about-render.lua | 13 +++++++++---- tests/extensions/test-about-render.lua | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/custom/extensions/about-render.lua b/custom/extensions/about-render.lua index 4e4b50b..73b1336 100644 --- a/custom/extensions/about-render.lua +++ b/custom/extensions/about-render.lua @@ -291,7 +291,7 @@ end local render_markdown, render_man if has_lpeg then - local P, R, S, C, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct + local P, R, S, B, C, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.B, lpeg.C, lpeg.Ct local space = S(" \t") local whitespace = S(" \t\r\n\f\v") @@ -345,6 +345,11 @@ if has_lpeg then local address = (alnum + S(".!#$%&'*+/=?^_`{|}~-")) ^ 1 * P("@") * alnum * (alnum + S(".-")) ^ 0 + -- An underscore inside a word belongs to the word, as in snake_case, + -- so it neither opens nor closes emphasis. + local word = alnum + R("\128\255") + local inner = B(word) * P("_") ^ 1 * #word + -- A character reference passes through for the browser to decode, -- within CommonMark's lengths. Its shape leaves no room for markup, and -- a name the browser does not know shows as written. @@ -370,10 +375,10 @@ if has_lpeg then + (P("!") * label * target) / node_image + (label * target) / node_link + (P("**") * C((1 - P("**")) ^ 1) * P("**")) / node_strong - + (P("__") * C((1 - P("__")) ^ 1) * P("__")) / node_strong + + (-B(word) * P("__") * C((inner + (1 - P("__"))) ^ 1) * P("__") * -word) / node_strong + (P("*") * C((1 - whitespace) * (1 - P("*")) ^ 0) * P("*")) / node_em - + (P("_") * C((1 - whitespace) * (1 - P("_")) ^ 0) * P("_")) / node_em - + C((1 - marker) ^ 1) / node_text + + (-B(word) * P("_") * C((1 - whitespace) * (inner + (1 - P("_"))) ^ 0) * P("_") * -word) / node_em + + C((1 - marker + inner) ^ 1) / node_text + C(P(1)) / node_text ) ^ 0) diff --git a/tests/extensions/test-about-render.lua b/tests/extensions/test-about-render.lua index e84c854..3925dfd 100644 --- a/tests/extensions/test-about-render.lua +++ b/tests/extensions/test-about-render.lua @@ -108,6 +108,12 @@ out = render("README.md", "an __up__ and _down_ word") h.contains("double underscores embolden", out, "up") h.contains("single underscores lean", out, "down") +out = render("README.md", "snake_case_name and _lean_ and foo__bar__") +h.contains("underscores inside words stay literal", out, "

snake_case_name and lean and foo__bar__

") + +out = render("README.md", "_a_b_ and __c_d__") +h.contains("emphasis spans an underscore inside a word", out, "

a_b and c_d

") + out = render("README.md", "\\*not leaning\\* and \\# and \\q") h.contains("a backslash makes punctuation literal", out, "

*not leaning* and # and \\q

") -- cgit