Files

178 lines
6.9 KiB
C++
Raw Permalink Normal View History

#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(const 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(const 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(const std::string& target,
const std::vector<std::string>& lines, int start, const numbered_elements& states,
const std::string& target_type, int target_count, const 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(
const std::string& target, const 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;
}