", sanitize(content), "
" }, array { content };
+end
+function converters.CodeBlock(data, ctx)
+ local attribs = read_attributes(data[1], nil, ctx);
+ local content = data[2];
+
+ local text = array { " 0 then
+ text:push(" class=\"", classes:join " ", "\"");
+ end
+
+ text:push(">", sanitize(content), "
");
+
+ return text, array { content };
+end
+function converters.Image(data, ctx)
+ local alt, alt_plain = convert_all(data[2], ctx);
+ local url = data[3][1];
+ local title = data[3][2];
+ local attribs = read_attributes(data[1], title or alt_plain:join " ", ctx);
+
+ local classes = array {};
+ if attribs.small then classes:push("small") end
+ if attribs.big then classes:push("big") end
+
+ local text = array {}
+ :push(" 0 then
+ text:push(" class=\"", classes:join " ", "\"");
+ end
+
+ text:push("/>");
+
+ return text, title and { title } or alt_plain or url or "[picture]";
+end
+function converters.Figure(data, ctx)
+ local chapter_i = #(ctx.headers or {});
+ ctx.figures_indices = ctx.figures_indices or {};
+ ctx.figures_indices[chapter_i] = (ctx.figures_indices[chapter_i] or 0) + 1;
+ local figure_i = ctx.figures_indices[chapter_i];
+
+ local prefix = ("%s.%s."):format(chapter_i, figure_i);
+
+ local attribs = read_attributes(data[1], prefix, ctx);
+ local id = attribs.id;
+
+ indent(ctx);
+ indent(ctx);
+
+ local name, name_plain = convert_all(data[2][1], ctx);
+ local content, plain = convert_all(data[3], ctx);
+
+ undent(ctx);
+ undent(ctx);
+ local text = array { "");
+ plain
+ :push(" (", prefix, " ")
+ :append(name_plain)
+ :push(")");
+
+ ctx.citables = ctx.citables or {};
+ if id then ctx.citables[id] = prefix end
+
+ return text, plain;
+end
+function converters.Div(data, ctx)
+ local attribs = read_attributes(data[1], nil, ctx, true);
+
+ if attribs.figure then
+ local separator_i = data[2]:find_i(function (v) return v.t == "HorizontalRule" end);
+
+ local content_data, title_data;
+
+ if separator_i == nil then
+ content_data = array { data[2][1] };
+ title_data = data[2]:slice(2);
+ else
+ content_data = data[2]:slice(1, separator_i - 1);
+ title_data = data[2]:slice(separator_i + 1);
+ end
+
+ if #title_data == 1 and title_data[1].t == "Para" then
+ title_data = title_data[1].c
+ end
+
+ return converters.Figure(array {
+ data[1],
+ array { title_data },
+ content_data,
+ }, ctx);
+ else
+ error "Divs are not supported";
+ end
+end
+
+function converters.Cite(data, ctx)
+ local citation = data[1][1];
+ local id = last_id(citation.citationId, ctx);
+
+ local function target()
+ local res = (ctx.citables or {})[id];
+ if res == nil then
+ io.stderr:write("WARNING! Citation '" .. id .. "' doesn't exist!\n");
+ res = id;
+ end
+
+ return res;
+ end
+
+ return array { "", target, "" }, array { target }, true;
+end
+function converters.Header(data, ctx)
+ local level = data[1];
+ local attribs = read_attributes(data[2], nil, ctx);
+
+ ctx.headers = ctx.headers or array {};
+ ctx.header_stack = ctx.header_stack or array {};
+
+ local parent = ctx.header_stack[level - 1];
+ if level > 1 and parent == nil then error "Heading hierarchy inconsistent" end
+
+ local text, plain = convert_all(data[3], ctx);
+
+ local header = {
+ id = attribs.id,
+ level = level,
+ children = array {},
+ ignored = attribs.nonum or false,
+ };
+
+ local text_prefix, plain_prefix = "", "";
+
+ if level == 1 then
+ ctx.headers:push(header);
+ else
+ parent.children:push(header);
+ end
+
+ if not header.ignored then
+ local prefix = array { count_headers(ctx.headers) };
+ local text_format, plain_format;
+
+ for i = 1, level - 1 do
+ --- @diagnostic disable-next-line: undefined-field
+ prefix:push(count_headers(ctx.header_stack[i].children));
+ end
+
+ header.prefix = prefix:join ".";
+
+ if level == 1 then
+ text_format = ctx.chapter_format or "Chapter %s" + :append(text) + :append "
", + plain; +end +function converters.Emph(data, ctx) + local text, plain = convert_all(data, ctx); + return arrays.concat({ "" }, text, { "" }), plain, true; +end +function converters.Strong(data, ctx) + local text, plain = convert_all(data, ctx); + return arrays.concat({ "" }, text, { "" }), plain, true; +end +function converters.Str(data) + return array { sanitize(data) }, array { data }, true; +end +function converters.Plain(data, ctx) + return convert_all(data, ctx); +end + +function converters.RawBlock(data) + return array {}, array {}, true; +end +function converters.MetaInlines(data, ctx) + return convert_all(data, ctx); +end + +function converters.LineBreak() + return array { "