CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/project/formatters/latex-format.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { writeFile, unlink } from "fs";
7
import { file } from "tmp";
8
import { callback } from "awaiting";
9
import { spawn } from "child_process";
10
import { replace_all } from "@cocalc/util/misc";
11
12
interface ParserOptions {
13
parser: string;
14
tabWidth?: number;
15
useTabs?: boolean;
16
}
17
18
function close(proc, cb): void {
19
proc.on("close", (code) => cb(undefined, code));
20
}
21
22
export async function latex_format(
23
input: string,
24
options: ParserOptions
25
): Promise<string> {
26
// create input temp file
27
const input_path: string = await callback(file, { postfix: ".tex" });
28
try {
29
await callback(writeFile, input_path, input);
30
// spawn the latexindent script.
31
const latexindent = spawn("latexindent", [input_path]);
32
let output: string = "";
33
// read data as it is produced.
34
latexindent.stdout.on("data", (data) => (output += data.toString()));
35
// wait for subprocess to close.
36
const code = await callback(close, latexindent);
37
if (code) {
38
throw Error(`latexindent exited with code ${code}`);
39
}
40
// now process the result according to the options.
41
if (!options.useTabs) {
42
// replace tabs by spaces
43
let tab_width = 2;
44
if (options.tabWidth !== undefined) {
45
tab_width = options.tabWidth;
46
}
47
let SPACES = "";
48
for (let i = 0; i < tab_width; i++) {
49
SPACES += " ";
50
}
51
output = replace_all(output, "\t", SPACES);
52
}
53
// latexindent also annoyingly introduces a lot of whitespace lines.
54
const lines: string[] = output.split("\n"),
55
lines2: string[] = [];
56
for (let i = 0; i < lines.length; i++) {
57
if (/\S/.test(lines[i])) {
58
lines2.push(lines[i]);
59
} else {
60
lines2.push("");
61
}
62
output = lines2.join("\n");
63
}
64
return output;
65
} finally {
66
unlink(input_path, () => {});
67
}
68
}
69
70