#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 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 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& 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& 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 << "" << target_type << " " << link_desc << ""; } 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& 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"((.*?)(\w+))"); 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; }