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:
2026-07-18 18:48:23 +02:00
commit 2ba7ceee7a
272 changed files with 27634 additions and 0 deletions

1
sks/kutil/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.d

33
sks/kutil/Makefile Normal file
View File

@@ -0,0 +1,33 @@
# Klammertext sks/kutil/ Makefile
# Improved version with automatic header dependency tracking
K := $(KLAMMERTEXT_HOME)
KM := $(K)/mac
include $(KM)/env/makefile.env
# Source files
SOURCES := kutil.cpp klammer_base.cpp
OBJECTS := kutil.o klammer_base.o
DEPFILES := kutil.d klammer_base.d
# Additional include paths
LOCAL_CPPFLAGS := -I$(KM)
# Compiler flags for dependency generation
DEPFLAGS = -MMD -MP -MF $(@:.o=.d)
.PHONY: all clean
# Default target
all : $(OBJECTS)
# Pattern rule for object files
%.o : %.cpp
$(CXX) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(CXXFLAGS) $(DEPFLAGS) $< -o $@
clean :
rm -f $(OBJECTS) $(DEPFILES) *.so *~
# Include generated dependency files (if they exist)
-include $(DEPFILES)

260
sks/kutil/js/kutil.js Normal file
View File

@@ -0,0 +1,260 @@
const K = (function() {
function get(selector_or_node) {
let result = selector_or_node;
if (typeof selector_or_node === "string") {
result = document.querySelector(selector_or_node);
}
//console.log("NODE: " + selector_or_node + " "
// + typeof result + " " + result.nodeName);
return result;
}
function getv(selector) {
return document.querySelectorAll(selector);
}
function visible(node, new_state) {
const nd = K.get(node);
if (!nd) { console.warn("K.visible: element not found:", node); return false; }
let result = nd;
if (new_state === "hide") {
nd.setAttribute("original-display", nd.style.display);
nd.style.display = "none";
} else if (new_state === "show") {
nd.style.display = nd.getAttribute("original-display");
} else if (new_state) {
alert("Klammertext: Bad visible state for function K.visible: "
+ new_state);
} else {
result = nd.style.display !== "none";
}
return result;
}
async function fetch_html(url) {
//console.log("fetch_html: " + url);
return await (await fetch(url)).text();
}
async function load(node, url) {
const nd = get(node);
nd.innerHTML = await fetch_html(url);
}
function width(node, new_width) {
let nd = K.get(node);
if (nd === null || typeof nd === 'undefined') {
console.warn("K.width: element not found:", node);
return 0;
}
let result;
if (new_width !== undefined) {
if (!nd.style) {
nd.style = {};
}
new_width = Math.max(0, new_width);
nd.style.width = new_width + "px";
result = new_width;
} else {
result = nd.offsetWidth;
}
return result;
}
function height(node, new_height) {
let nd = K.get(node);
if (nd === null) {
console.warn("K.height: element not found:", node);
return 0;
}
//console.log("height: " + node + " " + nd);
let result = nd;
if (new_height !== undefined) {
new_height = Math.max(0, new_height);
nd.style.height = new_height + "px";
result = new_height;
} else {
result = nd.offsetHeight;
}
return result;
}
function top(node) {
return K.get(node).getBoundingClientRect().top;
}
function bottom(node) {
return K.get(node).getBoundingClientRect().bottom;
}
function left(node) {
return K.get(node).getBoundingClientRect().left;
}
function right(node) {
return K.get(node).getBoundingClientRect().right;
}
function attr(node, attr_name, new_value) {
const nd = K.get(node);
if (!nd) { console.warn("K.attr: element not found:", node); return undefined; }
let result = new_value;
if (new_value) {
nd.setAttribute(attr_name, new_value);
} else {
result = nd.getAttribute(attr_name);
}
return result;
}
function map(selector, func) {
return [...(K.getv(selector))].map(func);
}
function has_class(node_or_vector, cls) {
if (!node_or_vector) { console.warn("K.has_class: null element"); return node_or_vector; }
let result;
if (node_or_vector.length) {
[...node_or_vector].map(function(elt) {
result = elt.classList.contains(cls);
});
} else {
result = node_or_vector.classList.contains(cls);
}
return result;
}
function add_class(node_or_vector, cls) {
if (!node_or_vector) { console.warn("K.add_class: null element"); return node_or_vector; }
if (node_or_vector.length) {
[...node_or_vector].map(function(elt) {
elt.classList.add(cls);
});
} else {
node_or_vector.classList.add(cls);
}
return node_or_vector;
}
function remove_class(node_or_vector, cls) {
if (!node_or_vector) { console.warn("K.remove_class: null element"); return node_or_vector; }
if (node_or_vector.length) {
[...node_or_vector].map(function(elt) {
elt.classList.remove(cls);
});
} else {
node_or_vector.classList.remove(cls);
}
return node_or_vector;
}
function text(node, new_text) {
let result = new_text;
if (new_text) {
K.get(node).textContent = new_text;
} else {
result = K.get(node).textContent;
}
return result;
}
function style(node, name, new_value) {
const nd = K.get(node);
let result;
if (new_value) {
nd.style.setProperty(name, new_value);
result = new_value;
} else {
result = window.getComputedStyle(nd).getPropertyValue(name);
}
return result;
}
function hpad(selector) {
const node = K.get(selector);
let result = parseInt(K.style(node, "padding-left"))
+ parseInt(K.style(node, "padding-right"));
return result;
}
return {add_class, attr, bottom, get, getv, has_class,
height, hpad, left, load, map, remove_class, right,
style, text, top, visible, width};
}());
function current_basename()
{
//var result = window.location.hash.toString().split("#")[1];
let parts = window.location.href.split("#");
let result;
if (parts.length > 1) {
result = parts[1];
} else {
result = "";
}
return result;
}
function search_not_active() {
return document.activeElement.getAttribute("id") !== "search_input";
}
function define_keypress(letter, id) {
let uppercase = letter.charCodeAt();
let lowercase = uppercase + 32;
K.get("html").addEventListener(
"keypress",
function (event) {
if (search_not_active()) {
if (event.which === uppercase || event.which === lowercase) {
K.get(id).click();
}
}
});
}
function update_page_title(element) {
let element_text = element.firstChild;
let regex = /((?:Part )?[0-9.]*)(.*)/;
let parts = regex.exec(element_text);
let title;
if (element_text) {
if (!parts[1]) {
title = parts[2].trim();
} else {
title = parts[1] + " - " + parts[2];
}
K.text("title", title);
}
}
//window.scrollY + document.querySelector('#elementId')
// .getBoundingClientRect().top // Y
function count_highlighted_toc_items() {
const highlighted = K.map(
".section-title",
function (o) {
return K.has_class(o, "highlight");
});
const count = highlighted.filter(
function (x) {
return x === true;
}).length;
return count;
}
function remove_toc_highlighting() {
[...K.getv(".section-title")].forEach(function (toc_item) {
K.remove_class(toc_item, "highlight");
});
}
function displayed_text() {
return K.get("#text") || K.get("#search_page") || K.get("#help_page");
}

