html filter finished
This commit is contained in:
parent
69c2e0545f
commit
9242d38ecf
@ -1,5 +1,7 @@
|
||||
pandoc -t native --ipynb-output=best 2_NumTypes.ipynb |jq
|
||||
|
||||
pandoc -t html --ipynb-output=all --lua-filter=ansi2html.lua -s --katex 2_NumTypes.ipynb > aaa.html
|
||||
|
||||
quarto commit:
|
||||
https://github.com/quarto-dev/quarto-cli/commit/2bd7b8719ecf8916f5754c0f3ac63ba5d7597c31
|
||||
https://github.com/quarto-dev/quarto-cli/issues/929
|
||||
|
302
ansi2html.lua
302
ansi2html.lua
@ -4,6 +4,72 @@
|
||||
-- https://github.com/jupyter/nbconvert/blob/main/nbconvert/filters/ansi.py
|
||||
-- converted to lua
|
||||
|
||||
-- good list of ANSI escape sequences:
|
||||
-- https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
||||
|
||||
local css = [[
|
||||
<!-- CSS added by ANSI escape sequences filter -->
|
||||
<style>
|
||||
.ansi {line-height:1; padding:0; margin: 0; letter-spacing:0;font-family:JuliaMono;}
|
||||
|
||||
/* console foregrounds and backgrounds */
|
||||
pre .ansi-black-fg { color: #3e424d; }
|
||||
pre .ansi-red-fg { color: #e75c58; }
|
||||
pre .ansi-green-fg { color: #00a250; }
|
||||
pre .ansi-yellow-fg { color: #ddb62b; }
|
||||
pre .ansi-blue-fg { color: #208ffb; }
|
||||
pre .ansi-magenta-fg { color: #d160c4; }
|
||||
pre .ansi-cyan-fg { color: #60c6c8; }
|
||||
pre .ansi-white-fg { color: #c5c1b4; }
|
||||
pre .ansi-black-bg { background-color: #3e424d; }
|
||||
pre .ansi-red-bg { background-color: #e75c58; }
|
||||
pre .ansi-green-bg { background-color: #00a250; }
|
||||
pre .ansi-yellow-bg { background-color: #ddb62b; }
|
||||
pre .ansi-blue-bg { background-color: #208ffb; }
|
||||
pre .ansi-magenta-bg { background-color: #d160c4; }
|
||||
pre .ansi-cyan-bg { background-color: #60c6c8; }
|
||||
pre .ansi-white-bg { background-color: #c5c1b4; }
|
||||
pre .ansi-black-intense-fg { color: #282c36; }
|
||||
pre .ansi-red-intense-fg { color: #b22b31; }
|
||||
pre .ansi-green-intense-fg { color: #007427; }
|
||||
pre .ansi-yellow-intense-fg { color: #b27d12; }
|
||||
pre .ansi-blue-intense-fg { color: #0065ca; }
|
||||
pre .ansi-magenta-intense-fg { color: #a03196; }
|
||||
pre .ansi-cyan-intense-fg { color: #258f8f; }
|
||||
pre .ansi-white-intense-fg { color: #a1a6b2; }
|
||||
pre .ansi-black-intense-bg { background-color: #282c36; }
|
||||
pre .ansi-red-intense-bg { background-color: #b22b31; }
|
||||
pre .ansi-green-intense-bg { background-color: #007427; }
|
||||
pre .ansi-yellow-intense-bg { background-color: #b27d12; }
|
||||
pre .ansi-blue-intense-bg { background-color: #0065ca; }
|
||||
pre .ansi-magenta-intense-bg { background-color: #a03196; }
|
||||
pre .ansi-cyan-intense-bg { background-color: #258f8f; }
|
||||
pre .ansi-white-intense-bg { background-color: #a1a6b2; }
|
||||
pre .ansi-default-inverse-fg { color: rgba(255, 255, 255, 1); }
|
||||
pre .ansi-default-inverse-bg { background-color: #111111; }
|
||||
pre .ansi-bold { font-weight: bold; }
|
||||
pre .ansi-underline { text-decoration: underline; }
|
||||
</style>
|
||||
]]
|
||||
|
||||
local latexpreamble = [[
|
||||
\usepackage{fancyvrb}
|
||||
\usepackage{fontspec}
|
||||
\renewenvironment{verbatim}{%
|
||||
\VerbatimEnvironment
|
||||
\begin{Verbatim}[commandchars=\\\{\}]%
|
||||
}{%
|
||||
\end{Verbatim}%
|
||||
}
|
||||
\setmonofont{JuliaMono}[
|
||||
Scale = MatchLowercase,
|
||||
UprightFont = *-Regular,
|
||||
BoldFont = *-Bold,
|
||||
ItalicFont = *-RegularItalic,
|
||||
BoldItalicFont = *-BoldItalic,
|
||||
]
|
||||
]]
|
||||
|
||||
local ANSI_COLORS = {
|
||||
"ansi-black",
|
||||
"ansi-red",
|
||||
@ -23,48 +89,77 @@ local ANSI_COLORS = {
|
||||
"ansi-white-intense"
|
||||
}
|
||||
|
||||
--[[
|
||||
local flag = false -- set to true if we find ANSI sequences, used by Meta
|
||||
|
||||
local function get_extended_color(numbers)
|
||||
local n = table.remove(numbers, 1)
|
||||
local r,g,b,idx
|
||||
if n == 2 and #numbers >=3 then
|
||||
-- 24bit RGB
|
||||
r = table.remove(numbers, 1)
|
||||
g = table.remove(numbers, 1)
|
||||
b = table.remove(numbers, 1)
|
||||
elseif n == 5 and #numbers >= 1 then
|
||||
-- 256 colors
|
||||
idx = table.remove(numbers, 1)
|
||||
if idx < 16 then
|
||||
-- 16 default terminal colors
|
||||
return idx
|
||||
elseif idx < 232 then
|
||||
-- 6x6x6 color cube, see http://stackoverflow.com/a/27165165/500098
|
||||
r = (idx - 16) // 36
|
||||
r = 55 + r * 40
|
||||
if r < 0 then r = 0 end
|
||||
g = ((idx - 16) % 36) // 6
|
||||
g = 55 + g * 40
|
||||
if g < 0 then g = 0 end
|
||||
b = (idx - 16) % 6
|
||||
b = 55 + b * 40
|
||||
if b < 0 then b = 0 end
|
||||
elseif idx < 256 then
|
||||
-- grayscale, see http://stackoverflow.com/a/27165165/500098
|
||||
r = (idx - 232) * 10 + 8
|
||||
g = r
|
||||
b = r
|
||||
end
|
||||
end
|
||||
return {r, g, b}
|
||||
end
|
||||
|
||||
|
||||
--[=[
|
||||
local re = require "re"
|
||||
|
||||
local codes = {
|
||||
-- attributes
|
||||
reset = 0,
|
||||
bright = 1,
|
||||
dim = 2,
|
||||
underscore = 4,
|
||||
-- blink = 5,
|
||||
reverse = 7,
|
||||
-- hidden = 8,
|
||||
|
||||
-- foreground
|
||||
black = 30,
|
||||
red = 31,
|
||||
green = 32,
|
||||
yellow = 33,
|
||||
blue = 34,
|
||||
magenta = 35,
|
||||
cyan = 36,
|
||||
white = 37,
|
||||
|
||||
-- background
|
||||
onblack = 40,
|
||||
onred = 41,
|
||||
ongreen = 42,
|
||||
onyellow = 43,
|
||||
onblue = 44,
|
||||
onmagenta = 45,
|
||||
oncyan = 46,
|
||||
onwhite = 47,
|
||||
}
|
||||
|
||||
local ANSI = re.compile [[
|
||||
'\x1b%[' {.*?} {[@-~]}
|
||||
]]
|
||||
|
||||
--]]
|
||||
--]=]
|
||||
|
||||
local function LaTeXconverter()
|
||||
local function LaTeXconverter(fg, bg, bold, underline, inverse)
|
||||
if not (fg or bg or bold or underline or inverse) then
|
||||
return "",""
|
||||
end
|
||||
|
||||
local starttag = ""
|
||||
local endtag = ""
|
||||
|
||||
if inverse then
|
||||
fg, bg = bg, fg
|
||||
end
|
||||
|
||||
if type(fg) == "number" then
|
||||
starttag = starttag .. "\\textcolor{" .. ANSI_COLORS[fg+1] .. "}{"
|
||||
endtag = "}" .. endtag
|
||||
elseif type(fg) == "table" then
|
||||
-- See http://tex.stackexchange.com/a/291102/13684
|
||||
starttag = starttag .. "\\def\\tcRGB{\\textcolor[RGB]}\\expandafter"
|
||||
starttag = starttag .. "\\tcRGB\\expandafter{\\detokenize{%s,%s,%s}}{" % fg
|
||||
endtag = "}" .. endtag
|
||||
elseif inverse then
|
||||
starttag = starttag .. "\\textcolor{ansi-default-inverse-fg}{"
|
||||
endtag = "}" .. endtag
|
||||
end
|
||||
end
|
||||
|
||||
local function HTMLconverter(fg, bg, bold, underline, inverse)
|
||||
@ -73,25 +168,27 @@ local function HTMLconverter(fg, bg, bold, underline, inverse)
|
||||
end
|
||||
local classes = {}
|
||||
local styles = {}
|
||||
|
||||
local type = type -- more efficient?
|
||||
local next = next
|
||||
if inverse then
|
||||
fg, bg = bg, fg
|
||||
end
|
||||
|
||||
if type(fg) == "number" then
|
||||
table.insert(classes, ANSI_COLORS[fg] .. "-fg")
|
||||
elseif fg then
|
||||
table.insert(classes, ANSI_COLORS[fg+1] .. "-fg")
|
||||
elseif type(fg) == "table" then
|
||||
table.insert(styles, string.format("color: rgb(%d,%d,%d)", fg[1], fg[2], fg[3]))
|
||||
elseif inverse then
|
||||
table.insert(classes,"ansi-default-inverse-fg")
|
||||
table.insert(classes, "ansi-default-inverse-fg")
|
||||
end
|
||||
|
||||
if type(bg) == "number" then
|
||||
table.insert(classes, ANSI_COLORS[bg] .. "-bg")
|
||||
elseif bg then
|
||||
table.insert(styles, string.format("background-color: rgb(%d,%d,%d)", bg[1], bg[2], bg[3]))
|
||||
table.insert(classes, ANSI_COLORS[bg+1] .. "-bg")
|
||||
elseif type(bg) == "table" then
|
||||
table.insert(styles, string.format("background-color: rgb(%d,%d,%d)",
|
||||
bg[1], bg[2], bg[3]))
|
||||
elseif inverse then
|
||||
table.insert(classes,"ansi-default-inverse-bg")
|
||||
table.insert(classes, "ansi-default-inverse-bg")
|
||||
end
|
||||
|
||||
if bold then
|
||||
@ -103,56 +200,63 @@ local function HTMLconverter(fg, bg, bold, underline, inverse)
|
||||
end
|
||||
|
||||
local starttag = "<span"
|
||||
if classes then
|
||||
if next(classes) ~= nil then
|
||||
starttag = starttag .. ' class="' .. table.concat(classes, " ") .. '"'
|
||||
end
|
||||
|
||||
if styles then
|
||||
if next(styles) ~= nil then
|
||||
starttag = starttag .. ' style="' .. table.concat(styles, " ") .. '"'
|
||||
end
|
||||
|
||||
return starttag,"</span>"
|
||||
return starttag..">","</span>"
|
||||
end
|
||||
|
||||
|
||||
function CodeBlock(e)
|
||||
local converter
|
||||
local function codeBlockTrans(e)
|
||||
local converter, fmt
|
||||
if FORMAT:match 'latex' then
|
||||
converter = LaTeXconverter
|
||||
fmt = 'latex'
|
||||
elseif FORMAT:match 'html' then
|
||||
converter = HTMLconverter
|
||||
fmt = 'html'
|
||||
elseif FORMAT:match 'native' then
|
||||
converter = HTMLconverter
|
||||
fmt = 'html'
|
||||
else
|
||||
return
|
||||
end
|
||||
local out=""
|
||||
if string.find(e.text, "\x1b%[") then
|
||||
flag = true
|
||||
local bold = false
|
||||
local underline = false
|
||||
local inverse = false
|
||||
local text = e.text
|
||||
local out = ""
|
||||
local chunk = ""
|
||||
local fg = {}
|
||||
local bg = {}
|
||||
local fg = nil
|
||||
local bg = nil
|
||||
local starttag = ""
|
||||
local endtag = ""
|
||||
local numbers={}
|
||||
|
||||
while text do
|
||||
while text ~= "" do
|
||||
numbers = {}
|
||||
local s1, e1, c1, d1 = string.find(text, "\x1b%[(.-)([@-~])")
|
||||
if s1 then
|
||||
if d1 == "m" then
|
||||
local numbers={}
|
||||
for i in string.gmatch(c1, "[^;]") do
|
||||
for i in string.gmatch(c1, "([^;]*)") do
|
||||
table.insert(numbers, tonumber(i))
|
||||
end
|
||||
else
|
||||
io.stderr:write("Unsupported ANSI sequence ESC["..c1..d1.." ignored\n" )
|
||||
end
|
||||
chunk, text = text:sub(1, s1-1), text:sub(e1+1)
|
||||
else
|
||||
chunk, text = text, ""
|
||||
end
|
||||
|
||||
if chunk then
|
||||
if chunk ~= "" then
|
||||
if bold and type(fg)=="number" and fg<8 then
|
||||
starttag, endtag = converter(fg+8, bg, bold, underline, inverse)
|
||||
else
|
||||
@ -160,7 +264,95 @@ function CodeBlock(e)
|
||||
end
|
||||
out = out .. starttag .. chunk .. endtag
|
||||
end
|
||||
end
|
||||
|
||||
while next(numbers) ~= nil do
|
||||
local n = table.remove(numbers, 1)
|
||||
if n == 0 then
|
||||
fg = nil
|
||||
bg = nil
|
||||
bold = false
|
||||
inverse = false
|
||||
underline = false
|
||||
elseif n == 1 then
|
||||
bold = true
|
||||
elseif n == 4 then
|
||||
underline = true
|
||||
elseif n == 5 then
|
||||
bold = true -- 'blinking'
|
||||
elseif n == 7 then
|
||||
inverse = true
|
||||
elseif n == 21 or n == 22 then
|
||||
bold = false
|
||||
elseif n == 24 then
|
||||
underline = false
|
||||
elseif n == 27 then
|
||||
inverse = false
|
||||
elseif n >= 30 and n <= 37 then
|
||||
fg = n - 30
|
||||
elseif n == 38 then
|
||||
fg = get_extended_color(numbers)
|
||||
elseif n == 39 then
|
||||
fg = nil
|
||||
elseif n >= 40 and n <= 47 then
|
||||
bg = n - 40
|
||||
elseif n == 48 then
|
||||
bg = get_extended_color(numbers)
|
||||
elseif n == 49 then
|
||||
bg = nil
|
||||
elseif n >= 90 and n <= 97 then
|
||||
fg = n + 8 - 90
|
||||
elseif n >= 100 and n <= 107 then
|
||||
bg = n + 8 - 100
|
||||
else
|
||||
io.stderr:write(string.format("ESC sequence with unknown code %d before:\n",n))
|
||||
io.stderr:write(chunk.."\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
-- e.text = out
|
||||
return pandoc.RawBlock(fmt, '<pre class="ansi"><code class="ansi">'..out..'</code></pre>')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- traverse='topdown'
|
||||
-- algo from https://github.com/jgm/pandoc/commit/77faccb505992c944cd1b92f50e4e00d2927682b
|
||||
local function divx(e)
|
||||
if e.classes[1] == "output" then
|
||||
print("output div entered")
|
||||
local c = e.content -- enhanced pandoc.List table
|
||||
local ranks = {}
|
||||
local best = 0
|
||||
for i, el in pairs(c) do
|
||||
print (i .. el.t)
|
||||
if el.t == "RawBlock" then
|
||||
print(el.format)
|
||||
else
|
||||
ranks:insert({rank = 2, i, el})
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function metaAdd(meta)
|
||||
if flag then
|
||||
-- read current "header-includes" from metadata, or make a new one
|
||||
-- and add css to the end of "header-includes"
|
||||
local current = meta['header-includes'] or pandoc.MetaList{meta['header-includes']}
|
||||
if FORMAT:match 'html' then
|
||||
current[#current+1] = pandoc.MetaBlocks(pandoc.RawBlock("html", css))
|
||||
end
|
||||
if FORMAT:match 'latex' then
|
||||
current[#current+1] = pandoc.MetaBlocks(pandoc.RawBlock("latex", latexpreamble))
|
||||
end
|
||||
meta['header-includes'] = current
|
||||
return(meta)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
{CodeBlock = codeBlockTrans},
|
||||
{Meta = metaAdd}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user