html filter finished

This commit is contained in:
Meik Hellmund 2022-09-26 08:05:37 +02:00
parent 69c2e0545f
commit 9242d38ecf
2 changed files with 249 additions and 55 deletions

View File

@ -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

View File

@ -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}
}