View File

@@ -0,0 +1,56 @@
#include <string>
#include <map>
#include "error.h"
#include "klammer_base.h"
#include "show.h"
std::string Klammer_base::get(std::string name)
{
//std::cout << "GET " << name << "\n";
std::string result = m_machine.m_state.value(name);
return result;
}
std::string Klammer_base::get(const char* name)
{
// msg() << "GETc " << name << "\n";
std::string sname { name };
std::string result = m_machine.m_state.value(name);
return result;
}
std::string Klammer_base::html()
{
return "[html target undefined]";
}
std::string Klammer_base::tex()
{
return "[tex target undefined]";
}
std::string Klammer_base::txt()
{
return "[txt target undefined]";
}
std::string Klammer_base::result()
{
std::string target = get("K_target");
if (target == "html")
return html();
else if (target == "tex" or target == "pdf")
return tex();
else if (target == "txt")
return txt();
else
throw Target_error("Unknown target: " + target);
}
void Klammer_base::show(std::string klammer_name)
{
std::cout << "Arguments of klammer \"" << klammer_name << "\"\n"
<< m_machine.m_state.describe() << "\n";
}

31
sks/kutil/klammer_base.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <iostream>
#include <string>
#include <map>
#include <filesystem>
#include "eval.h"
#include "machine.h"
#define VISIBLE __attribute__ ((visibility ("default")))
using argmap = std::map<std::string, std::string>;
class Klammer_base {
public:
Klammer_base(Machine& machine)
: m_machine(machine)
{};
virtual ~Klammer_base() {};
std::string get(std::string);
std::string get(const char* name);
virtual std::string html();
virtual std::string tex();
virtual std::string txt();
std::string result();
void show(std::string klammer_name);
Machine m_machine;
};

