Skip to content

Instantly share code, notes, and snippets.

@bpj
Last active September 18, 2018 15:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bpj/5513fc3fc4e33fc6330b693bcd9e4198 to your computer and use it in GitHub Desktop.
Save bpj/5513fc3fc4e33fc6330b693bcd9e4198 to your computer and use it in GitHub Desktop.
Pandoc filter to add anchors to option descriptions in CLI program documentation
--[[
pandoc options-anchors.lua
Pandoc filter which walks all definition lists in all divs with a class
`options-list` (or `optionslist` or `option-list` or `optionlist`) and
wraps all DL terms whose stringification starts with what looks like a
CLI option name[^1] in a span with an id `option-LONG-OPTION-NAME`,
where `LONG-OPTION-NAME` is the first long option name[^2] in the
stringified term. e.g.
```markdown_pandoc
:::options-list
`-C`, `--change`, `-m`, `--mogrify`
: Change things.
`--thing=`*STRING*
: Specify something
:::
```
becomes
```markdown_pandoc
:::options-list
[`-C`, `--change`, `-m`, `--mogrify`]{#option-change}
: Change things.
[`--thing=`*STRING*]{#option-thing}
: Specify something
:::
```
This is primarily intended for the Pandoc manual, but may be used for any
CLI program documentation document with similar layout.
[^1]: 'option-like' is defined as one or two hyphens followed by a
letter followed by zero or more hyphens or word characters.
[^2]: 'long-option-like' is defined as two hyphens followed by a letter
followed by one or more hyphens or word characters.
Author: Benct Philip Jonsson <bpjonsson@gmail.com>
]]
local p = pandoc
local u = pandoc.utils
-- from bpj's bag of tricks a perlism for sure...
local function first_idx (array, pattern)
for i,v in ipairs(array) do
local s = string.find(tostring(v), pattern)
if s ~= nil then return i end
end
return nil
end
local function get_option_id (term)
term = u.stringify(p.Emph(term))
local s = string.find(term, '^%-%-?%a[%-%w]*')
if s ~= nil then
local name = string.match(term, '%-%-(%a[%-%w]+)')
if name ~= nil then return 'option-' .. name end
end
return nil
end
local function is_element (value, t)
if type(value) ~= 'table' then return false end
if value.t and t == value.t then return true end
return false
end
local function span_with_id (inlines, id)
if #inlines < 1 then return {} end
if #inlines == 1 then
if is_element(inlines[1], 'Span') then
local span = inlines[1]
local old_id = span.identifier or ""
if old_id == id then return span end
if string.len(old_id) == 0 then
span.identifier = id
return { span }
end
end
end
return { p.Span(inlines, p.Attr(id)) }
end
local function option_anchors (div)
local is_opt_list = first_idx(div.classes, '^options?%-?list$')
if is_opt_list == nil then return end
return p.walk_block( div, {
DefinitionList = function (dl)
for _,pair in ipairs(dl.content) do
local id = get_option_id(pair[1])
if id ~= nil then
pair[1] = span_with_id(pair[1], id)
end
end
return dl
end
})
end
return { { Div = option_anchors } }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment