Repository navigation
Expand file tree
/
Copy pathbuild.mcpp
More file actions
73 lines (67 loc) · 3.23 KB
/
Copy pathbuild.mcpp
File metadata and controls
73 lines (67 loc) · 3.23 KB
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
// mcpp-ide's build program: the backend's view of spec/, generated where the build writes.
//
// spec/ is the one source of every editor-facing declaration (settings, presets, runtime strings,
// mcpp's manifest keys and build-program directives, the command table and the editors' strings).
// The backend reads it as JSON at startup, so
// this program only carries the files into a module, `mcppide.generated.spec`, as string literals:
// nothing is generated into the repository and nothing parses JSON here. The editors' declarations
// (package.json's contributes, plugin.xml's actions, the message bundles) are written by
// `mcpp-ide-dev gen`, a program of this package, when an adapter is built.
import std;
import mcpp;
namespace {
std::string env_or_empty(const char* name) {
const char* v = std::getenv(name);
return v ? std::string(v) : std::string{};
}
std::string slurp(const std::filesystem::path& p) {
std::ifstream in(p, std::ios::binary);
return std::string(std::istreambuf_iterator<char>(in), {});
}
// A literal of any length: pieces of at most 8000 bytes, each a raw string, which the compiler
// joins (one compiler bounds a single literal at 16 KiB). A piece never splits a UTF-8 sequence.
std::string literal(std::string_view text) {
std::string out;
std::size_t at = 0;
if (text.empty()) return "R\"mcppide()mcppide\"";
while (at < text.size()) {
std::size_t n = std::min<std::size_t>(8000, text.size() - at);
while (at + n < text.size() && (static_cast<unsigned char>(text[at + n]) & 0xC0) == 0x80) --n;
out += "R\"mcppide(";
out += text.substr(at, n);
out += ")mcppide\"\n ";
at += n;
}
return out;
}
} // namespace
int main() {
const std::filesystem::path root = env_or_empty("MCPP_MANIFEST_DIR");
const std::filesystem::path out = env_or_empty("MCPP_OUT_DIR");
const std::filesystem::path spec = root / "spec";
const std::array<std::pair<const char*, const char*>, 9> files{{
{"kSettingsJson", "settings.json"},
{"kPresetsJson", "presets.json"},
{"kCommandsJson", "commands.json"},
{"kRuntimeZhCnJson", "i18n/runtime.zh-cn.json"},
{"kManifestEnJson", "i18n/manifest.en.json"},
{"kManifestZhCnJson", "i18n/manifest.zh-cn.json"},
{"kTomlSchemaJson", "toml-schema.json"},
{"kBuildScriptApiJson", "buildscript-api.json"},
{"kTestFrameworksJson", "test-frameworks.json"},
}};
std::string module =
"// Generated by mcpp-ide's build.mcpp from spec/ (not part of the repository).\n"
"export module mcppide.generated.spec;\n\nimport std;\n\nexport namespace mcppide::generated {\n\n";
for (const auto& [name, file] : files) {
const auto path = spec / file;
mcpp::rerun_if_changed(path.generic_string().c_str());
module += std::format("// spec/{}\ninline constexpr std::string_view {} =\n {};\n\n", file, name, literal(slurp(path)));
}
module += "} // namespace mcppide::generated\n";
std::filesystem::create_directories(out);
const auto target = out / "spec.cppm";
if (slurp(target) != module) std::ofstream(target, std::ios::binary) << module;
mcpp::generated(target.generic_string().c_str());
return 0;
}