58
sks/kutil/klammer_base.py Normal file
View File

@@ -0,0 +1,58 @@
import pprint
import re
import kutil
def unescape_ktesc(s):
"""Resolve KTESC escape markers back to original characters.
Use this for argument values used programmatically (filenames, etc.)."""
def replace(match):
hex_chars = match.group(1)
result = ''
for i in range(0, len(hex_chars), 4):
result += chr(int(hex_chars[i:i+4], 16))
return result
return re.sub(r'KTESC([0-9a-f]+)KTESC', replace, s)
class Klammer_base:
def __init__(self, K):
#args = {k:escape(v) for k, v in K.__dict__.items()
args = {k:v for k, v in K.__dict__.items()
if not k.startswith('__')}
for key in args:
setattr(self, key, args[key])
#setattr(self, "_klammer_name", klammer_name)
#pprint.pprint(self.__dict__)
def html(self):
#return '[{}: HTML]'.format(self.__class__.__name__)
return None
def tex(self):
#return '[{}: LaTeX]'.format(self.__class__.__name__)
return None
def txt(self):
#return '[{}: Plain text]'.format(self.__class__.__name__)
return None
def show(self, label=""):
if label:
print(label)
pprint.pprint(self.__dict__)
def __str__(self):
result = None
if self.K_target == 'html':
result = self.html()
elif self.K_target in {'tex', 'pdf'}:
result = kutil.escape(self.tex())
elif self.K_target == 'txt':
result = self.txt()
if result is None:
#print(self.__dict__)
raise Exception(
f'Target "{self.K_target}" is undefined for klammer "@{self.K_klammer}"')
return result

173
sks/kutil/kutil.cpp Normal file
View File

