-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #28 from AlmogBaku/build/upgrade-docusaurus
build: upgrade docusaurus
- Loading branch information
Showing
7 changed files
with
9,475 additions
and
6,368 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
--[[ | ||
logging.lua: pandoc-aware logging functions (can also be used standalone) | ||
Copyright: (c) 2022 William Lupton | ||
License: MIT - see LICENSE file for details | ||
Usage: See README.md for details | ||
]] | ||
|
||
-- if running standalone, create a 'pandoc' global | ||
if not pandoc then | ||
_G.pandoc = {utils = {}} | ||
end | ||
|
||
-- if there's no pandoc.utils, create a local one | ||
if not pcall(require, 'pandoc.utils') then | ||
pandoc.utils = {} | ||
end | ||
|
||
-- if there's no pandoc.utils.type, create a local one | ||
if not pandoc.utils.type then | ||
pandoc.utils.type = function(value) | ||
local typ = type(value) | ||
if not ({table=1, userdata=1})[typ] then | ||
-- unchanged | ||
elseif value.__name then | ||
typ = value.__name | ||
elseif value.tag and value.t then | ||
typ = value.tag | ||
if typ:match('^Meta.') then | ||
typ = typ:sub(5) | ||
end | ||
if typ == 'Map' then | ||
typ = 'table' | ||
end | ||
end | ||
return typ | ||
end | ||
end | ||
|
||
-- namespace | ||
local logging = {} | ||
|
||
-- helper function to return a sensible typename | ||
logging.type = function(value) | ||
-- this can return 'Inlines', 'Blocks', 'Inline', 'Block' etc., or | ||
-- anything that built-in type() can return, namely 'nil', 'number', | ||
-- 'string', 'boolean', 'table', 'function', 'thread', or 'userdata' | ||
local typ = pandoc.utils.type(value) | ||
|
||
-- it seems that it can also return strings like 'pandoc Row'; replace | ||
-- spaces with periods | ||
-- XXX I'm not sure that this is done consistently, e.g. I don't think | ||
-- it's done for pandoc.Attr or pandoc.List? | ||
typ = typ:gsub(' ', '.') | ||
|
||
-- map Inline and Block to the tag name | ||
-- XXX I guess it's intentional that it doesn't already do this? | ||
return ({Inline=1, Block=1})[typ] and value.tag or typ | ||
end | ||
|
||
-- derived from https://www.lua.org/pil/19.3.html pairsByKeys() | ||
logging.spairs = function(list, comp) | ||
local keys = {} | ||
for key, _ in pairs(list) do | ||
table.insert(keys, tostring(key)) | ||
end | ||
table.sort(keys, comp) | ||
local i = 0 | ||
local iter = function() | ||
i = i + 1 | ||
return keys[i] and keys[i], list[keys[i]] or nil | ||
end | ||
return iter | ||
end | ||
|
||
-- helper function to dump a value with a prefix (recursive) | ||
-- XXX should detect repetition/recursion | ||
-- XXX would like maxlen logic to apply at all levels? but not trivial | ||
local function dump_(prefix, value, maxlen, level, add) | ||
local buffer = {} | ||
if prefix == nil then prefix = '' end | ||
if level == nil then level = 0 end | ||
if add == nil then add = function(item) table.insert(buffer, item) end end | ||
local indent = maxlen and '' or (' '):rep(level) | ||
|
||
-- get typename, mapping to pandoc tag names where possible | ||
local typename = logging.type(value) | ||
|
||
-- don't explicitly indicate 'obvious' typenames | ||
local typ = (({boolean=1, number=1, string=1, table=1, userdata=1}) | ||
[typename] and '' or typename) | ||
|
||
-- light userdata is just a pointer (can't iterate over it) | ||
-- XXX is there a better way of checking for light userdata? | ||
if type(value) == 'userdata' and not pcall(pairs(value)) then | ||
value = tostring(value):gsub('userdata:%s*', '') | ||
|
||
-- modify the value heuristically | ||
elseif ({table=1, userdata=1})[type(value)] then | ||
local valueCopy, numKeys, lastKey = {}, 0, nil | ||
for key, val in pairs(value) do | ||
-- pandoc >= 2.15 includes 'tag', nil values and functions | ||
if key ~= 'tag' and val and type(val) ~= 'function' then | ||
valueCopy[key] = val | ||
numKeys = numKeys + 1 | ||
lastKey = key | ||
end | ||
end | ||
if numKeys == 0 then | ||
-- this allows empty tables to be formatted on a single line | ||
-- XXX experimental: render Doc objects | ||
value = typename == 'Doc' and '|' .. value:render() .. '|' or | ||
typename == 'Space' and '' or '{}' | ||
elseif numKeys == 1 and lastKey == 'text' then | ||
-- this allows text-only types to be formatted on a single line | ||
typ = typename | ||
value = value[lastKey] | ||
typename = 'string' | ||
else | ||
value = valueCopy | ||
-- XXX experimental: indicate array sizes | ||
if #value > 0 then | ||
typ = typ .. '[' .. #value .. ']' | ||
end | ||
end | ||
end | ||
|
||
-- output the possibly-modified value | ||
local presep = #prefix > 0 and ' ' or '' | ||
local typsep = #typ > 0 and ' ' or '' | ||
local valtyp = type(value) | ||
if valtyp == 'nil' then | ||
add('nil') | ||
elseif ({boolean=1, number=1, string=1})[valtyp] then | ||
typsep = #typ > 0 and valtyp == 'string' and #value > 0 and ' ' or '' | ||
-- don't use the %q format specifier; doesn't work with multi-bytes | ||
local quo = typename == 'string' and '"' or '' | ||
add(string.format('%s%s%s%s%s%s%s%s', indent, prefix, presep, typ, | ||
typsep, quo, value, quo)) | ||
-- light userdata is just a pointer (can't iterate over it) | ||
-- XXX is there a better way of checking for light userdata? | ||
elseif valtyp == 'userdata' and not pcall(pairs(value)) then | ||
add(string.format('%s%s%s%s %s', indent, prefix, presep, typ, | ||
tostring(value):gsub('userdata:%s*', ''))) | ||
elseif ({table=1, userdata=1})[valtyp] then | ||
add(string.format('%s%s%s%s%s{', indent, prefix, presep, typ, typsep)) | ||
-- Attr and Attr.attributes have both numeric and string keys, so | ||
-- ignore the numeric ones | ||
-- XXX this is no longer the case for pandoc >= 2.15, so could remove | ||
-- the special case? | ||
local first = true | ||
if prefix ~= 'attributes:' and typ ~= 'Attr' then | ||
for i, val in ipairs(value) do | ||
local pre = maxlen and not first and ', ' or '' | ||
dump_(string.format('%s[%s]', pre, i), val, maxlen, | ||
level + 1, add) | ||
first = false | ||
end | ||
end | ||
-- report keys in alphabetical order to ensure repeatability | ||
for key, val in logging.spairs(value) do | ||
local pre = maxlen and not first and ', ' or '' | ||
-- this check can avoid an infinite loop, e.g. with metatables | ||
-- XXX should have more general and robust infinite loop avoidance | ||
if key:match('^__') and type(val) ~= 'string' then | ||
add(string.format('%s%s: %s', pre, key, tostring(val))) | ||
|
||
-- pandoc >= 2.15 includes 'tag' | ||
elseif not tonumber(key) and key ~= 'tag' then | ||
dump_(string.format('%s%s:', pre, key), val, maxlen, | ||
level + 1, add) | ||
end | ||
first = false | ||
end | ||
add(string.format('%s}', indent)) | ||
end | ||
return table.concat(buffer, maxlen and '' or '\n') | ||
end | ||
|
||
logging.dump = function(value, maxlen) | ||
if maxlen == nil then maxlen = 70 end | ||
local text = dump_(nil, value, maxlen) | ||
if #text > maxlen then | ||
text = dump_(nil, value, nil) | ||
end | ||
return text | ||
end | ||
|
||
logging.output = function(...) | ||
local need_newline = false | ||
for i, item in ipairs({...}) do | ||
-- XXX space logic could be cleverer, e.g. no space after newline | ||
local maybe_space = i > 1 and ' ' or '' | ||
local text = ({table=1, userdata=1})[type(item)] and | ||
logging.dump(item) or tostring(item) | ||
io.stderr:write(maybe_space, text) | ||
need_newline = text:sub(-1) ~= '\n' | ||
end | ||
if need_newline then | ||
io.stderr:write('\n') | ||
end | ||
end | ||
|
||
-- basic logging support (-1=errors, 0=warnings, 1=info, 2=debug, 3=debug2) | ||
-- XXX should support string levels? | ||
logging.loglevel = 0 | ||
|
||
-- set log level and return the previous level | ||
logging.setloglevel = function(loglevel) | ||
local oldlevel = logging.loglevel | ||
logging.loglevel = loglevel | ||
return oldlevel | ||
end | ||
|
||
-- verbosity default is WARNING; --quiet -> ERROR and --verbose -> INFO | ||
-- --trace sets TRACE or DEBUG (depending on --verbose) | ||
if type(PANDOC_STATE) == 'nil' then | ||
-- use the default level | ||
elseif PANDOC_STATE.trace then | ||
logging.loglevel = PANDOC_STATE.verbosity == 'INFO' and 3 or 2 | ||
elseif PANDOC_STATE.verbosity == 'INFO' then | ||
logging.loglevel = 1 | ||
elseif PANDOC_STATE.verbosity == 'WARNING' then | ||
logging.loglevel = 0 | ||
elseif PANDOC_STATE.verbosity == 'ERROR' then | ||
logging.loglevel = -1 | ||
end | ||
|
||
logging.error = function(...) | ||
if logging.loglevel >= -1 then | ||
logging.output('(E)', ...) | ||
end | ||
end | ||
|
||
logging.warning = function(...) | ||
if logging.loglevel >= 0 then | ||
logging.output('(W)', ...) | ||
end | ||
end | ||
|
||
logging.info = function(...) | ||
if logging.loglevel >= 1 then | ||
logging.output('(I)', ...) | ||
end | ||
end | ||
|
||
logging.debug = function(...) | ||
if logging.loglevel >= 2 then | ||
logging.output('(D)', ...) | ||
end | ||
end | ||
|
||
logging.debug2 = function(...) | ||
if logging.loglevel >= 3 then | ||
logging.warning('debug2() is deprecated; use trace()') | ||
logging.output('(D2)', ...) | ||
end | ||
end | ||
|
||
logging.trace = function(...) | ||
if logging.loglevel >= 3 then | ||
logging.output('(T)', ...) | ||
end | ||
end | ||
|
||
-- for temporary unconditional debug output | ||
logging.temp = function(...) | ||
logging.output('(#)', ...) | ||
end | ||
|
||
return logging |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.