kdesc --typeface from the reflection klammerset; a missing font directory is a row, not an error

Assembled from klammertext-dev daad6273483a. The font-store listing is
rendered from ref/ (one table per search directory, in search order,
with the styles each typeface holds); the search path is described,
not validated, so a KLAMMERTEXT_FONTS directory that does not exist --
the default ~/.klammertext/fonts on a fresh install -- is a row saying
so and the command exits 0. A typeface an earlier directory also holds
is marked shadowed, with the winning directory, in a column present only
when needed. The store's layout convention has one reader,
fonts_in_directory(). Six kdesc suite cases pin the listing.
This commit is contained in:
ack committed 2026-09-23 17:36:35 +02:00
1 parent c016b3e5f3
commit f9af1ff869
7 files changed
+188 -103

No files matched your search

+9
View File
@@ -55,3 +55,12 @@
@@katom_rewrite_patterns.* ::
@eval :cpp *KLAMMERTEXT_HOME*/ref/reflect katom_rewrite_patterns @ @@
@@klammertext_fonts.k :
List the typefaces the font store can resolve, one table per search
directory in search order -- the KLAMMERTEXT_FONTS directories (by default
$HOME/.klammertext/fonts), then the Klammertext default set -- with the
font styles each holds. A typeface found in an earlier directory shadows
the same one found later, and the later row says so. @@
@@klammertext_fonts.* ::
@eval :cpp *KLAMMERTEXT_HOME*/ref/reflect klammertext_fonts @ @@
+84
View File
@@ -1,4 +1,6 @@
#include <map>
#include <set>
#include <vector>
#include "machine.h"
#include "character.h"
@@ -335,3 +337,85 @@ std::string katom_rewrite_patterns([[maybe_unused]] Machine& machine)
kt << "table@\n";
return kt.str();
}
// A path written into generated Klammertext: the six specials and the
// txt target's nbsp marker ~ quoted with ^, which any ASCII punctuation
// accepts. A font directory is the user's to name, so it may hold any of them.
static std::string kt_literal(const std::string& text)
{
static const std::string quoted = "@|#^:*~";
std::string result {};
for (char c : text) {
if (quoted.find(c) != std::string::npos) {
result += '^';
}
result += c;
}
return result;
}
// The font store as a table per search directory, in search order. The
// search path is DESCRIBED here, not validated: a directory that does not
// exist is a row saying so, never an error, because resolve_font() skips
// one silently (a document renders fine with it) and a fresh install has no
// ~/.klammertext/fonts yet -- the default entry would fail every new user.
// kdesc --klammersets treats a missing search directory the same way.
extern "C"
std::string klammertext_fonts([[maybe_unused]] Machine& machine)
{
std::stringstream kt {};
kt << "@s2 Klammertext typefaces and font styles @\n\n";
// The directory each dir_name was FIRST seen in: the store searches in
// this order and stops at the first hit, so a later one is shadowed.
std::map<std::string, std::string> first_seen {};
strings_t bases = installed_font_dirs();
bases.push_back(default_font_dir());
for (size_t i = 0; i < bases.size(); i++) {
const std::string& base = bases[i];
bool is_default = (i == bases.size() - 1);
std::string caption = is_default
? "Klammertext default typefaces: " + kt_literal(symbolic_klammertext_filename(base))
: "Installed typeface directory: " + kt_literal(base);
// Rows before the header: the "Shadowed by" column exists only in a
// table that has something to put in it.
struct Row { std::string family, styles, shadowed_by; };
std::vector<Row> rows {};
bool any_shadowed = false;
for (const Resolved_font& font : fonts_in_directory(base)) {
strings_t styles {};
if (!font.regular.empty()) styles.push_back("Regular");
if (!font.bold.empty()) styles.push_back("Bold");
if (!font.italic.empty()) styles.push_back("Italic");
if (!font.bold_italic.empty()) styles.push_back("BoldItalic");
Row row { kt_literal(font.family_name), join(styles, ", "), "" };
if (first_seen.contains(font.dir_name)) {
row.shadowed_by = kt_literal(first_seen[font.dir_name]);
any_shadowed = true;
} else {
first_seen[font.dir_name] = base;
}
rows.push_back(row);
}
kt << "\n@table :caption " << caption << " |\n"
<< "Typeface name | Font styles" << (any_shadowed ? " | Shadowed by" : "")
<< " ||\n";
if (!fs::is_directory(base)) {
kt << "[directory does not exist] ||\n";
} else if (rows.empty()) {
kt << "[no fonts] ||\n";
}
for (const Row& row : rows) {
kt << row.family << " | " << row.styles;
if (any_shadowed) {
kt << " | " << row.shadowed_by;
}
kt << " ||\n";
}
kt << "table@\n\n";
}
return kt.str();
}