@@ -0,0 +1,173 @@
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <fstream>
#include "error.h"
#include "util.h"
#include "katom.h"
#include "kutil.h"
#include "show.h"
#include <filesystem>
std::string read_file(std::string filename)
{
std::ifstream stream {};
std::ostringstream buffer {};
stream.open(filename);
if (stream.is_open()) {
stream >> buffer.rdbuf();
} else {
std::cout << "File not opened\n";
}
return buffer.str();
}
std::string klammertext_dir()
{
std::string khome { "KLAMMERTEXT_HOME" };
char* kdir = getenv(khome.c_str());
if (kdir == nullptr) {
std::stringstream ss {};
ss << "The environment variable " << q_(khome) << " is not defined";
throw Environment_error(ss.str());
}
return kdir;
}
bool in_subset(std::string base, std::vector<std::string> subset)
{
return subset.empty() ||
(std::find(subset.begin(), subset.end(), base) != subset.end());
}
std::vector<std::string> sks_files_of_type(std::string extension, std::vector<std::string> subset)
{
bool dbg = false;
std::string kdir = klammertext_dir();
std::vector<std::string> result {};
if (dbg) msg() << "Extension: " << extension << "\n";
for (auto base : sks_basenames) {
std::string ext_dir { kdir + "/sks/" + base + "/" + extension };
if (file_exists(ext_dir)) {
std::string list_filename { ext_dir + "/list.txt" };
if (file_exists(list_filename)) {
if (dbg) msg() << " List: " << list_filename << "\n";
std::string list = string_from_file(list_filename);
for (auto s : regex_split(list, std::regex(R"(\n+)"), true)) { // split_lines(list)) {
if (s[0] == '#')
continue;
std::string ext_filename = { ext_dir + "/" + s };
if (!file_exists(ext_filename)) {
std::string msg = "File " + ext_filename + " in " + list_filename + " does not exist";
throw Internal_error(msg);
}
if (in_subset(fs::path(s).stem(), subset)) {
if (dbg) msg() << " Add: " << ext_filename << "\n";
result.push_back(ext_filename);
}
}
} else {
for (auto f : get_files_in_directory(ext_dir)) {
if (f[f.size()-1] != '~') {
if (in_subset(fs::path(f).stem(), subset)) {
result.push_back(ext_dir + "/" + f);
if (dbg) msg() << " Add: " << f << "\n";
}
}
}
}
}
}
return result;
}
std::string find_kt_file(std::string filename)
{
std::string result {};
std::vector<std::string> prefix {"", "kt/"};
std::vector<std::string> suffix {"", ".kt"};
std::vector<std::string> all_possible {};
for (auto p : prefix) {
for (auto s : suffix) {
std::string possible { p + filename + s };
//std::cout << "Checking: " << possible << "\n";
if (file_exists(possible, false)) {
result = possible;
all_possible.push_back(possible);
break;
}
}
if (result.size() > 0) {
break;
}
}
if (result.size() == 0) {
std::cout << "Filename \"" << filename << "\" does not exist and\ndoes not match any of the default patterns:\n";
for (std::string f : all_possible) {
std::cout << " " << f << "\n";
}
exit(1);
}
//std::cout << " Found: " << result << "\n";
return result;
}
std::string caption_marker(std::string name, std::string caption, std::string delimiter)
{
std::string result {caption};
if (caption.size() > 0) {
result = delimiter + caption;
}
result = caption_delimiter + name + caption_delimiter + result + caption_delimiter;
return result;
}
/*
std::string process(Machine& M, std::string target, fs::path source_filename,
bool post_process, bool unescape_chars)
{
// Text text(source_filename, false, false);
Source source;
source.read(source_filename
text.parse();
M.preserve_parse(text);
M.extract_definitions(text);
M.apply(target, text);
std::string processed = M.to_string(target, text, post_process, unescape_chars);
//processed = modify_whitespace_string(processed);
//M.restore_parse(text);
return processed;
}
std::string process(Machine& M, std::string target, std::string source_text,
bool post_process, bool unescape_chars)
{
Text text(source_text, false, false);
text.parse();
M.preserve_parse(text);
M.extract_definitions(text);
M.apply(target, text);
std::string processed = M.to_string(target, text, post_process, unescape_chars);
//M.restore_parse(text);
return processed;
}
std::string process(Machine& M, std::string target,
std::string source_text, fs::path source_filename,
bool post_process, bool unescape_chars)
{
Text text({source_text}, {source_filename}, false, false);
text.parse();
M.preserve_parse(text);
M.extract_definitions(text);
M.apply(target, text);
std::string processed = M.to_string(target, text, post_process, unescape_chars);
//M.restore_parse(text);
return processed;
}
*/

35
sks/kutil/kutil.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include <string>
#include <vector>
#include "machine.h"
#include "file.h"
inline
std::vector<std::string> sks_basenames { // removed "book"
"kutil", "color", "document", "block", "font", "link", "section",
"list", "image", "table", "code", "target", "date" };
const std::string caption_delimiter = "__CAPTION__";
std::string read_file(std::string filename);
std::string klammertext_dir();
std::vector<std::string> old_sks_files_of_type(std::string extension);
std::vector<std::string> sks_files_of_type(std::string extension, std::vector<std::string> subset={});
std::string caption_marker(std::string name, std::string caption, std::string delimiter=" ");
std::string find_kt_file(std::string filename);
std::string process(Machine& M, std::string target, std::string source_text,
bool post_process=false, bool unescape_chars=false);
std::string process(Machine& M, std::string target, fs::path source_filename,
bool post_process=false, bool unescape_chars=false);
std::string process(Machine& M, std::string target,
std::string source_text, fs::path source_filename,
bool post_process, bool unescape_chars);

63
sks/kutil/kutil.k Normal file
View File

