Initial commit: Klammertext source distribution
Curated source subset assembled by klammertext-dev's doc/make_dist.sh: the Klammermachine (mac), the Standard Klammer Set (sks), the commands (com), editor plugins and install guides (doc), a test subset (tst), and lib/bin placeholders. Builds with 'make -C com'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
4
com/.gitignore
vendored
Normal file
4
com/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
ktext
|
||||
kdesc
|
||||
kdiag
|
||||
*.d
|
||||
101
com/Makefile
Normal file
101
com/Makefile
Normal file
@@ -0,0 +1,101 @@
|
||||
# Klammertext com/ Makefile
|
||||
# Improved version with automatic header dependency tracking
|
||||
|
||||
K := $(KLAMMERTEXT_HOME)
|
||||
KS := $(K)/sks
|
||||
KM := $(K)/mac
|
||||
|
||||
include $(KM)/env/makefile.env
|
||||
|
||||
# Commands to build
|
||||
COMMANDS := kdiag kdesc ktext
|
||||
|
||||
# Build output directory: commands are linked directly into ../bin, so there is
|
||||
# exactly one copy of each (no redundant executables in com/) and make still
|
||||
# tracks them by path for incremental builds.
|
||||
BINDIR := ../bin
|
||||
BINCOMMANDS := $(addprefix $(BINDIR)/,$(COMMANDS))
|
||||
|
||||
# System install location (out-of-tree). Override on the command line, e.g.
|
||||
# make install PREFIX=/opt DESTDIR=/tmp/stage
|
||||
PREFIX ?= /usr/local
|
||||
DESTDIR ?=
|
||||
|
||||
# Shared library location
|
||||
LIBDIR := ../lib
|
||||
LIBRARY := $(LIBDIR)/libklammertext.so
|
||||
|
||||
# Linker flags for commands
|
||||
COM_LDFLAGS := $(EXPORT_DYNAMIC) -Wl,-rpath,'$(ORIGIN)/../lib' -L$(LIBDIR)
|
||||
|
||||
# Dependency files for command sources
|
||||
DEPFILES := $(addsuffix .d,$(COMMANDS))
|
||||
|
||||
# Compiler flags for dependency generation ($(@F) keeps the .d files in com/,
|
||||
# not in the ../bin output directory).
|
||||
DEPFLAGS = -MMD -MP -MF $(@F).d
|
||||
|
||||
.PHONY: all clean redo clang mac sks install
|
||||
|
||||
# Default target: build dependencies first, then commands
|
||||
all : | mac sks
|
||||
$(MAKE) commands
|
||||
|
||||
# Separate target to build commands (called after dependencies are ready)
|
||||
.PHONY: commands
|
||||
commands : $(BINCOMMANDS)
|
||||
|
||||
# Ensure the output directory exists before linking into it.
|
||||
$(BINDIR) :
|
||||
mkdir -p $@
|
||||
|
||||
# Build mac/ objects
|
||||
mac :
|
||||
$(MAKE) -C $(KM) -j
|
||||
|
||||
# Build sks/ components (depends on mac)
|
||||
sks : | mac
|
||||
$(MAKE) -C $(KS)/kutil -j
|
||||
$(MAKE) -C $(KS)/target -j
|
||||
$(MAKE) -C $(KS)/document
|
||||
|
||||
# Explicit rules for each command - link against shared library, output to bin/
|
||||
$(BINDIR)/kdiag : kdiag.cpp $(LIBRARY) | $(BINDIR)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEPFLAGS) $(COM_LDFLAGS) $(LDFLAGS) $< -o $@ -lklammertext $(LDLIBS)
|
||||
|
||||
$(BINDIR)/kdesc : kdesc.cpp $(LIBRARY) | $(BINDIR)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEPFLAGS) $(COM_LDFLAGS) $(LDFLAGS) $< -o $@ -lklammertext $(LDLIBS)
|
||||
|
||||
$(BINDIR)/ktext : ktext.cpp $(LIBRARY) | $(BINDIR)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEPFLAGS) $(COM_LDFLAGS) $(LDFLAGS) $< -o $@ -lklammertext $(LDLIBS)
|
||||
|
||||
# Out-of-tree system install (copies; the build tree stays intact). The
|
||||
# installed commands still need KLAMMERTEXT_HOME pointing at a Klammertext tree
|
||||
# for sks/ and the Python modules; their rpath finds libklammertext.so in
|
||||
# $(PREFIX)/lib.
|
||||
install : all
|
||||
install -d $(DESTDIR)$(PREFIX)/bin $(DESTDIR)$(PREFIX)/lib
|
||||
install -m755 $(BINCOMMANDS) $(DESTDIR)$(PREFIX)/bin
|
||||
install -m755 $(LIBRARY) $(DESTDIR)$(PREFIX)/lib
|
||||
|
||||
clean :
|
||||
rm -f $(BINCOMMANDS) $(DEPFILES) *~
|
||||
|
||||
redo :
|
||||
ifneq ($(filter clang,$(MAKECMDGOALS)),)
|
||||
@:
|
||||
else
|
||||
$(MAKE) -C $(KM) clean
|
||||
$(MAKE) -C $(KS)/kutil clean
|
||||
$(MAKE) -C $(KS)/target clean
|
||||
$(MAKE) -C $(KS)/document clean
|
||||
$(MAKE) clean
|
||||
$(MAKE) all
|
||||
endif
|
||||
|
||||
# "make clang" = incremental build; "make clang redo" = full clean rebuild
|
||||
clang :
|
||||
$(MAKE) $(or $(filter-out clang,$(MAKECMDGOALS)),all) COMPILER=clang
|
||||
|
||||
# Include generated dependency files (if they exist)
|
||||
-include $(DEPFILES)
|
||||
83
com/kdesc.cpp
Normal file
83
com/kdesc.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "argv.h"
|
||||
#include "command.h"
|
||||
#include "error.h"
|
||||
#include "file.h"
|
||||
#include "ktype.h"
|
||||
#include "log.h"
|
||||
#include "argtype_set.h"
|
||||
#include "character.h"
|
||||
#include "show.h"
|
||||
#include "util.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
set_verbose_level(argc, argv);
|
||||
|
||||
Argv args {};
|
||||
args.flag("c", "Special characters");
|
||||
args.flag("a", "Argument types");
|
||||
args.flag("k", "Katom types");
|
||||
args.flag("r", "Katom rewrite patterns");
|
||||
args.opt("input", "Input filename", "filename", "", "'text'");
|
||||
args.flag("targets", "Show targets defined by the input file");
|
||||
args.flag("klammers", "Show klammers defined by the input file");
|
||||
args.opt("v", "'verbosity'", "n", "0", "'verbosity'");
|
||||
|
||||
if (show_usage(argc, argv)) {
|
||||
args.usage(file_basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
auto p = [&](std::string name) { return args.get(name) == "true"; };
|
||||
|
||||
args.parse(argc, argv);
|
||||
verbose_level = stoi(args.get("v"));
|
||||
if (verbose_level > 0) {
|
||||
args.describe();
|
||||
}
|
||||
|
||||
if (p("c")) {
|
||||
show_special_characters();
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
if (p("a")) {
|
||||
Argtype_set argtypes;
|
||||
std::cout << boldblack << "\nStandard klammer argument types\n" << black;
|
||||
std::cout << argtypes.describe() << "\n";
|
||||
}
|
||||
|
||||
if (p("k")) {
|
||||
describe_katoms(verbose_level > 2);
|
||||
}
|
||||
|
||||
if (p("r")) {
|
||||
describe_rewrite_patterns();
|
||||
}
|
||||
|
||||
Machine M;
|
||||
|
||||
strings_t input_filenames = args.as_vector("input");
|
||||
std::cout << "input_filenames: " << input_filenames << "\n";
|
||||
if (input_filenames.empty()) {
|
||||
M.read(fs::path(M.m_state.value("KLAMMERTEXT_HOME") + "/sks/sks.k"));
|
||||
} else {
|
||||
for (auto fname : input_filenames) {
|
||||
std::cout << "Read " << fname << "\n";
|
||||
M.read(fs::path(absolute_pathname(fname)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p("targets")) {
|
||||
std::cout << boldblack << "Targets\n" << black << M.m_targets.describe(2, true);
|
||||
}
|
||||
|
||||
if (p("klammers")) {
|
||||
std::cout << boldblack << "Klammers\n" << black << M.m_klammers.describe(2);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Error& e) {
|
||||
e.print_message();
|
||||
}
|
||||
}
|
||||
118
com/kdiag.cpp
Normal file
118
com/kdiag.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
|
||||
#include "util.h"
|
||||
#include "argument_set.h"
|
||||
#include "argv.h"
|
||||
#include "argument.h"
|
||||
#include "command.h"
|
||||
#include "error.h"
|
||||
#include "file.h"
|
||||
#include "katom.h"
|
||||
#include "log.h"
|
||||
#include "show.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
set_verbose_level(argc, argv);
|
||||
|
||||
Argv args {};
|
||||
args.req("input", "Klammertext input text", "'text'");
|
||||
args.flag("type", "Show katom types in subscript");
|
||||
args.flag("index", "Show the list index of the katom");
|
||||
args.flag("text", "Show text katoms with selected attributes");
|
||||
args.flag("replaced","Show replaced katoms");
|
||||
args.flag("ignored", "Show ignored katoms");
|
||||
args.flag("all", "Show all katoms, including katoms replaced or ignored"); // in brackets with selected attributes");
|
||||
args.flag("spans", "Show the beginning and ending katoms of spans");
|
||||
args.flag("rewrite", "Show applied rewrite rules");
|
||||
args.flag("args", "Show how the text would be parsed as klammer arguments");
|
||||
args.opt("pos", "Number of positional arguments to parse for --args", "count", "-1", R"(([^\s]+))");
|
||||
args.flag("read", "Process read: @read <filename> @");
|
||||
args.flag("eval", "Process eval: @eval <expression> @");
|
||||
args.flag("cond", "Process cond: @cond <condition> | <if-true> | <if_false> @");
|
||||
args.flag("nonascii","Process encoded characters (not ASCII): ^... or ^...^");
|
||||
args.flag("literal", "Process literal: ^'...'^");
|
||||
args.flag("ignore", "Process ignored: #, ##, #[...]#");
|
||||
args.flag("ws", "Process whitespace: #-, #+, #/");
|
||||
args.flag("klammer", "Process klammer definitions: @@<name> ... @@");
|
||||
args.flag("process", "Process all");
|
||||
args.opt("v", "'verbosity'", "degree", "0", "'verbosity'");
|
||||
|
||||
if (show_usage(argc, argv)) {
|
||||
args.usage(file_basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
auto p = [&](std::string name) { return args.get(name) == "true"; };
|
||||
|
||||
args.parse(argc, argv);
|
||||
verbose_level = args.as_int("v");
|
||||
if (verbose_level > 0) {
|
||||
args.describe();
|
||||
}
|
||||
|
||||
if (p("rewrite")) {
|
||||
show_rewrite_rules = true;
|
||||
}
|
||||
|
||||
Machine machine;
|
||||
std::string input = args.as_string("input");
|
||||
std::string command = construct_command_pathname(argv[0]);
|
||||
katom_list katoms {};
|
||||
if (p("process")) {
|
||||
katoms = machine.process(input, command);
|
||||
} else {
|
||||
katoms = machine.process(
|
||||
//args.as_string("input"), construct_command_pathname(argv[0]),
|
||||
input, command,
|
||||
p("nonascii"), p("literal"), p("ignore"), p("ws"), p("klammer"),
|
||||
p("eval"), p("cond"), p("read"));
|
||||
}
|
||||
if (p("spans")) {
|
||||
describe_spans(katoms);
|
||||
} else {
|
||||
if (p("ignored")) std::cout << kignored;
|
||||
if (p("type")) std::cout << ktype;
|
||||
if (p("index")) std::cout << kindex;
|
||||
if (p("text")) std::cout << kall;
|
||||
if (p("all")) std::cout << kall << kreplaced << kignored;
|
||||
if (p("replaced")) std::cout << kreplaced;
|
||||
std::cout << katoms << "\n";
|
||||
}
|
||||
|
||||
if (p("args")) {
|
||||
int req_count = args.as_int("pos");
|
||||
bool limit_req = req_count != -1;
|
||||
if (req_count == -1) {
|
||||
req_count = std::numeric_limits<int>::max();
|
||||
}
|
||||
auto [required, optional, rest] =
|
||||
argument_split(katoms.begin(), katoms.end(), req_count);
|
||||
std::stringstream ss {};
|
||||
ss << "required";
|
||||
if (limit_req) {
|
||||
ss << " (" << req_count << ")";
|
||||
}
|
||||
ss << ":";
|
||||
std::string req_label = ss.str();
|
||||
auto label_width = req_label.size() + 2;
|
||||
std::cout << std::setfill(' ')
|
||||
<< std::right << std::setw(label_width) << req_label << " " << required << "\n"
|
||||
<< std::right << std::setw(label_width) << "optional:" << " " << optional << "\n";
|
||||
if (limit_req) {
|
||||
std::cout << std::right << std::setw(label_width) << "rest:" << " " << rest << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Error& e) {
|
||||
std::string advice = "";
|
||||
if (e.m_type == "target")
|
||||
advice = "To include the Standard Klammer Set, add flag \"--sks\".";
|
||||
e.print_message(advice);
|
||||
}
|
||||
std::cout << black;
|
||||
return 0;
|
||||
}
|
||||
|
||||
109
com/ktext.cpp
Normal file
109
com/ktext.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#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_set.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_set::general_name, "'word'");
|
||||
args.opt("o", "Output basename; meaning and default defined by target.", "basename",
|
||||
"", "'word'");
|
||||
args.opt("k", "File containing the klammerset definition; default is the Standard Klammer Set. With a value of \"none\", no klammerset is loaded.",
|
||||
"pathname", "", "'word'");
|
||||
args.flag("d", "Display the output to the screen, rather than writing files.");
|
||||
args.flag("m", "Show the Klammermachine state at the beginning of processing.");
|
||||
args.opt("v", "'verbosity'", "degree", "0", "'verbosity'");
|
||||
|
||||
if (show_usage(argc, argv)) {
|
||||
args.usage(file_basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
args.parse(argc, argv);
|
||||
if (verbose_level > 0) {
|
||||
args.describe();
|
||||
}
|
||||
std::string input_text = args.as_string("s");
|
||||
std::vector<std::string> input_filenames = args.as_vector("filenames");
|
||||
|
||||
if (input_text.empty() && input_filenames.empty()) {
|
||||
throw Argument_error(
|
||||
"You must specify input filenames and/or text", Locator());
|
||||
}
|
||||
|
||||
auto [target, output_dir, output_basename, output_filename,
|
||||
write_files, display_only] =
|
||||
parse_args(input_filenames, args.as_string("t"), args.as_string("o"),
|
||||
args.as_bool("d"));
|
||||
|
||||
if (*(output_filename.end() - 1) == '*'
|
||||
&& !display_only) {
|
||||
throw Argument_error(
|
||||
"You must specify an output target or "
|
||||
"display the results with the \"-d\" flag.",
|
||||
Locator());
|
||||
}
|
||||
|
||||
Machine M;
|
||||
M.m_state.open_frame("ktext");
|
||||
M.m_state.set("K_target", target);
|
||||
M.m_state.set("K_output_dir", output_dir);
|
||||
M.m_state.set("K_output_basename", output_basename);
|
||||
M.m_state.set("K_stdout_only", display_only ? "true" : "false");
|
||||
M.m_state.set("K_input_filenames", join(input_filenames, " "));
|
||||
M.m_state.set("K_verbose_level", std::to_string(verbose_level));
|
||||
|
||||
if (!input_filenames.empty()) {
|
||||
M.m_state.set(
|
||||
"K_input_dir",absolute_pathname(file_directory(input_filenames[0])));
|
||||
} else {
|
||||
M.m_state.set("K_input_dir", fs::current_path().string());
|
||||
}
|
||||
|
||||
std::string klammerset_filename = args.as_string("k");
|
||||
if (klammerset_filename != "none") {
|
||||
if (klammerset_filename.empty()) {
|
||||
klammerset_filename = M.m_state.value("KLAMMERTEXT_HOME") + "/sks/sks.k";
|
||||
}
|
||||
K::log(1, "Reading klammerset filename: " + klammerset_filename);
|
||||
M.read(fs::path(klammerset_filename));
|
||||
}
|
||||
|
||||
if (!input_text.empty()) {
|
||||
M.read(input_text + "\n");
|
||||
}
|
||||
for (auto p : input_filenames) {
|
||||
M.read(fs::path(p));
|
||||
}
|
||||
|
||||
if (args.as_bool("m")) {
|
||||
std::cout << M << "\n";
|
||||
}
|
||||
|
||||
std::string result = trim(M.apply(target));
|
||||
if (display_only && !result.empty()) {
|
||||
std::cout << result << "\n";
|
||||
} else if (!result.empty()) {
|
||||
msg() << "Output filename: " << output_filename << "\n";
|
||||
string_to_file(output_filename, result + "\n");
|
||||
(void)K::log(1, "Wrote file: " + output_filename);
|
||||
}
|
||||
}
|
||||
catch (Error& err) {
|
||||
err.print_message();
|
||||
std::cout << "\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user