A named group of optional parameters, declared once and used by several
klammers, so a writer learns one vocabulary instead of a spelling per
klammer. The "o" target is a pseudo-target beside "k": "k" declares a
klammer's interface and documents it, "o" declares an option interface and
documents it, and neither produces output for any target.
@@caption_args.o :caption :number.bool true :caption_side.side
: Arguments that define a caption for a block element @@
@@code.k :filename @hpos_args :hpos left @ @caption_args :caption_side top @
| text.literal : A source file displayed verbatim @@
A set is used only in the parameter list of a ".k" declaration -- the one
place a klammer's interface is declared once for all of its targets -- and
is resolved as that list is read. Names and types come from the set; a
default may be overridden where it is used. A klammer application in a
parameter list is now a definition-time error.
The SKS gains the sets caption_args and hpos_args (:hpos and :offset), and
@table, @image, @image_grid, @reference and @show gain .k declarations. A
distance is no longer written as a position: :hpos 4em is rejected, and the
same layout is :hpos left :offset 4em. Code listings are numbered by
default, like tables and figures.
New engine sources mac/option_set{,_registry}.{h,cpp}; tst/ ships two more
suites, option_set_test.sh and signature_test.sh (twelve in all).
(from dev 34e536cb0329)
167 lines
5.9 KiB
C++
167 lines
5.9 KiB
C++
#include <sstream>
|
|
#include <iterator>
|
|
|
|
#include "target_registry.h"
|
|
#include "error.h"
|
|
#include "log.h"
|
|
#include "util.h"
|
|
#include "show.h"
|
|
#include "log.h"
|
|
#include "katom.h"
|
|
|
|
std::string Target_registry::declare_name = "k";
|
|
std::string Target_registry::general_name = "*";
|
|
std::string Target_registry::optionset_name = "o";
|
|
|
|
Target_registry::Target_registry()
|
|
: m_parameters(Parameter_set("name | desc :after_apply :after_write :includes :escape | transforms.rest"))
|
|
{
|
|
Target k(declare_name, "Description of parameters and klammer result", Locator());
|
|
Target general(general_name, "General target, used when a target is not specified", Locator());
|
|
Target option_set(optionset_name, "Declaration of an option set: parameters shared by klammers", Locator());
|
|
add(k);
|
|
add(general);
|
|
add(option_set);
|
|
}
|
|
|
|
void Target_registry::add(Target target)
|
|
{
|
|
(void)K::log(3, target);
|
|
check_for_previous_definition(target.m_name, target.m_loc);
|
|
m_targets[target.m_name] = target;
|
|
m_names.push_back(target.m_name);
|
|
}
|
|
|
|
void Target_registry::add(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& katoms)
|
|
{
|
|
(void)K::log(3, *begin, *(end - 1));
|
|
auto [positional, optional, rest] =
|
|
argument_split(begin + 1, end - 1, m_parameters.m_positional.size());
|
|
auto values = m_parameters.value_map(positional, optional, rest, begin->m_loc);
|
|
|
|
//std::cout << ktype << "Transformed: " << kreplaced << std::pair(begin, end) << "\n";
|
|
//std::cout << values << "\n";
|
|
Target target(values["name"], values["desc"], begin->m_loc);
|
|
target.add_transforms(values["transforms"]);
|
|
target.add_escapes(values["escape"]);
|
|
target.add_after_apply(values["after_apply"]);
|
|
target.m_includes = word_split(values["includes"]);
|
|
// Inherit escapes from included targets
|
|
for (const auto& included : target.m_includes) {
|
|
if (m_targets.count(included)) {
|
|
for (const auto& esc : m_targets[included].m_escapes) {
|
|
target.m_escapes.push_back(esc);
|
|
}
|
|
}
|
|
}
|
|
// Registration (and the previous-definition check) goes through
|
|
// add(Target) -- the single registration path.
|
|
add(target);
|
|
|
|
for (auto& [name, defined_target] : m_targets) {
|
|
if (is_in(name, target.m_includes)) {
|
|
defined_target.m_provides.push_back(target.m_name);
|
|
}
|
|
}
|
|
|
|
// std::for_each(begin, end, [](Katom& k) { k.m_type = katom_t::replaced; });
|
|
modify_type(katom_t::replaced, begin, end);
|
|
auto next_iter = end;
|
|
ignore_whitespace(next_iter, katoms);
|
|
}
|
|
|
|
|
|
void Target_registry::check_for_previous_definition(const std::string& name, const Locator& loc) const
|
|
{
|
|
if (has(name)) {
|
|
const Target& current = m_targets.at(name);
|
|
throw Target_error("Target \"" + name + "\" is already defined:\n " + current.m_loc.desc(),
|
|
loc, false);
|
|
}
|
|
}
|
|
|
|
bool Target_registry::has(const std::string& target_name) const
|
|
{
|
|
// Membership comes from the map; m_names exists only to preserve
|
|
// definition order for describe().
|
|
return m_targets.count(target_name) > 0;
|
|
}
|
|
|
|
|
|
Target Target_registry::get(const std::string& target_name, const Locator& loc) const
|
|
{
|
|
if (has(target_name) || target_name == Target_registry::general_name) {
|
|
return m_targets.at(target_name);
|
|
} else {
|
|
throw Target_error("Target " + target_name + " does not exist", loc);
|
|
}
|
|
}
|
|
|
|
void Target_registry::transform(const std::string& target_name, katom_list& katoms) const
|
|
{
|
|
(void)K::log(3);
|
|
m_targets.at(target_name).transform(katoms);
|
|
}
|
|
|
|
std::vector<std::string> Target_registry::user_defined() const
|
|
{
|
|
return collect_if(
|
|
m_names, [](const auto& name) {
|
|
return name != Target_registry::declare_name
|
|
&& name != Target_registry::general_name
|
|
&& name != Target_registry::optionset_name; });
|
|
}
|
|
|
|
// The targets a klammer body can be applied under. Neither "k" nor "o"
|
|
// produces output: both declare an interface and describe it.
|
|
std::vector<std::string> Target_registry::applicable() const
|
|
{
|
|
return collect_if(
|
|
m_names, [](const auto& name) {
|
|
return name != Target_registry::declare_name
|
|
&& name != Target_registry::optionset_name; });
|
|
}
|
|
|
|
std::string Target_registry::describe(int margin, bool long_format) const
|
|
{
|
|
std::string tab(margin, ' ');
|
|
std::stringstream ss {};
|
|
std::vector<std::string> descs {};
|
|
for (const std::string& name : m_names) {
|
|
descs.push_back(m_targets.at(name).m_desc);
|
|
}
|
|
auto name_width = max_length(m_names);
|
|
auto desc_width = max_length(descs);
|
|
for (const std::string& name : m_names) {
|
|
const Target& t = m_targets.at(name);
|
|
if (long_format) {
|
|
ss << tab << std::setfill(' ') << std::setw(name_width) << std::right << name << " "
|
|
<< std::setw(desc_width) << std::left << t.m_desc << " "
|
|
<< t.m_loc.str() << "\n";
|
|
} else {
|
|
ss << tab << std::setfill(' ') << std::setw(name_width) << name << sp_arrow << t << "\n";
|
|
}
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
/*
|
|
void Targets::describe()
|
|
{
|
|
std::string intro =
|
|
"A \"target\" specifies the output format of Klammertext processing. "
|
|
"Targets are identified by the typical filename extension of the format. "
|
|
"A klammer defines how it converts its arguments to the appropriate structure for one or more targets. "
|
|
"The special target \"k\" is used for a klammer definition that describes that klammer's "
|
|
"arguments and purpose in the various targets for which it is defined. "
|
|
"If the klammer definition does not specify a target, the klammer can be used for any target.";
|
|
std::cout << "Klammertext targets\n\n" << justify(intro) << "\n\n";
|
|
for (std::string name : names) {
|
|
if (name == Target::any_target_name)
|
|
continue;
|
|
targets[name]->describe();
|
|
std::cout << "\n";
|
|
}
|
|
}
|
|
*/
|