import { dirname, join, normalize, relative } from "../../deno_ral/path.ts";
import { ensureDirSync, safeRemoveSync } from "../../deno_ral/fs.ts";
import { writeFileToStdout } from "../../core/console.ts";
import { dirAndStem, expandPath } from "../../core/path.ts";
import { texSafeFilename } from "../../core/tex.ts";
import { kKeepTex, kOutputExt, kOutputFile } from "../../config/constants.ts";
import { Format } from "../../config/types.ts";
import { PandocOptions, RenderFlags, RenderOptions } from "./types.ts";
import { kStdOut, replacePandocOutputArg } from "./flags.ts";
import { OutputRecipe } from "./types.ts";
import { pdfEngine } from "../../config/pdf.ts";
import { execProcess } from "../../core/process.ts";
import { parseFormatString } from "../../core/pandoc/pandoc-formats.ts";
import { normalizeOutputPath } from "./output-shared.ts";
export interface PdfGenerator {
generate: (
input: string,
format: Format,
pandocOptions: PandocOptions,
) => Promise<string>;
computePath: (texStem: string, inputDir: string, format: Format) => string;
}
export function texToPdfOutputRecipe(
input: string,
finalOutput: string,
options: RenderOptions,
format: Format,
pdfIntermediateTo: string,
pdfGenerator: PdfGenerator,
pdfOutputDir?: string | null,
): OutputRecipe {
const [inputDir, inputStem] = dirAndStem(input);
let fixupInputName = "";
if (format.identifier["target-format"]) {
const formatDesc = parseFormatString(format.identifier["target-format"]);
fixupInputName = `${formatDesc.variants.join("")}${
formatDesc.modifiers.join("")
}`;
}
const texStem = texSafeFilename(`${inputStem}${fixupInputName}`);
const output = texStem + ".tex";
let args = options.pandocArgs || [];
const pandoc = { ...format.pandoc };
if (options.flags?.output) {
args = replacePandocOutputArg(args, output);
} else {
pandoc[kOutputFile] = output;
}
const complete = async (pandocOptions: PandocOptions) => {
const input = join(inputDir, output);
const pdfOutput = await pdfGenerator.generate(input, format, pandocOptions);
const compileTex = join(inputDir, output);
if (!format.render[kKeepTex]) {
safeRemoveSync(compileTex);
}
if (finalOutput) {
if (finalOutput === kStdOut) {
writeFileToStdout(pdfOutput);
safeRemoveSync(pdfOutput);
} else {
const outputPdf = expandPath(finalOutput);
if (normalize(pdfOutput) !== normalize(outputPdf)) {
ensureDirSync(dirname(outputPdf));
Deno.renameSync(pdfOutput, outputPdf);
}
}
if (pdfOutputDir) {
console.log({ pdfOutputDir });
try {
safeRemoveSync(pdfOutputDir, { recursive: false });
} catch {
}
}
return normalizeOutputPath(input, finalOutput);
} else {
return normalizeOutputPath(input, pdfOutput);
}
};
const pdfOutput = finalOutput
? finalOutput === kStdOut
? undefined
: normalizeOutputPath(input, finalOutput)
: normalizeOutputPath(
input,
pdfGenerator.computePath(texStem, dirname(input), format),
);
const to = format.pandoc.to === "pdf" ? pdfIntermediateTo : format.pandoc.to;
return {
output,
keepYaml: false,
args,
format: {
...format,
pandoc: {
...pandoc,
to,
},
},
complete,
finalOutput: pdfOutput ? relative(inputDir, pdfOutput) : undefined,
};
}
export function useContextPdfOutputRecipe(
format: Format,
flags?: RenderFlags,
) {
const kContextPdfEngine = "context";
if (format.pandoc.to === "pdf" && format.render[kOutputExt] === "pdf") {
const engine = pdfEngine(format.pandoc, format.render, flags);
return engine.pdfEngine === kContextPdfEngine;
} else {
return false;
}
}
export function contextPdfOutputRecipe(
input: string,
finalOutput: string,
options: RenderOptions,
format: Format,
): OutputRecipe {
const computePath = (stem: string, dir: string, _format: Format) => {
return join(dir, stem + ".pdf");
};
const generate = async (
input: string,
format: Format,
pandocOptions: PandocOptions,
): Promise<string> => {
const engine = pdfEngine(format.pandoc, format.render, pandocOptions.flags);
const cmd = "context";
const args = [input];
if (engine.pdfEngineOpts) {
args.push(...engine.pdfEngineOpts);
}
args.push(
"--purgeall",
"--batchmode",
);
const result = await execProcess({
cmd,
args,
});
if (result.success) {
const [dir, stem] = dirAndStem(input);
return computePath(stem, dir, format);
} else {
throw new Error();
}
};
return texToPdfOutputRecipe(
input,
finalOutput,
options,
format,
"context",
{
generate,
computePath,
},
);
}