Skip to content

Commit 9ac3f6e

Browse files
committed
refactor: move some generator utility functions into separate file
1 parent 02c43e7 commit 9ac3f6e

File tree

2 files changed

+158
-143
lines changed

2 files changed

+158
-143
lines changed

_scripts/mini_nvim.lua

Lines changed: 11 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
-- Utility ====================================================================
2-
local reflow = function(lines)
3-
local new_lines = vim.split(table.concat(lines, '\n'), '\n')
4-
for i, l in ipairs(new_lines) do
5-
lines[i] = l
6-
end
7-
end
8-
9-
local is_blank = function(x) return x:find('^%s*$') ~= nil end
10-
11-
local make_anchor = function(x)
12-
-- Improve anchor for versions. This also removes any prerelease indicators.
13-
if x:find('^[Vv]ersion ') ~= nil then x = 'v' .. x:match('[%d%.]+') end
14-
15-
-- Manual heading anchors in Pandoc (like "# Heading {#my-heading}") don't
16-
-- work with a lot of non-alphanumeric chars (like "(" / ")" / "'"). Remove
17-
-- them to sanitaize anchors.
18-
-- The `<xxx>` in anchor can be confused for HTML tag. Escape it.
19-
return (x:lower():gsub('[^%w%.%-_]', ''):gsub('%s', '-'):gsub('<(.-)>', '\\<%1\\>'))
20-
end
2+
local util = dofile('_scripts/util.lua')
3+
4+
local reflow = util.reflow
5+
local is_blank = util.is_blank
6+
local make_anchor = util.make_anchor
7+
local get_help_tags = util.get_help_tags
8+
local iter_noncode = util.iter_noncode
9+
local add_hierarchical_heading_anchors = util.add_hierarchical_heading_anchors
10+
local add_source_note = util.add_source_note
11+
local adjust_header_footer = util.adjust_header_footer
12+
local replace_quote_alerts = util.replace_quote_alerts
2113

