Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/command/render/latexmk/quarto-latexmk.ts
3589 views
1
import { debug } from "../../../deno_ral/log.ts";
2
import {
3
Command,
4
CompletionsCommand,
5
HelpCommand,
6
} from "cliffy/command/mod.ts";
7
import { parse } from "flags";
8
9
import {
10
appendLogOptions,
11
cleanupLogger,
12
initializeLogger,
13
logError,
14
logOptions,
15
} from "../../../core/log.ts";
16
import { LatexmkOptions } from "./types.ts";
17
import { generatePdf } from "./pdf.ts";
18
import {
19
kExeDescription,
20
kExeName,
21
kExeVersion,
22
} from "./quarto-latexmk-metadata.ts";
23
import { exitWithCleanup } from "../../../core/cleanup.ts";
24
import { mainRunner } from "../../../core/main.ts";
25
26
interface EngineOpts {
27
pdf: string[];
28
index: string[];
29
tlmgr: string[];
30
}
31
32
function parseOpts(args: string[]): [string[], EngineOpts] {
33
const pdfOpts = parseEngineFlags("pdf-engine-opt", args);
34
const indexOpts = parseEngineFlags("index-engine-opt", pdfOpts.resultArgs);
35
const tlmgrOpts = parseEngineFlags("tlmgr-opt", indexOpts.resultArgs);
36
return [
37
tlmgrOpts.resultArgs,
38
{
39
pdf: pdfOpts.values,
40
index: indexOpts.values,
41
tlmgr: tlmgrOpts.values,
42
},
43
];
44
}
45
46
function parseEngineFlags(optFlag: string, args: string[]) {
47
const values = [];
48
const resultArgs = [];
49
50
for (const arg of args) {
51
if (arg.startsWith(`--${optFlag}=`)) {
52
const value = arg.split("=")[1];
53
values.push(value);
54
} else {
55
resultArgs.push(arg);
56
}
57
}
58
return { values, resultArgs };
59
}
60
61
export async function pdf(args: string[]) {
62
// Parse any of the option flags
63
const [parsedArgs, engineOpts] = parseOpts(args);
64
65
const pdfCommand = new Command()
66
.name(kExeName)
67
.arguments("<input:string>")
68
.version(kExeVersion + "\n")
69
.description(kExeDescription)
70
.option(
71
"--pdf-engine <engine>",
72
"The PDF engine to use",
73
)
74
.option(
75
"--pdf-engine-opt=<optionsfile:string>",
76
"Options passed to the pdf engine. Can be used multiple times - values will be passed in the order they appear in the command. These must be specified using an '='.",
77
)
78
.option(
79
"--index-engine <engine>",
80
"The index engine to use",
81
)
82
.option(
83
"--index-engine-opt=<optionsfile:string>",
84
"Options passed to the index engine. Can be used multiple times - values will be passed in the order they appear in the command. These must be specified using an '='.",
85
)
86
.option(
87
"--bib-engine <engine>",
88
"The bibliography engine to use",
89
)
90
.option(
91
"--no-auto-install",
92
"Disable automatic package installation",
93
)
94
.option(
95
"--tlmgr-opt=<optionsfile:string>",
96
"Options passed to the tlmgr engine. Can be used multiple times - values will be passed in the order they appear in the command. These must be specified using an '='.",
97
)
98
.option(
99
"--no-auto-mk",
100
"Disable the pdf generation loop",
101
)
102
.option(
103
"--min <min:number>",
104
"The minimum number of iterations",
105
)
106
.option(
107
"--max <max:number>",
108
"The maximum number of iterations",
109
)
110
.option("--output-dir <directory>", "The output directory")
111
.option("--no-clean", "Don't clean intermediaries")
112
.throwErrors()
113
.action(async (options: unknown, input: string) => {
114
const latexmkOptions = mkOptions(
115
input,
116
options as Record<string, unknown>,
117
engineOpts,
118
);
119
await generatePdf(latexmkOptions);
120
});
121
122
await appendLogOptions(pdfCommand)
123
.command("help", new HelpCommand().global())
124
.command("completions", new CompletionsCommand()).hidden()
125
.parse(parsedArgs);
126
}
127
128
if (import.meta.main) {
129
await mainRunner(async () => {
130
await pdf(Deno.args);
131
});
132
}
133
134
function mkOptions(
135
input: string,
136
options: Record<string, unknown>,
137
engineOpts: EngineOpts,
138
): LatexmkOptions {
139
const engine = {
140
pdfEngine: options.pdfEngine as string || "pdflatex",
141
pdfEngineOpts: engineOpts.pdf,
142
bibEngine: bibEngine(options.bibEngine as string) || "biblatex",
143
indexEngine: options.indexEngine as string || "makeindex",
144
indexEngineOpts: engineOpts.index,
145
tlmgrOpts: engineOpts.tlmgr,
146
};
147
148
const latexMkOptions = {
149
input,
150
engine,
151
autoInstall: options.autoInstall as boolean,
152
autoMk: options.autoMk as boolean,
153
minRuns: options.min as number,
154
maxRuns: options.max as number,
155
outputDir: options.outputDir as string,
156
clean: options.clean as boolean,
157
};
158
159
// Debug message that show engine configuration (set --log-level debug to view)
160
debug(() => {
161
return JSON.stringify(latexMkOptions, undefined, 2);
162
});
163
164
return latexMkOptions;
165
}
166
167
function bibEngine(bibEngine?: string): "biblatex" | "natbib" {
168
if (bibEngine?.toLowerCase() === "natbib") {
169
return "natbib";
170
} else {
171
return "biblatex";
172
}
173
}
174
175