txt section numbering, @typeface :middle/:lift and html scale, NewGardinerOmni, html :leading (from dev 9fa469dd74ed)

Section headings under txt are numbered inside a @document only; @typeface
gains :middle and :lift and its :scale now means the same in html and
pdf; NewGardinerOmni ships (OFL 1.1, Mark-Jan Nederhof) and @egyptian /
@chinese replace @cjk; @table :leading and :colsep reach html; kdesc
--typeface help names the flag; @document.txt is a Python class.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ackandClaude Fable 5.1 committed 2026-09-18 20:02:44 +02:00
1 parent 0ead40f272
commit 63956c00e5
26 files changed
+437 -173

No files matched your search

+4 -1
View File
@@ -51,7 +51,10 @@ document.so : $(LOCAL_OBJECTS) $(SKS_OBJECTS) $(LIBRARY) document.cpp | deps
document.cpp -o $@ $(ALL_OBJECTS) -lklammertext $(LDLIBS)
clean :
rm -f $(LOCAL_OBJECTS) $(LOCAL_DEPFILES) *.so *~ __pycache__
rm -f $(LOCAL_OBJECTS) $(LOCAL_DEPFILES) *.so *~
# document_txt.py is imported at render time (2026-09-18), so this
# directory now exists here; rm -f refused it and failed every clean.
rm -rf __pycache__
# Include generated dependency files (if they exist)
-include $(LOCAL_DEPFILES)
+4 -15
View File
@@ -62,21 +62,10 @@
: Top-level document structure
@@
@@document.html,tex :: @eval :cpp *KLAMMERTEXT_HOME*/sks/document/document document @ @@
# The following definition of @document.txt is not adequate (it ignores :files,
# for example), but it enables tests of other txt klammers for now. When one of
# the arguments is empty, the justifcation postprocess should remove multiple
# lines, but __VSPACE__ inserts a space character, which prevents the lines
# removal from the justification function. You can also see the extra space
# before the *subtitle* value.
@@document.html,tex ::
@eval :cpp *KLAMMERTEXT_HOME*/sks/document/document document @
@@
@@document.txt ::
@eval "*title*".upper() @ @nl@
*subtitle*
*author* @nl@
*date*
*text*
@eval document_txt.Document(K) @
@@
-23
View File
@@ -1,23 +0,0 @@
import kutil
import html_util
import tex_util
class Document(klammer_base.Klammer_base):
def __init__(self, K):
super().__init__(K)
def html(self):
if self.include_css == "true":
css_code, css_files = html_util.css(self.css, self._sks_enabled)
head = html_util.head(self.title, css_files=css_files, css_code=css_code)
else:
head = head = html_util.head(self.title, include_fonts=self.include_fonts == "true")
return html_util.page(head, self.body)
def tex(self):
ragged_right = self.ragged_right in {"true", "True", "1"}
return tex_util.page(
self.title, self.subtitle, self.leading, self.pointsize, ragged_right, self.body)
def txt(self):
return self.body
+6 -20
View File
@@ -340,9 +340,14 @@ std::string Document_class::typeface_preamble()
std::stringstream ss {};
for (size_t i = 0; i < m_extra_typefaces.size(); i++) {
const auto& [name, scale] = m_extra_typefaces[i];
// Compared by directory name, as collect_typefaces() compares: a
// @typeface may write the family name or the store's directory
// name, and family_name holds what the css declares (2026-09-12),
// so a name-for-name comparison missed the directory spelling and
// left \ktface<n> undefined in the .tex (found 2026-09-17).
const Resolved_font* rf = nullptr;
for (const auto& f : m_resolved_extra)
if (f.family_name == name) rf = &f;
if (f.dir_name == name_to_dirname(name)) rf = &f;
if (!rf) continue;
// \newfontfamily declares a switch command, unlike \setmainfont,
// which changes the document's font permanently.
@@ -351,22 +356,3 @@ std::string Document_class::typeface_preamble()
}
return ss.str();
}
/*
void output_msg(const std::string& msg)
{
std::cout << red;
(void)K::log(1, msg);
std::cout << black;
}
void Document_class::create_directory(const std::string& directory)
{
if (write_files) {
fs::create_directories(directory);
} else {
output_msg("Output directory: " + directory);
}
}
*/
+19
View File
@@ -1,3 +1,4 @@
#include <iomanip>
#include "util.h"
#include "error.h"
#include "log.h"
@@ -118,6 +119,24 @@ std::string Document_class::font_definitions()
ss << " --sans-serif: \"" << m_resolved_sans.family_name << "\", sans-serif;\n";
if (!m_mono_typeface.empty())
ss << " --monospace: \"" << m_resolved_mono.family_name << "\", monospace;\n";
// The factor a @typeface span's font-size is multiplied by (2026-09-18).
// font.css renders the body at "font-size-adjust: ex-height 0.5", so
// the text the reader sees is 0.5 / x-height times its nominal size
// (EB Garamond, x-height 0.400: 1.25). A @typeface span switches
// the adjust OFF (a script with no x-height cannot be matched), so
// its ":scale N" was N times the NOMINAL size -- about a fifth
// smaller against the visible text than the same N in pdf, where
// fontspec's Scale= is against text rendered at nominal size.
// Folding the body's enlargement in here makes :scale mean the
// same thing in both targets. Emitted as a custom property the
// span multiplies in with calc(), so a fragment rendered without
// @document falls back to 1. SYNC: the anchor 0.5 is font.css's.
const float xheight_anchor = 0.5f;
if (m_resolved_serif.xheight_ratio > 0.0f) {
std::stringstream factor {};
factor << std::setprecision(4) << xheight_anchor / m_resolved_serif.xheight_ratio;
ss << " --typeface_scale: " << factor.str() << ";\n";
}
ss << "}\n";
}
// Font-size normalization across families is no longer emitted from
+33
View File
@@ -0,0 +1,33 @@
import kutil
import klammer_base
import phases
class Document(klammer_base.Klammer_base):
def __init__(self, K):
super().__init__(K)
if self.files:
raise Exception("The :files option is not defined for the 'txt' target")
def html(self):
raise Exception("Implemented by document.cpp")
def tex(self):
raise Exception("Implemented by document.cpp")
def txt(self):
# The document marker: section numbering under txt is a document
# service, and the numbering phase numbers only when it finds this
# at the head of the text (a fragment, as kdesc renders, has none).
result = phases.txt_document_marker() + "\n"
if self.title:
result += f"@b {self.title} @ @nl@\n"
if self.subtitle:
result += f"@b {self.subtitle} @ @nl@\n"
result += "\n"
if self.author:
result += f"@i {self.author} @ @nl@\n"
if self.date:
result += f"@i {self.date} @ @nl@\n"
result += "\n"
result += self.text
return result