@@ -0,0 +1,63 @@
@@show s : @eval :cpp show show @ @@
@@caption_arguments :
:caption
:number.bool true
:caption_side.side bottom
:caption_font.font i
:caption_font_size.float .9
@@
@@reference spec | name :
__REF__*spec*__*name*__
@@
@@@argtype number | a number
:pattern 'float'^|'int'
:python_cast (lambda s: float(s))
@@@
@@@argtype length | a length specifier
#:pattern f^|none^|'float'w^|'float'h^|'int'px^|'float'em^|'int'pt
# The last pattern is a string, used where possible to determine its length
:pattern f^|none^|'float'w^|'float'h^|'int'px^|'float'em^|'int'pt^|"[^^"]+"^|'float'pw^|'float'ph
# :python_cast (lambda s : __import__("kutil").parse_length("tex", s))
@@@
@@@argtype lengths | a list of lengths
:pattern ('length'^|\s+)*
#:python_cast (lambda s : [__import__("kutil").parse_length("tex", e) for e in s.split()])
@@@
@@@argtype side | a side of a box
:pattern top^|right^|bottom^|left
@@@
@@@argtype hpos | horizontal position
:pattern left^|center^|right^|none
@@@
@@@argtype figure_id |
an identifier for a figure.
The identifier can be in one of six forms:
before
before <offset-to-figure>
after
after <offset-to-figure>
<image-basename>
<id>
The "before" value means the figure before this place in the text;
the number indicates the number of figures behind that place in the
text. This means that "before" is equivalent to "before 1". The
"after" value uses an offset in the same way but counting forewards.
For images, the <image-basename> argument is the basename argument to
the ^@image klammer and can be used as an identifier.
An <id> is the value of the ^:id argument for an image.
^:pattern before(?^:\s+\d+)?^|after(?^:\s+\d+)?^|[-\w]+
@@@

209
sks/kutil/kutil.py Normal file
View File

