Assembled from klammertext-dev ed13dfaa5b7a. kpy/klammertext.cpp is a CPython extension module giving a Python script an instance of the Machine class -- ktext in-process, set up through the same functions the command uses. Errors map one-to-one to Python exceptions under the C++ names; an @eval's Python exception is chained as __cause__. Built by make -C mac, found through PYTHONPATH (env/runtime.env sets it), tested by tst/kpy_test.sh. Three engine changes came with it: Error::message(), set_command_state(), and the @eval error report carrying its traceback. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uv7KWxafinDPraswEf4GsC
88 lines
3.4 KiB
C++
88 lines
3.4 KiB
C++
#include <iostream>
|
|
#include "error.h"
|
|
#include "command.h"
|
|
#include "log.h"
|
|
#include "argv.h"
|
|
#include "file.h"
|
|
#include "util.h"
|
|
#include "machine.h"
|
|
#include "show.h"
|
|
#include "target_registry.h"
|
|
#include "klammerset_registry.h"
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
try {
|
|
set_verbose_level(argc, argv);
|
|
Argv args {};
|
|
args.req("filenames", "Input files in Klammertext format. ", "'list'");
|
|
args.opt("s", "Text processed before input files.", "input-string", "", "'text'");
|
|
args.opt("t","Output target; default is general (unspecified)", "target",
|
|
Target_registry::general_name, "'word'");
|
|
args.opt("o", "Output basename; meaning and default defined by target.", "basename",
|
|
"", "'word'");
|
|
args.flag("d", "Display the output to the screen, rather than writing a file.");
|
|
args.opt("klammersets", "Klammersets to load, as a list of symbols resolved on the "
|
|
"klammerset search path. Several combine: they are loaded in the order given "
|
|
"and share one namespace. The default is the Standard Klammer Set; "
|
|
"\"none\" loads none.",
|
|
"symbols", "", "'list'");
|
|
args.opt("v", "'verbosity'", "degree", "0", "'verbosity'");
|
|
|
|
if (show_usage(argc, argv)) {
|
|
// A bare command is a REQUEST for information, not a failure:
|
|
// usage goes to stdout (it is the result being asked for) and the
|
|
// exit status is 0, so "ktext && echo ok" reports what happened.
|
|
args.usage(file_basename(argv[0]));
|
|
exit(0);
|
|
}
|
|
args.parse(argc, argv);
|
|
if (verbose_level > 0) {
|
|
args.describe();
|
|
}
|
|
std::string input_text = args.as_string("s");
|
|
// argv boundaries are authoritative (a shell-quoted "my file.kt" is
|
|
// one element); group_filename_tokens adds the standalone-"/" list
|
|
// form, the existence rescue for unquoted spaces, and ~ expansion.
|
|
std::vector<std::string> input_filenames =
|
|
group_filename_tokens(args.as_vector("filenames"));
|
|
|
|
if (input_text.empty() && input_filenames.empty()) {
|
|
throw Argument_error(
|
|
"You must specify input filenames and/or text", Locator::none());
|
|
}
|
|
|
|
auto [target, output_dir, output_basename, output_filename,
|
|
write_files, display_only] =
|
|
parse_args(input_filenames, args.as_string("t"),
|
|
expand_tilde(args.as_string("o")), args.as_bool("d"));
|
|
|
|
Machine M;
|
|
set_command_state(M, "ktext", target, input_filenames, output_dir,
|
|
output_basename, display_only);
|
|
|
|
load_klammersets(M, word_split(args.as_string("klammersets")));
|
|
|
|
if (!input_text.empty()) {
|
|
M.read(input_text + "\n");
|
|
}
|
|
for (auto p : input_filenames) {
|
|
M.read(fs::path(p));
|
|
}
|
|
|
|
std::string result = trim(M.apply(target));
|
|
if (display_only && !result.empty()) {
|
|
std::cout << result << "\n";
|
|
} else if (!result.empty()) {
|
|
string_to_file(output_filename, result + "\n");
|
|
(void)K::log(1, "Wrote file: " + output_filename);
|
|
}
|
|
}
|
|
catch (Error& err) {
|
|
err.print_message();
|
|
std::cerr << "\n";
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|