A section link names the TEXT of a heading: :section alone means the current file, a value names the file of the same @document that has it. Resolved by @document at assembly in html and tex; errors for a missing file, a missing title, a doubled title and a link outside a @document. The Markdown converter reads a Markdown anchor as a section link to the heading its slug names. Also from dev: the converter's four silent defects fixed and --chapter (9ae2c4cd), and the engine's alone-value error text. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
50 lines
2.4 KiB
C++
50 lines
2.4 KiB
C++
// @link :section -- a link to a section by the TEXT of its heading.
|
|
//
|
|
// Decided by Andy, 2026-10-12. :section (argtype section_link) written
|
|
// alone says the heading is in the CURRENT file; written with a value, the
|
|
// value is the basename (no directory, no extension) of the file of the
|
|
// same @document that has it. So a link names exactly one file, and a
|
|
// title shared between files is never ambiguous. Titles match with
|
|
// klammer markup removed and whitespace collapsed to one space,
|
|
// case-sensitive.
|
|
//
|
|
// Resolution happens here, when @document assembles its files -- the only
|
|
// place every heading is known -- from two markers the klammers emit:
|
|
// Link __seclink__<title>__KTSL__<file>__ (in the href / \hyperlink;
|
|
// <file> empty for the current one)
|
|
// Section %__sectionlink__<id>__KTSL__<basename>__KTSL__<title>__ (tex only;
|
|
// the html pass reads the heading elements themselves, which
|
|
// carry their ids after insert_ids())
|
|
// KTSL separates the fields because a title or a basename may contain a
|
|
// single underscore (md_to_sks_test). A file the document does not have, a
|
|
// title the file does not have, and a title it has more than once are
|
|
// errors, never fallbacks (the commands do not warn and continue).
|
|
#ifndef SECTION_LINK_H
|
|
#define SECTION_LINK_H
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
struct Section_target {
|
|
std::string title {}; // normalized
|
|
std::string basename {}; // the file's basename, "" for :text content
|
|
std::string id {}; // the anchor: html id, or tex \hypertarget name
|
|
};
|
|
|
|
// The comparison form of a heading's text: tags and TeX control sequences
|
|
// removed, braces dropped, whitespace collapsed, trimmed.
|
|
std::string normalize_section_title(const std::string& s);
|
|
|
|
// The target a :section link names, or an Argument_error that says why
|
|
// there is none. FILE is the :section value ("" for the current file),
|
|
// WHERE the basename of the file holding the link ("" for the document's
|
|
// :text) and FILES the document's basenames. At assembly the link's own
|
|
// position is gone, so the file is the location an error can give
|
|
// (Locator::none(), never the C++ site).
|
|
Section_target resolve_section_target(
|
|
const std::vector<Section_target>& table, const std::string& title,
|
|
const std::string& file, const std::string& where,
|
|
const std::vector<std::string>& files);
|
|
|
|
#endif
|