@@ -0,0 +1,209 @@
import os
import re
import inspect
import html_util
from html_util import E
def black_text():
return "\033[0;30m"
def blue_text(text):
return f"\033[0;34m{text}\033[0m"
def red_text(text):
return f"\033[31m{text}\033[0m"
def msg(text=""):
frame = inspect.currentframe().f_back
print(blue_text(f"[{os.path.basename(frame.f_code.co_filename)}:{frame.f_lineno}]"), text)
def escape(s):
result = s
#result = re.sub(r"\b", r"\b", result)
#result = re.sub(r"\t", r"\t", result)
#result = re.sub("\f", r"\\f", result)
#result = re.sub("\v", r"\\v", result)
#result = re.compile("\\(.)").sub(r"\\\1", result)
return result
def klammertext_dir():
var = 'KLAMMERTEXT_HOME'
kdir = os.environ.get(var)
if kdir is None:
raise Exception(
f"The environment variable {var} must be defined as the top-level Klammertext directory")
return kdir
def cache_directory(relative_pathname, basename):
directory = relative_pathname
if not os.path.isdir(directory):
os.makedirs(directory)
result = directory + "/_klammertext_cache/" + basename
return result;
def sks_dirs():
result = 'kutil book document block font link section list image table code color'.split()
k = klammertext_dir()
result = [[e, f"{k}/sks/{e}"] for e in result]
return result
def sks_files_of_type(extension):
result = []
for base, sks_dir in sks_dirs():
filename = f'{sks_dir}/{base}.{extension}'
if os.path.exists(filename):
result.append([base, filename])
return result
def make_dir_if_necessary(d, delete_contents=False):
if not os.path.exists(d):
os.makedirs(d)
if delete_contents:
os.system(f'rm -rf {d}/*')
def protect_klammertext_special_characters(text):
result = text
result = re.compile(r"\^").sub("", result)
result = re.compile(r"@").sub("", result)
result = re.compile(r":").sub("̅C̅", result)
result = re.compile(r"\|").sub("̅B̅", result)
return result
# When did this ever make sense? Before the new word patterns, probably.
def bar_delimiter():
return "\3"
def double_bar_delimiter():
return "\4"
def caption_delimiter():
return "__CAPTION__"
def caption_marker(name, caption, delimiter=" - "):
caption = re.sub("\n", " ", caption)
d = caption_delimiter()
if caption:
caption = f"{delimiter}{caption}"
return f"{d}{name}{d}{caption}{d}"
def rest_args(s, dimensions=1):
if s.endswith("||"):
s = s[:-2]
s = re.sub(r"\t", r"\\t", s)
double_bar_pat = re.compile(r"\|\|")
bar_pat = re.compile(r"\s*\|\s*")
parts = [e.strip() for e in double_bar_pat.split(s.strip())]
for p in parts:
elts = bar_pat.split(p.strip())
elts = ["~" if (e.strip() == "") else e.strip() for e in elts]
result = [bar_pat.split(e) for e in parts]
if dimensions == 1:
result = result[0]
return result
def parse_length(target, s, rel_fraction):
def choose(html_value, tex_value):
return html_value if target == "html" else tex_value
pat = re.compile(r'(?:([0-9.]+)([a-z]+))|(none|f)|(?:"([^"]+)")')
#pat = re.compile(r'(?:([0-9.]+)([a-z]+))|(none|f)|(?:{([^}]+)})')
#pat = re.compile(r'(?:([0-9.]+)([a-z]+))|(f)')
match = pat.match(s)
if match is None: # But already checked by the klammer
raise Exception(f'The argument "{s}" is not a length')
#print(match.groups())
num, units, fit, text = match.groups()
num = float(num) if num else ""
num *= rel_fraction
if fit:
result = "f" # choose("100vw", "\\textwidth")
elif text:
text = re.compile(r"\{\}\\textbackslash\{\}").sub(r"\\", text)
if text[0] == "-":
result = choose("", f"\\textwidth - \\widthof{{ {text[1:]}}}")
else:
result = choose("", f"\\widthof{{ {text}}}")
elif units == "w":
result = choose(f"{100 * num}vw", f"{num}\\textwidth")
elif units == "h":
result = choose(f"{100 * num}vh", f"{num}\\textheight")
elif units == "pw":
result = choose(f"{100 * num}vw", f"{num}\\paperwidth")
elif units == "ph":
result = choose(f"{100 * num}vh", f"{num}\\paperheight")
elif units == "px":
result = choose(f"{round(num)}", f"{num}px")
else:
result = f"{num}{units}"
result = re.sub("\t", "\\t", result)
return result, num, units
def old_parse_length(target, s):
pat = re.compile(r'(?:([0-9.]+)([a-z]+))|(none|f)|("([^"]+)")')
match = pat.match(s)
if match is None:
raise Exception(f'The argument "{s}" is not a length')
if match.group(3) in {"none", "f"}:
return "f"
if s[0] == '"':
if target in {"tex", "pdf"}:
return f"\\widthof{{{match.group(5)} }}"
else:
return ""
num, units = match.groups()[:2]
if float(num) == 0:
return None
result = f"{num}{units}"
if target in {"tex", "pdf"}:
if units == "w":
result = fr"{num}\textwidth"
elif units == "h":
result = fr"{numb}\textheight"
elif target in {"html"}:
scale_x = None
scale_y = None
if units == "w":
#result = fr"{int(float(num)*100)}vw"
result = fr"calc({int(float(num)*100)}vw - 2rem)"
#result = 0
scale_x = num
result = "none"
elif units == "h":
result = fr"{int(float(num)*100)}vw"
#result = 0
scale_y = num
result = "none"
result = [result, scale_x, scale_y]
else:
raise Exception(f"Uknown length: '{s}'")
return result
def parse_lengths(target, s):
# Fill strings with space character for the split:
#print("parse_lengths:", s)
def replace(match):
return re.sub(r"\s", "~", match.group(1))
result = re.compile(r'("[^"]+")').sub(replace, s)
#print(result, result.split())
result = [parse_length(target, e)[0] for e in result.split()]
return result
paragraph_separator_re = re.compile(r'\n *\n', re.S)
def format_for_paragraphs(s):
result = s
if len(paragraph_separator_re.findall(result)) > 0:
result = '\n\n{}\n\n'.format(result)
return result

43
sks/kutil/show.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include <string>
#include <sstream>
#include <map>
#include "util.h"
#include "eval.h"
#include "machine.h"
#include "klammer_base.h"
using namespace std;
extern "C" VISIBLE string show(std::map<std::string, std::string> args)
{
cout << "SHOW\n" << args << "\n";
return "SHOW";
string s = getarg(args, "s");
string target = getarg(args, "_target");
string kt = string_replace(s, "\\^\\^", "__CIRCUM__");
kt = string_replace(kt, "\\^", "");
kt = string_replace(kt, "__CIRCUM__", "HAT");
//kt = "@lit " + kt + " @";
cout << "Modified: " << kt << "\n";
Machine M {};
M.state.state.set("K_program_name", "show");
Text T(true);
T.read_string(kt);
T.parse();
M.extract_definitions(T);
M.apply(target, T);
string processed = M.to_string(target, T);
stringstream ss {};
//ss << s << sp_arrow << processed;
ss << "@t " << s << " @ | " << processed;
return ss.str();
}