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>
178 lines
6.8 KiB
C++
178 lines
6.8 KiB
C++
#include "reference.h"
|
|
#include "target.h"
|
|
#include "util.h"
|
|
#include "show.h"
|
|
|
|
// Escape marker for backslash in pre-processed text
|
|
static const std::string BS = Target::escape_marker("\\");
|
|
|
|
std::ostream& operator<<(std::ostream& os, const numbered_element_spec& spec)
|
|
{
|
|
os << "[" << std::get<0>(spec) << "|"
|
|
<< std::get<1>(spec) << "|"
|
|
<< std::get<2>(spec) << "]";
|
|
return os;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const numbered_elements& line_states)
|
|
{
|
|
bool found = false;
|
|
for (long unsigned i = 0; i < line_states.size(); i++) {
|
|
if (std::get<1>(line_states[i]) != "") {
|
|
os << i << ": " << line_states[i] << "\n";
|
|
found = true;
|
|
}
|
|
}
|
|
if (!found) {
|
|
os << "[No matching lines]";
|
|
}
|
|
return os;
|
|
}
|
|
|
|
std::string add_latex_caption_numbers(std::string latex_text)
|
|
{
|
|
std::string caption_delimiter { "__CAPTION__" }; // But also in kutil.py
|
|
std::regex caption_delimiter_rgx(caption_delimiter);
|
|
// Accept either the escape-marker form (from the :files path, where
|
|
// M.apply("tex", false) leaves markers in place) or the resolved
|
|
// literal-backslash form (from the :text path, already processed by
|
|
// the outer Machine).
|
|
std::regex section_rgx("(?:" + BS + R"(|\\)sA\{.*)");
|
|
|
|
std::map<std::string, int> index_map {};
|
|
bool section_seen = false;
|
|
std::string result {};
|
|
std::smatch match {};
|
|
for (std::string line : regex_split(latex_text, std::regex(R"(\n)"), false)) {
|
|
if (regex_match(line, match, section_rgx)) {
|
|
index_map.clear();
|
|
section_seen = true;
|
|
}
|
|
if (line.find(caption_delimiter) != std::string::npos) {
|
|
std::vector<std::string> parts = regex_split(line, caption_delimiter_rgx);
|
|
std::string before = parts[0];
|
|
std::string caption_type = parts[1];
|
|
std::string caption = parts[2];
|
|
std::string after = parts.size() == 4 ? parts[3] : "";
|
|
if (index_map.count(caption_type) == 0)
|
|
index_map[parts[1]] = 1;
|
|
int n = index_map[caption_type];
|
|
std::stringstream modified {};
|
|
modified << before << " " << caption_type << " ";
|
|
// Suppress the section/chapter prefix before any section has
|
|
// appeared, matching insert_html_caption_numbers behavior
|
|
// ("Figure 1" not "Figure 0.1").
|
|
if (section_seen) {
|
|
modified << "{\\ifthenelse{\\isundefined{\\thechapter}}{\\thesection}{\\thechapter}}.";
|
|
}
|
|
modified << n << " " << caption << after;
|
|
line = modified.str();
|
|
index_map[caption_type]++;
|
|
}
|
|
result += line + "\n";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
numbered_elements latex_line_states(std::vector<std::string> lines)
|
|
{
|
|
// \hypertarget{Reference-Figure-0}{}\label{Label-Reference-Figure-0}
|
|
std::regex element_container_rgx(BS + R"(hypertarget\{(Reference-(\w+)-\d+)\}.*)");
|
|
std::regex element_caption_rgx(BS + R"(vstrut.*?\}\{.*?\}\{\s*(\w+)\s+(.+\.\d+).*)");
|
|
|
|
numbered_elements states(lines.size());
|
|
std::string id {};
|
|
std::string reftype {};
|
|
for (unsigned int i = 0; i < lines.size(); i++) {
|
|
std::smatch container_match {};
|
|
std::smatch caption_match {};
|
|
if (regex_match(lines[i], container_match, element_container_rgx)) {
|
|
id = container_match[1];
|
|
reftype = container_match[2];
|
|
} else if (regex_match(lines[i], caption_match, element_caption_rgx)) {
|
|
states[i] = {id, caption_match[1], caption_match[2]};
|
|
}
|
|
}
|
|
return states;
|
|
}
|
|
|
|
std::string find_target(std::string target,
|
|
std::vector<std::string>& lines, int start, numbered_elements states,
|
|
std::string target_type, int target_count, std::string direction)
|
|
{
|
|
// msg() << "find_target: " << target_type << " target_count: " << target_count
|
|
// << " direction: " << direction << "\n";
|
|
unsigned int offset = direction == "before" ? -1 : 1;
|
|
std::string current_type {};
|
|
int current_count = target_count;
|
|
unsigned int fi = start;
|
|
for (; fi > 0 && fi < lines.size(); fi += offset) {
|
|
// msg() << fi << " : " << states[fi] << "\n";
|
|
current_type = std::get<1>(states[fi]);
|
|
if (current_type == target_type) {
|
|
current_count--;
|
|
}
|
|
if (current_count == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (current_count > 0) {
|
|
std::stringstream msg {};
|
|
//ss << "No image exists that is \"" << direction << " " << current_count
|
|
// << "\" from line " << start << " in the HTML file.\n";
|
|
msg << "There is no " << target_type << " that is " << current_count
|
|
<< " " << direction << " the reference.\n";
|
|
//throw Argument_error(ss.str());
|
|
return "NOT FOUND: " + target_type + " " + direction;
|
|
}
|
|
std::stringstream ss {};
|
|
auto link_target = std::get<0>(states[fi]);
|
|
auto link_desc = std::get<2>(states[fi]);
|
|
if (target == "html") {
|
|
ss << "<a href=\"^#" << link_target << "\">" << target_type << " " << link_desc << "</a>";
|
|
} else if (target == "tex" || target == "latex") {
|
|
ss << BS << "figureref{" << link_target << "}{" << target_type << " " << link_desc << "}";
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
std::string resolve_caption_references(
|
|
std::string target, std::vector<std::string> lines, numbered_elements states)
|
|
{
|
|
//auto lines = regex_split(text, std::regex(R"(\n)"), false);
|
|
// numbered_elements states = line_states(lines);
|
|
//std::regex reference_rgx(R"((.*?)___([A-Za-z]+) (\w+) (\d+)___([^\n]*))");
|
|
//std::regex reference_rgx(R"((.*?)<a href=\"__(\w+)( \d+)?__\">(\w+)</a>)");
|
|
|
|
std::regex reference_rgx(R"((.*?)__REF__(\w+)( \d+)?__(\w+)__)");
|
|
|
|
std::string result;
|
|
for (unsigned int i = 0; i < lines.size(); i++) {
|
|
std::string line = lines[i];
|
|
if (line.find("__REF__") == std::string::npos) {
|
|
result += line + "\n";
|
|
} else {
|
|
std::sregex_iterator end {};
|
|
size_t endpos = 0;
|
|
std::string mline {};
|
|
for (std::sregex_iterator p
|
|
{line.begin(), line.end(), reference_rgx}; p!= end; ++p) {
|
|
std::smatch match = *p;
|
|
std::string prefix = match[1];
|
|
std::string direction = match[2];
|
|
int count = match[3] == "" ? 1 : std::stoi(match[3]);
|
|
std::string target_type = match[4];
|
|
mline += prefix +
|
|
find_target(target, lines, i, states, target_type, count, direction);
|
|
endpos = match.position() + match.length();
|
|
}
|
|
if (endpos < line.size()) {
|
|
mline += line.substr(endpos);
|
|
}
|
|
// msg() << " mline: " << mline << "\n";
|
|
result += mline + "\n";
|
|
}
|
|
}
|
|
return result;
|
|
}
|