Skip to content

Commit 3adc7b3

Browse files
committed
Migrate pdfCommand from cliffy to clipanion
1 parent 3839170 commit 3adc7b3

File tree

1 file changed

+84
-101
lines changed

1 file changed

+84
-101
lines changed

src/command/render/latexmk/quarto-latexmk.ts

Lines changed: 84 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1+
/*
2+
* quarto-latexmk.ts
3+
*
4+
* Copyright (C) 2021-2024 Posit Software, PBC
5+
*/
16
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";
7+
import { Command, Option } from "npm:clipanion";
8+
import { isNumber } from "npm:typanion";
89

910
import {
10-
appendLogOptions,
11-
cleanupLogger,
12-
initializeLogger,
13-
logError,
14-
logOptions,
11+
addLoggingOptions,
1512
} from "../../../core/log.ts";
1613
import { LatexmkOptions } from "./types.ts";
1714
import { generatePdf } from "./pdf.ts";
@@ -20,7 +17,6 @@ import {
2017
kExeName,
2118
kExeVersion,
2219
} from "./quarto-latexmk-metadata.ts";
23-
import { exitWithCleanup } from "../../../core/cleanup.ts";
2420
import { mainRunner } from "../../../core/main.ts";
2521

2622
interface EngineOpts {
@@ -29,105 +25,92 @@ interface EngineOpts {
2925
tlmgr: string[];
3026
}
3127

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-
}
28+
export abstract class PDFCommand extends Command {
29+
input = Option.String();
30+
31+
['bib-engine'] = Option.String('--bib-engine', {description: "The bibliography engine to use"});
32+
33+
['index-engine'] = Option.String('--index-engine', {description: "The index engine to use"});
34+
['index-engine-opt'] = Option.Array('--index-engine', {
35+
description: "Options passed to the index engine." +
36+
"Can be used multiple times - values will be passed in the order they appear in the command." +
37+
"These must be specified using an '='."
38+
});
39+
40+
max = Option.String("--max", {
41+
description: "The maximum number of iterations",
42+
validator: isNumber(),
43+
});
44+
45+
min = Option.String("--min", {
46+
description: "The minimum number of iterations",
47+
validator: isNumber(),
48+
});
49+
50+
['no-auto-install'] = Option.Boolean('--no-auto-install', {description: "Disable automatic package installation"});
51+
['no-auto-mk'] = Option.Boolean('--no-auto-mk', {description: "Disable the pdf generation loop"});
52+
['no-clean'] = Option.Boolean('--no-clean', {description: "Don't clean intermediaries"});
53+
54+
outputDir = Option.String("--output-dir", { description: "The output directory" });
4555

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-
}
56+
['pdf-engine'] = Option.String('--pdf-engine', {description: "The PDF engine to use"});
57+
['pdf-engine-opt'] = Option.Array('--pdf-engine-opt', {
58+
description: "Options passed to the pdf engine." +
59+
"Can be used multiple times - values will be passed in the order they appear in the command." +
60+
"These must be specified using an '='."
61+
});
62+
63+
['tlmgr-opt'] = Option.Array('--tlmgr-opt', {
64+
description: "Options passed to the tlmgr engine." +
65+
"Can be used multiple times - values will be passed in the order they appear in the command." +
66+
"These must be specified using an '='."
67+
});
68+
69+
async execute() {
70+
const engineOpts: EngineOpts = {
71+
index: this['index-engine-opt'],
72+
pdf: this['pdf-engine-opt'],
73+
tlmgr: this['tlmgr-opt'],
74+
};
75+
const latexmkOptions = mkOptions(
76+
this.input,
77+
this,
78+
engineOpts,
79+
);
80+
await generatePdf(latexmkOptions);
5781
}
58-
return { values, resultArgs };
5982
}
6083

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);
84+
const commands = [
85+
PDFCommand,
86+
];
87+
88+
class PDFCli extends Cli {
89+
constructor() {
90+
super({
91+
binaryLabel: kExeDescription,
92+
binaryName: kExeName,
93+
binaryVersion: kExeVersion,
12094
});
12195

122-
await appendLogOptions(pdfCommand)
123-
.command("help", new HelpCommand().global())
124-
.command("completions", new CompletionsCommand()).hidden()
125-
.parse(parsedArgs);
96+
[
97+
...commands,
98+
Builtins.HelpCommand
99+
100+
// TODO: shell completion is not yet supported by clipanion
101+
// see https://github.com/arcanis/clipanion/pull/89
102+
// Builtins.CompletionsCommand
103+
].forEach((command) => {
104+
addLoggingOptions(command);
105+
this.register(command);
106+
});
107+
}
126108
}
127109

128110
if (import.meta.main) {
129111
await mainRunner(async () => {
130-
await pdf(Deno.args);
112+
const pdf = new PDFCli();
113+
await pdf.runExit(Deno.args);
131114
});
132115
}
133116

0 commit comments

Comments
 (0)