-
Notifications
You must be signed in to change notification settings - Fork 772
/
LatexGenerator.cpp
90 lines (79 loc) · 3.3 KB
/
LatexGenerator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "LatexGenerator.h"
#include <iomanip>
#include <iterator>
#include <regex>
#include <sstream>
#include <glib.h>
#include "util/PathUtil.h"
#include "util/i18n.h"
#include "util/serdesstream.h"
LatexGenerator::LatexGenerator(const LatexSettings& settings): settings(settings) {}
auto LatexGenerator::templateSub(const std::string& input, const std::string& templ, const Color textColor)
-> std::string {
const static std::regex substRe("%%XPP_((TOOL_INPUT)|(TEXT_COLOR))%%");
std::string output;
output.reserve(templ.length());
int templatePos = 0;
for (std::sregex_iterator it(templ.begin(), templ.end(), substRe); it != std::sregex_iterator{}; it++) {
std::smatch match = *it;
std::string matchStr = match[1];
std::string repl;
// Performance can be optimized here by precomputing hashes
if (matchStr == "TOOL_INPUT") {
repl = input;
} else if (matchStr == "TEXT_COLOR") {
auto s = serdes_stream<std::ostringstream>();
auto tmp_color = textColor;
tmp_color.alpha = 0;
s << std::hex << std::setfill('0') << std::setw(6) << std::right << tmp_color;
repl = s.str();
}
output.append(templ, templatePos, match.position() - templatePos);
output.append(repl);
templatePos = match.position() + match.length();
}
output.append(templ, templatePos);
return output;
}
auto LatexGenerator::asyncRun(const fs::path& texDir, const std::string& texFileContents) -> Result {
std::string cmd = this->settings.genCmd;
GError* err = nullptr;
const auto&& fail = [&](GenError&& res) -> Result {
g_error_free(err);
return res;
};
auto texFilePath = (Util::getLongPath(texDir) / "tex.tex").string();
for (auto i = cmd.find(u8"{}"); i != std::string::npos; i = cmd.find(u8"{}", i + texFilePath.length())) {
cmd.replace(i, 2, texFilePath);
}
// Windows note: g_shell_parse_argv assumes POSIX paths, so Windows paths need to be escaped.
gchar** argv = nullptr;
if (!g_shell_parse_argv(cmd.c_str(), nullptr, &argv, &err)) {
return fail({FS(_F("Failed to parse LaTeX generator command: {1}") % err->message)});
}
gchar* prog = argv[0];
if (!prog || !(prog = g_find_program_in_path(prog))) {
GenError res{FS(_F("Failed to find LaTeX generator program in PATH: {1}") % argv[0])};
g_strfreev(argv);
g_error_free(err);
return res;
}
g_free(argv[0]);
argv[0] = prog;
if (!g_file_set_contents(texFilePath.c_str(), texFileContents.c_str(), texFileContents.length(), &err)) {
return fail({FS(_F("Could not save .tex file: {1}") % err->message)});
}
auto flags = static_cast<GSubprocessFlags>(G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE);
GSubprocessLauncher* launcher = g_subprocess_launcher_new(flags);
g_subprocess_launcher_set_cwd(launcher, texDir.u8string().c_str());
auto* proc = g_subprocess_launcher_spawnv(launcher, argv, &err);
std::string progName(prog);
g_strfreev(argv);
g_object_unref(launcher);
if (proc) {
return {proc};
} else {
return fail(
{FS(_F("Could not start {1}: {2} (exit code: {3})") % progName.c_str() % err->message % err->code)});
}
}