katom types from ref/ in groups, @table :leading in lines of text and :rulesep, @code under txt, one table style attribute, literal-klammer options (from dev 2e453744f5e9)

kdesc --katoms is Klammertext rendered from ref/, the types in titled groups,
with --katoms full for the regex column.  @table :leading L is L lines of the
surrounding text in html as in pdf (default 1), and :rulesep spaces the
horizontal rules.  The html table has one style attribute, so :column_width
fractions take effect again.  @code and @source_listing render in plain
text; captions are numbered per kind there, and a table needs no blank line
around it.  @c takes :nd, and an option-shaped word before a bar inside
literal code is code.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ackandClaude Fable 5.1 committed 2026-09-21 22:37:13 +02:00
1 parent 63956c00e5
commit 217c0f3fc5
23 files changed
+625 -290

No files matched your search

+73 -7
View File
@@ -5,11 +5,13 @@
import re
import klammer_base
import kutil
import html_util
import txt_util
import phases
from html_util import E
import latex_util as L
def escape_newlines(s):
# A newline becomes the marker the html paragraph pass turns back into a
# line break, so a verbatim source file keeps its lines. Used by Source.
@@ -119,7 +121,13 @@ def tex_line(line):
a monospace font, which LaTeX will not collapse -- so the code's
indentation and internal alignment survive.
"""
return quote_specials(escape_latex(line)).replace(" ", "~")
# An apostrophe is hidden as a marker: after a quoted caret it would
# otherwise read back as "^" + "^'", the opening of a literal span, and
# "@c \^' c@" -- the regex of that very katom -- failed the document
# with a span that does not end. html_line hides it with the other
# typographic characters; the marker decodes to the plain character.
quoted = quote_specials(escape_latex(line)).replace("'", klammer_base.escape_ktesc("'"))
return quoted.replace(" ", "~")
def widest_line(lines):
r"""The line to measure the block's width with.
@@ -325,12 +333,64 @@ class Code(klammer_base.Klammer_base):
# As in tex: the caption goes through the shared helper, so it sits
# in the same position container as the listing and moves with it.
if self.number or self.caption:
# A left-placed (or flowing) listing's caption is flush with it,
# as in tex, where such a listing is unboxed and its caption a
# paragraph on the same indent; a centred or right-placed one is
# boxed there and its caption centred over the box, which is
# the helper's default here too.
align = "left" if self.hpos in ("left", "none") else None
return html_util.add_caption(
listing, "Listing", self.number, self.caption,
self.caption_style, self.hpos, self.caption_side, True,
self.caption_size, offset=self.offset)
self.caption_size, offset=self.offset, caption_align=align)
return html_util.hpos_container(listing, self.hpos, self.offset).str()
def txt_indent(self):
# The block's indent in columns, by @table's rule: a left- or
# right-placed block is inset by its :offset (0 = flush), ":hpos
# none" flows with no indent, and "center" -- not attempted in plain
# text -- keeps the block convention, Target_txt_indent.
if self.hpos in ("left", "right"):
return int(kutil.parse_width("txt", self.offset)[0])
if self.hpos == "none":
return 0
return int(self.Target_txt_indent)
def txt(self):
# The listing is LAID OUT here, line by line, and says so with the
# verbatim marker (phases.txt_lay_out) so the justification pass
# leaves it alone -- a blank line in the code included, which holds
# a marker and therefore does not end the paragraph.
#
# Each line is prepared exactly as txt()'s inline sibling prepares a
# fragment: the Klammertext specials QUOTED, because this result is
# re-read as Klammertext (raw, a "#" removed the rest of its line and
# a "code@" in a quoted source file closed the document's own span:
# "A named end katom does not match"), and the typographic characters
# hidden, so "--x" stays two hyphens. Spaces become the nbsp marker
# AFTER that, not "~": hide_typographic has already hidden the
# code's own tildes, and a "~" written here would be turned into a
# space by the txt target's transform only as long as it survived.
lines = self.text.strip("\n").split("\n")
indent = txt_util.NBSP * self.txt_indent()
def prepared(line):
line = klammer_base.hide_typographic(quote_specials(line.rstrip()))
return line.replace(" ", txt_util.NBSP)
width = max(len(line.rstrip()) for line in lines)
rule = indent + klammer_base.hide_typographic("-" * width)
body = [indent + prepared(line) for line in lines]
# A caption above the listing is ruled off by the caption pass, so
# the listing draws its own top rule only when nothing does.
captioned = self.number or self.caption
caption_above = captioned and self.caption_side in ("top", "left")
if not caption_above:
body.insert(0, rule)
body.append(rule)
result = phases.txt_lay_out("\n".join(body))
return txt_util.add_caption(
result, "Listing", self.number, self.caption, self.caption_side,
self.txt_indent())
class Code_fragment(klammer_base.Klammer_base):
def __init__(self, K):
@@ -356,10 +416,13 @@ class Code_fragment(klammer_base.Klammer_base):
# without a beginning) and the typographically active characters
# hidden, so a "--" in code stays two hyphens.
result = klammer_base.hide_typographic(quote_specials(self.code_text.strip()))
# Surround code symbols with ‹ and ›, though there are conflicts in Swiss
# German, Italian and some Scandinavian languages. Should be clear in
# context, though.
result = "\u2039" + result + "\u203A"
# If *nd* ("no delimiters) is false (the default), surround code symbols
# with the characters ‹ and ›. There are conflicts in Swiss German,
# Italian and some Scandinavian languages, but the meaning should be
# clear in context.
if not self.nd:
result = "\u2039" + result + "\u203A"
return result
def extract_marked_region(src, marker, filename):
@@ -424,6 +487,9 @@ class Source(Code):
# not exist until the file has been read. File content carries no
# whitespace markers anyway, since those come from the katomizer.
klammer_base.Klammer_base.__init__(self, K)
# The filename arrives with the target's escapes as markers -- under
# tex an underscore is one -- and a marker names no file.
self.filename = klammer_base.unescape_ktesc(self.filename)
try:
with open(self.filename) as fp:
text = fp.read()