From aee34c95d83cf66bcacd0848a5f4ab0a1ccc198f Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Fri, 16 Oct 2026 18:05:28 -1000 Subject: Give readme headings anchors like GitHub's A readme's links to its own sections, as in a table of contents, had nothing on the page to land on. --- custom/extensions/about-render.lua | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'custom/extensions') diff --git a/custom/extensions/about-render.lua b/custom/extensions/about-render.lua index 73b1336..6ee790b 100644 --- a/custom/extensions/about-render.lua +++ b/custom/extensions/about-render.lua @@ -32,6 +32,10 @@ local max_depth = 24 local filename, tree_base, tree_query, chunks = "", "", "", {} +-- How often each heading anchor has been handed out. The ids already on the +-- page around the readme start at one, so no heading takes them. +local id_counts = {} + -- Lua patterns backtrack, so "%s+$" costs the square of a run of spaces in -- the middle of a line. Finding each end directly stays linear. @@ -204,6 +208,34 @@ local function shows_something(lines) return false end +local function plain_text(nodes, parts) + for _, node in ipairs(nodes) do + if node.kind == "text" or node.kind == "code" then + parts[#parts + 1] = node.text + elseif node.kids then + plain_text(node.kids, parts) + end + end + return parts +end + +-- Gives a heading the anchor GitHub would, so a readme's links to its own +-- sections work. That is its text in lower case, with punctuation dropped +-- and each space a hyphen, and a count added to a repeat. Bytes past ASCII +-- stay, keeping the letters of other scripts. +local function emit_id(nodes) + local base = table.concat(plain_text(nodes, {})):lower() + :gsub("[^%w_%- \128-\255]", ""):gsub(" ", "-") + if base == "" then + return + end + local count = id_counts[base] or 0 + id_counts[base] = count + 1 + html(" id='") + html_attr(count > 0 and base .. "-" .. count or base) + html("'") +end + local function emit_lines(lines) for i, line in ipairs(lines) do if i > 1 then @@ -219,7 +251,9 @@ emit_blocks = function(blocks) for _, block in ipairs(blocks) do local kind = block.kind if kind == "heading" then - html("") + html("") emit_inline(block.kids) html("") elseif kind == "hr" then @@ -778,6 +812,7 @@ function filter_open(name, base, query) tree_base = base or "" tree_query = query or "" chunks = {} + id_counts = { cgit = 1, header = 1, about = 1 } end function filter_write(str) -- cgit