diff options
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
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.
Diffstat (limited to 'custom/extensions/about-render.lua')
-rw-r--r--custom/extensions/about-render.lua37
1 file changed, 36 insertions, 1 deletion
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("<h" .. block.level .. ">")
+ html("<h" .. block.level)
+ emit_id(block.kids)
+ html(">")
emit_inline(block.kids)
html("</h" .. block.level .. ">")
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)