2214
-- Metadata ===================================================================
2315
local metadata_lines = {
@@ -32,18 +24,6 @@ local metadata_lines = {
3224
vim.fn.writefile(metadata_lines, 'mini.nvim/_metadata.yml')
3325

3426
-- Help files =================================================================
35-
local get_help_tags = function()
36-
local tags_path = '_deps/mini.nvim/doc/tags'
37-
if vim.uv.fs_stat(tags_path) == nil then vim.cmd('helptags _deps/mini.nvim/doc') end
38-
39-
local tags = {}
40-
for _, l in ipairs(vim.fn.readfile(tags_path)) do
41-
local tag, basename = l:match('^(.-)\t(.-)%.txt\t')
42-
tags[tag] = basename
43-
end
44-
return tags
45-
end
46-
4727
local make_codeblocks = function(lines)
4828
local codeblock_start, cur_indent
4929
local empty_at_codeblock_start = {}
@@ -77,20 +57,6 @@ local make_codeblocks = function(lines)
7757
reflow(lines)
7858
end
7959

80-
local iter_noncode = function(lines)
81-
local n = #lines
82-
local f = function(_, i)
83-
if i >= n then return nil end
84-
i = i + 1
85-
if lines[i]:find('^ *```%w*$') == nil then return i, lines[i] end
86-
for j = i + 1, n do
87-
if lines[j]:find('^ *```$') ~= nil and j < n then return j + 1, lines[j + 1] end
88-
end
89-
return nil
90-
end
91-
return f, {}, 0
92-
end
93-
9460
local adjust_rulers = function(lines)
9561
for i, l in iter_noncode(lines) do
9662
if l:find('^=+$') ~= nil or l:find('^-+$') ~= nil then lines[i] = '---\n' end
@@ -242,65 +208,6 @@ local adjust_alignment = function(lines)
242208
end
243209
end
244210

245-
local add_hierarchical_heading_anchors = function(lines)
246-
local anchor_stack = {}
247-
for i, l in iter_noncode(lines) do
248-
-- Reuse already present anchor and other extra pandoc related data
249-
-- (like from right aligned tag heading with its own anchor and class).
250-
-- Anchors should only be present for the "top level" headings.
251-
local header_prefix, header_name, header_anchor, header_extra = l:match('^(#+)%s+(.-) {#([^%s}]+)(.*)}$')
252-
if header_anchor == nil then
253-
header_prefix, header_name = l:match('^(#+)%s+(.+)$')
254-
header_extra = ''
255-
end
256-
257-
if header_prefix ~= nil and header_name ~= nil then
258-
header_anchor = header_anchor or make_anchor(header_name)
259-
260-
-- Modify stack
261-
local header_level = header_prefix:len()
262-
anchor_stack[header_level] = header_anchor
263-
-- NOTE: Take into account that `anchor_stack` can have holes if headings
264-
-- are not in consecutive levels
265-
for k, _ in pairs(anchor_stack) do
266-
if k > header_level then anchor_stack[k] = nil end
267-
end
268-
269-
-- Add anchor
270-
local keys = vim.tbl_keys(anchor_stack)
271-
table.sort(keys)
272-
local anchor = table.concat(vim.tbl_map(function(k) return anchor_stack[k] end, keys), '-')
273-
lines[i] = string.format('%s %s {#%s%s}', header_prefix, header_name, anchor, header_extra)
274-
end
275-
end
276-
end
277-
278-
local add_source_note = function(lines)
279-
local msg = "_Generated from the `main` branch of 'mini.nvim'_"
280-
if lines[1]:find('align="center"') ~= nil then
281-
-- Center align if after center aligned element (i.e. top README image)
282-
table.insert(lines, 2, '<p align="center">' .. msg .. '</p>')
283-
table.insert(lines, 3, '')
284-
else
285-
table.insert(lines, 1, msg)
286-
table.insert(lines, 2, '')
287-
end
288-
end
289-
290-
local adjust_header_footer = function(lines, title)
291-
-- Add informative header for better search
292-
table.insert(lines, 1, '---')
293-
table.insert(lines, 2, string.format('title: "%s"', title))
294-
table.insert(lines, 3, '---')
295-
table.insert(lines, 4, '')
296-
297-
-- Remove modeline
298-
if lines[#lines]:find('^ vim:') then
299-
lines[#lines] = nil
300-
lines[#lines] = nil
301-
end
302-
end
303-
304211
local create_help = function()
305212
local help_tags = get_help_tags()
306213

@@ -346,45 +253,6 @@ local replace_demo_link = function(lines)
346253
end
347254
end
348255

349-
local replace_quote_alerts = function(lines)
350-
-- Quotes on GitHub can start with special "Alert" syntax for special render.
351-
-- The syntax is `> [!<kind>]`. Like `> [!NOTE]` or `> [!TIP]`.
352-
-- Quarto has similar thing but it is called callout blocks and the syntax
353-
-- is different. Thankfully, kinds are the same, just lowercase.
354-
--
355-
-- Sources:
356-
-- https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts
357-
-- https://quarto.org/docs/authoring/callouts.html#callout-types
358-
local allowed_kinds = {
359-
NOTE = true,
360-
TIP = true,
361-
IMPORTANT = true,
362-
WARNING = true,
363-
CAUTION = true,
364-
}
365-
366-
local alert_start, alert_kind, alert_indent
367-
local n_repl, n_lines = 0, #lines
368-
for i, l in iter_noncode(lines) do
369-
if alert_start == nil then
370-
alert_indent, alert_kind = l:match('^(%s*)>%s+%[!(%w+)%]$')
371-
if allowed_kinds[alert_kind] ~= nil and is_blank(lines[i - 1] or '') then alert_start = i end
372-
else
373-
-- Remove quotes of the whole block until it ends.
374-
-- Accout for possible quote alert at last or second to last line.
375-
lines[i], n_repl = l:gsub('^%s*>%s+', alert_indent)
376-
if n_repl == 0 or i == n_lines then
377-
lines[alert_start] = string.format('%s::: {.callout-%s}', alert_indent, alert_kind:lower())
378-
lines[i] = n_repl == 0 and (alert_indent .. ':::\n' .. l) or (l .. '\n' .. alert_indent .. ':::')
379-
380-
alert_start, alert_kind = nil, nil
381-
end
382-
end
383-
end
384-
385-
reflow(lines)
386-
end
387-
388256
local replace_help_links = function(lines)
389257
for i, l in ipairs(lines) do
390258
lines[i] = l:gsub('%(%.%./doc/(.-)%.txt%)', '(../doc/%1.qmd)'):gsub('%(doc/(.-)%.txt%)', '(doc/%1.qmd)')

_scripts/util.lua

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
local M = {}
2+
3+
M.reflow = function(lines)
4+
local new_lines = vim.split(table.concat(lines, '\n'), '\n')
5+
for i, l in ipairs(new_lines) do
6+
lines[i] = l
7+
end
8+
end
9+
10+
M.is_blank = function(x) return x:find('^%s*$') ~= nil end
11+
12+
M.make_anchor = function(x)
13+
-- Improve anchor for versions. This also removes any prerelease indicators.
14+
if x:find('^[Vv]ersion ') ~= nil then x = 'v' .. x:match('[%d%.]+') end
15+
16+
-- Manual heading anchors in Pandoc (like "# Heading {#my-heading}") don't
17+
-- work with a lot of non-alphanumeric chars (like "(" / ")" / "'"). Remove
18+
-- them to sanitaize anchors.
19+
-- The `<xxx>` in anchor can be confused for HTML tag. Escape it.
20+
return (x:lower():gsub('[^%w%.%-_]', ''):gsub('%s', '-'):gsub('<(.-)>', '\\<%1\\>'))
21+
end
22+
23+
M.get_help_tags = function(tags_path)
24+
tags_path = tags_path or '_deps/mini.nvim/doc/tags'
25+
if vim.uv.fs_stat(tags_path) == nil then vim.cmd('helptags _deps/mini.nvim/doc') end
26+
27+
local tags = {}
28+
for _, l in ipairs(vim.fn.readfile(tags_path)) do
29+
local tag, basename = l:match('^(.-)\t(.-)%.txt\t')
30+
tags[tag] = basename
31+
end
32+
return tags
33+
end
34+
35+
M.iter_noncode = function(lines)
36+
local n = #lines
37+
local f = function(_, i)
38+
if i >= n then return nil end
39+
i = i + 1
40+
if lines[i]:find('^ *```%w*$') == nil then return i, lines[i] end
41+
for j = i + 1, n do
42+
if lines[j]:find('^ *```$') ~= nil and j < n then return j + 1, lines[j + 1] end
43+
end
44+
return nil
45+
end
46+
return f, {}, 0
47+
end
48+
49+
M.add_hierarchical_heading_anchors = function(lines)
50+
local anchor_stack = {}
51+
for i, l in M.iter_noncode(lines) do
52+
-- Reuse already present anchor and other extra pandoc related data
53+
-- (like from right aligned tag heading with its own anchor and class).
54+
-- Anchors should only be present for the "top level" headings.
55+
local header_prefix, header_name, header_anchor, header_extra = l:match('^(#+)%s+(.-) {#([^%s}]+)(.*)}$')
56+
if header_anchor == nil then
57+
header_prefix, header_name = l:match('^(#+)%s+(.+)$')
58+
header_extra = ''
59+
end
60+
61+
if header_prefix ~= nil and header_name ~= nil then
62+
header_anchor = header_anchor or M.make_anchor(header_name)
63+
64+
-- Modify stack
65+
local header_level = header_prefix:len()
66+
anchor_stack[header_level] = header_anchor
67+
-- NOTE: Take into account that `anchor_stack` can have holes if headings
68+
-- are not in consecutive levels
69+
for k, _ in pairs(anchor_stack) do
70+
if k > header_level then anchor_stack[k] = nil end
71+
end
72+
73+
-- Add anchor
74+
local keys = vim.tbl_keys(anchor_stack)
75+
table.sort(keys)
76+
local anchor = table.concat(vim.tbl_map(function(k) return anchor_stack[k] end, keys), '-')
77+
lines[i] = string.format('%s %s {#%s%s}', header_prefix, header_name, anchor, header_extra)
78+
end
79+
end
80+
end
81+
82+
M.add_source_note = function(lines)
83+
local msg = "_Generated from the `main` branch of 'mini.nvim'_"
84+
if lines[1]:find('align="center"') ~= nil then
85+
-- Center align if after center aligned element (i.e. top README image)
86+
table.insert(lines, 2, '<p align="center">' .. msg .. '</p>')
87+
table.insert(lines, 3, '')
88+
else
89+
table.insert(lines, 1, msg)
90+
table.insert(lines, 2, '')
91+
end
92+
end
93+
94+
M.adjust_header_footer = function(lines, title)
95+
-- Add informative header for better search
96+
table.insert(lines, 1, '---')
97+
table.insert(lines, 2, string.format('title: "%s"', title))
98+
table.insert(lines, 3, '---')
99+
table.insert(lines, 4, '')
100+
101+
-- Remove modeline
102+
if lines[#lines]:find('^ vim:') then
103+
lines[#lines] = nil
104+
lines[#lines] = nil
105+
end
106+
end
107+
108+
M.replace_quote_alerts = function(lines)
109+
-- Quotes on GitHub can start with special "Alert" syntax for special render.
110+
-- The syntax is `> [!<kind>]`. Like `> [!NOTE]` or `> [!TIP]`.
111+
-- Quarto has similar thing but it is called callout blocks and the syntax
112+
-- is different. Thankfully, kinds are the same, just lowercase.
113+
--
114+
-- Sources:
115+
-- https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts
116+
-- https://quarto.org/docs/authoring/callouts.html#callout-types
117+
local allowed_kinds = {
118+
NOTE = true,
119+
TIP = true,
120+
IMPORTANT = true,
121+
WARNING = true,
122+
CAUTION = true,
123+
}
124+
125+
local alert_start, alert_kind, alert_indent
126+
local n_repl, n_lines = 0, #lines
127+
for i, l in M.iter_noncode(lines) do
128+
if alert_start == nil then
129+
alert_indent, alert_kind = l:match('^(%s*)>%s+%[!(%w+)%]$')
130+
if allowed_kinds[alert_kind] ~= nil and M.is_blank(lines[i - 1] or '') then alert_start = i end
131+
else
132+
-- Remove quotes of the whole block until it ends.
133+
-- Accout for possible quote alert at last or second to last line.
134+
lines[i], n_repl = l:gsub('^%s*>%s+', alert_indent)
135+
if n_repl == 0 or i == n_lines then
136+
lines[alert_start] = string.format('%s::: {.callout-%s}', alert_indent, alert_kind:lower())
137+
lines[i] = n_repl == 0 and (alert_indent .. ':::\n' .. l) or (l .. '\n' .. alert_indent .. ':::')
138+
139+
alert_start, alert_kind = nil, nil
140+
end
141+
end
142+
end
143+
144+
M.reflow(lines)
145+
end
146+
147+
return M

0 commit comments

Comments
 (0)