import { marked } from 'marked';
import { highlight } from './prism';
import katex = require('katex');
import type { KatexOptions } from 'katex';
import render_bytefield = require('bytefield-svg');
import { renderSvg as render_nomnoml } from 'nomnoml';
import { pikchr } from 'pikchr';
import { parse as parse_yaml } from 'yaml';
import { icons } from './icons';
import { strip_svg } from './svg';
import { generate_mecard_qr_code, generate_qr_code } from './qrcode';
import { bind_data_async } from './async-steps';
import { render_vega_spec } from './vega';
import { parse_attributes } from './attrs';
import { MarkdownOptions } from './render';
export function create_renderer(opts: MarkdownOptions) {
const renderer = new marked.Renderer();
renderer.heading = heading(renderer, opts);
renderer.code = code(renderer, opts);
// ...
return renderer;
}
function heading(renderer: marked.Renderer, opts: MarkdownOptions) {
return function(orig_text: string, level: 1 | 2 | 3 | 4 | 5 | 6, raw: string, slugger) {
let { text, id, html_attrs } = parse_attributes(raw);
if (! id) {
id = slugger.slug(text);
html_attrs.push(`id="${id}"`);
}
return `
${escape(code, is_escaped)}`;
}
let caption = '';
const flags = new Set${escape(code, is_escaped)}`);
case 'bash:samp': {
// Find the first newline that is not preceeded by a "\"
const end_of_input = /(?${render_prism(code, 'bash')}`);
}
const input = code.slice(0, end_of_input.index);
const rendered_input = render_prism(input, 'bash');
const output = code.slice(end_of_input.index + 1);
const rendered_output = `${escape(output, is_escaped)}`;
return figure(`${rendered_input}\n${rendered_output}`);
};
case 'katex': {
const katex_opts: KatexOptions = {
displayMode: true, // true == "block"
output: 'html',
macros: opts.katex_macros,
};
return figure(
(katex as any).renderToString(code, katex_opts)
);
};
case 'nomnoml': {
const svg = render_nomnoml(code);
return figure(post_process_nomnoml_svg(svg));
};
case 'clojure:bytefield': {
const svg = render_bytefield(code);
return figure(post_process_bytefield_svg(svg));
};
case 'pikchr': {
const svg = pikchr(code);
return figure(post_process_pikchr_svg(svg));
};
case 'qrcode': {
const promise = generate_qr_code(code);
const async_binding = bind_data_async(promise);
return figure(async_binding);
};
case 'yaml:mecard': {
const parsed = parse_yaml(code);
const promise = generate_mecard_qr_code(parsed);
const async_binding = bind_data_async(promise);
return figure(async_binding);
};
case 'json:vega': {
const spec = JSON.parse(code);
const promise = render_vega_spec(spec);
const binding = bind_data_async(promise);
return figure(binding);
};
case 'yaml:vega': {
const spec = parse_yaml(code);
const promise = render_vega_spec(spec);
const binding = bind_data_async(promise);
return figure(binding);
};
default:
return figure(`${render_prism(code, args[0])}`);
}
function render_http_with_content(code: string, lang: string) {
// Find the first double newline
const end_of_header = /(?:\r\n|\r|\n)(?:\r\n|\r|\n)/.exec(code);
// If there is no such newline, the whole content is HTTP header
if (! end_of_header) {
return figure(`${render_prism(code, 'http')}`);
}
const header = code.slice(0, end_of_header.index);
const rendered_header = render_prism(header, 'http', true);
const content = code.slice(end_of_header.index + 1);
const rendered_content = render_prism(content, lang, true);
return figure(`${rendered_header}\n${rendered_content}`);
}
function render_prism(code: string, lang: string, include_class = false) {
const out = highlight(code, lang);
if (out != null && out !== code) {
is_escaped = true;
code = out;
}
const classname = include_class ? `class="language-${lang}"` : '';
return `${escape(code, is_escaped)}`;
}
};
}
const arg_pattern = /^(?:[a-zA-Z0-9_:-]+|"(?:[^"\n]|(?<=\\)")*")/;
function parse_code_args(text: string) {
const args: string[] = [ ];
text = text.trim();
while (text.length) {
const match = arg_pattern.exec(text);
if (! match) {
break;
}
if (match[0][0] === '"') {
args.push(match[0].slice(1, -1));
}
else {
args.push(match[0]);
}
text = text.slice(match[0].length).trimStart();
}
return args;
}
function escape(str: string, is_escaped: boolean) {
return is_escaped ? str : str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''');
}
const svg_text = /