Files
Matthew Woehlke afd937eb3e cmRST: Split parsing into two phases
Refactor cmRST to split parsing into two phases; one which processes
directives and collects lines to be output, and a second which performs
the actual output. In particular, this fixes substitutions not being
replaced when the definition appears after usage.

To facilitate this, refactor how replacement definitions are collected
so that content included via `toctree` has a separate replacement
context.

Also, record the length of the previously output line, so that when
headings are detected, we can reconstruct the markup to match the
(potentially changed by replacements) final length of the header text.
2026-07-29 15:04:59 -04:00

122 lines
3.4 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <cstddef>
#include <iosfwd>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "cmsys/RegularExpression.hxx"
/** \class cmRST
* \brief Perform basic .rst processing for command-line help
*
* This class implements a subset of reStructuredText and Sphinx
* document processing. It is used to print command-line help.
*
* If you modify the capabilities of this class, be sure to update
* the Help/manual/cmake-developer.7.rst documentation and to update
* the Tests/CMakeLib/testRST.(rst|expect) test input and output.
*/
class cmRST
{
public:
cmRST(std::string docroot);
bool ProcessFile(std::string const& fname, bool isModule = false);
void Write(std::ostream& os);
private:
enum class Include
{
Normal,
Module,
TocTree
};
enum class Markup
{
None,
Normal,
Empty
};
enum class Directive
{
None,
ParsedLiteral,
LiteralBlock,
CodeBlock,
Replace,
TocTree
};
struct ContentLine
{
ContentLine() = default;
ContentLine(std::string l, size_t c, bool m)
: Content{ std::move(l) }
, Context{ c }
, InlineMarkup{ m }
{
}
std::string Content;
size_t Context;
bool InlineMarkup;
};
void ProcessRST(std::istream& is);
void ProcessModule(std::istream& is);
void Reset();
void ProcessLine(std::string const& line);
void NormalLine(std::string const& line);
void OutputLine(std::string const& line, bool inlineMarkup);
void WriteLine(std::ostream& os, ContentLine const& content);
std::string ReplaceSubstitutions(std::string const& line, size_t context);
void OutputMarkupLines(bool inlineMarkup);
bool ProcessInclude(std::string file, Include type);
void ProcessDirectiveParsedLiteral();
void ProcessDirectiveLiteralBlock();
void ProcessDirectiveCodeBlock();
void ProcessDirectiveReplace();
void ProcessDirectiveTocTree();
static void UnindentLines(std::vector<std::string>& lines);
std::string DocRoot;
int IncludeDepth = 0;
size_t ContextOffset = 0;
bool OutputLinePending = false;
bool LastLineEndedInColonColon = false;
Markup MarkupType = Markup::None;
Directive DirectiveType = Directive::None;
cmsys::RegularExpression CMakeDirective;
cmsys::RegularExpression CMakeModuleDirective;
cmsys::RegularExpression ParsedLiteralDirective;
cmsys::RegularExpression CodeBlockDirective;
cmsys::RegularExpression ReplaceDirective;
cmsys::RegularExpression IncludeDirective;
cmsys::RegularExpression TocTreeDirective;
cmsys::RegularExpression ProductionListDirective;
cmsys::RegularExpression NoteDirective;
cmsys::RegularExpression VersionDirective;
cmsys::RegularExpression ModuleRST;
cmsys::RegularExpression CMakeRole;
cmsys::RegularExpression InlineLink;
cmsys::RegularExpression InlineLiteral;
cmsys::RegularExpression Substitution;
cmsys::RegularExpression TocTreeLink;
cmsys::RegularExpression Header;
std::string::size_type LastLength;
std::vector<std::string> MarkupLines;
std::vector<ContentLine> OutputLines;
std::string DocDir;
std::vector<std::map<std::string, std::string>> Replace;
std::set<std::string> Replaced;
std::string ReplaceName;
};