Width and height argtypes, kdesc --argtypes from ref/, txt @define/@left_right/@columns, kdiag --check value validation (from dev d6993110e9b3)

Also: the klammertext argtype (descriptions kept as source), txt table
wrapping and :hpos/:offset, @c between ‹ ›, txt section headings, the
ktext newline-only trim, capitalize(), and the argtype test suite.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ackandClaude Fable 5.1 committed 2026-09-16 16:59:49 +02:00
1 parent 9b0d0d7897
commit 0ead40f272
39 files changed
+734 -158

No files matched your search

+13 -10
View File
@@ -31,10 +31,10 @@ vertical mode is a no-op.
# Indented block
@@indent.k s :left.int 8 :right.int -1 :ragged.bool false :
Indented block. The *left* and *right* values are the number of characters for
indentation (as roughtly defined by "ex"). By default, *right* is set to the
*left* value (with -1 as the sentinel).
@@indent.k s :left.width 8 :right.width :ragged.bool false :
Indented block. *left* and *right* are widths: a bare number is that many
characters (the width of a digit in a proportional typeface), or a width
with a unit such as 2em. *right* defaults to the *left* value.
@@
@@indent.html,tex,txt :: @eval block.Indent(K) eval@ @@
@@ -124,13 +124,12 @@ indentation (as roughtly defined by "ex"). By default, *right* is set to the
@@extendpage.tex :: \enlargethispage{*linecount*\baselineskip} @@
@@extendpage.txt :: @@
# Vertical space
@@vspace.k lines.float : Vertical space, in multiples of the current line height @@
@@vspace.tex :: \vspace{*lines*\baselineskip} @@
@@vspace.html :: <div style="height: *lines*lh"></div> @@
@@vspace.txt :: @eval phases.txt_vspace_marker() * round(*lines*) @ @@
# The first parameter of the height type: a bare number is lines in every
# target (as it always was here), and a unit may now be given.
@@vspace.k lines.height : Vertical space: a number of lines, or a height such as 2em @@
@@vspace.html,tex,txt :: @eval block.Vspace(K) @ @@
# Vertical fill to end of page
@@ -146,6 +145,10 @@ only makes some vertical space. @@
@@vfill.html :: <div class="vfill"></div> @@
@@vfill.txt :: @vspace 3 @ @@
# Horizontal space
@@hspace.k width.width : Horizontal space of the given *width* (a bare number is characters) @@
@@hspace.html,tex,txt :: @eval block.Hspace(K) @ @@
# Questions and answers
@@ -202,7 +205,7 @@ bar (|) between each line. Then, two bars (||), and the right lines with a bar
betwen them.
@@
@@left_right.html,tex :: @eval block.Left_right(K) @ @@
@@left_right.html,tex,txt :: @eval block.Left_right(K) @ @@
# Footnote
+74 -13
View File
@@ -11,35 +11,56 @@ from html_util import E
import color
class Indent(klammer_base.Klammer_base):
"""An indented block (@indent). :left and :right are widths: a bare
number is characters in every target (2026-09-16); :right defaults to
:left."""
def __init__(self, K):
super().__init__(K)
# Doesn't do anything now:
# self.s = kutil.escape(self.s)
if self.right < 0:
if not self.right:
self.right = self.left
self.reduce = self.left + self.right
def html(self):
text_align = "justify" if not self.ragged else "left"
left = kutil.parse_width("html", self.left)[0]
right = kutil.parse_width("html", self.right)[0]
return E("div").body(self.s)\
.sty("margin", f"0.5rem {self.right}ex 0.5rem {self.left}ex")\
.sty("margin", f"0.5rem {right} 0.5rem {left}")\
.sty("text-align", text_align)\
.str()
def tex(self):
if self.ragged:
self.s = "\\raggedright " + self.s
result = rf"\hspace*{{{self.left}ex}}" + latex_util.minipage(
self.s, rf"\linewidth - {self.reduce}ex", center=False)
left = kutil.parse_width("tex", self.left)[0]
right = kutil.parse_width("tex", self.right)[0]
result = rf"\hspace*{{{left}}}" + latex_util.minipage(
self.s, rf"\linewidth - {left} - {right}", center=False)
result = latex_util.block(result)
return result
def txt(self):
indent = phases.txt_nbsp_marker() * self.left # a space that survives
width = int(self.Target_txt_width) - self.left - self.right + 1 # Off-by one for textwrap
result = self.s
result = re.sub("KK0022", '"', result)
result = indent + f"\n{indent}".join(textwrap.wrap(result, width=width, break_on_hyphens=True))
return result
left = int(kutil.parse_width("txt", self.left)[0])
right = int(kutil.parse_width("txt", self.right)[0])
indent = phases.txt_nbsp_marker() * left # a space that survives
width = int(self.Target_txt_width) - left - right
result = re.sub("KK0022", '"', self.s)
return phases.txt_lay_out(indent + f"\n{indent}".join(phases.txt_wrap(result, width)))
class Hspace(klammer_base.Klammer_base):
"""Horizontal space (@hspace): a width, so a bare number is characters
in every target."""
def __init__(self, K):
super().__init__(K)
def html(self):
return f'<span style="display: inline-block; width: {kutil.parse_width("html", self.width)[0]}"></span>'
def tex(self):
return f"\\hspace{{{kutil.parse_width('tex', self.width)[0]}}}"
def txt(self):
# The nbsp marker, not spaces: an @eval result of only whitespace
# is trimmed away entirely.
return phases.txt_nbsp_marker() * int(kutil.parse_width("txt", self.width)[0])
class Note(klammer_base.Klammer_base):
@@ -106,6 +127,26 @@ class Lines(klammer_base.Klammer_base):
def txt(self):
return self.lines
class Vspace(klammer_base.Klammer_base):
"""Vertical space (@vspace): the first parameter of the height type. A
bare number is lines in every target, as it always was here; a unit
(2em, 12pt) is now accepted as well, under html and tex."""
def __init__(self, K):
super().__init__(K)
def html(self):
height = kutil.parse_height("html", self.lines)[0]
return f'<div style="{kutil.css_height("height", height)}"></div>'
def tex(self):
return f"\\vspace{{{kutil.parse_height('tex', self.lines)[0]}}}"
def txt(self):
# One marker per line; the justification phase turns them into
# blank lines after paragraph normalization (a whitespace-only
# @eval result would be trimmed away, hence the markers).
return phases.txt_vspace_marker() * int(kutil.parse_height("txt", self.lines)[0])
class Left_right(klammer_base.Klammer_base):
def __init__(self, K):
super().__init__(K)
@@ -126,3 +167,23 @@ class Left_right(klammer_base.Klammer_base):
result += rf"\parbox{{\linewidth}}{{{left} \hfill {right}}}" + " \\\\\n"
result = result[:-3]
return result
def txt(self):
# Plain text: the left text at the block indent, the right text ending
# at Target_txt_width, the gap filled with the nbsp marker (the only
# space that survives to the output, and what marks the block as laid
# out). A pair that cannot share a line -- less than two columns
# between them -- goes on two lines, the right text still flush right.
nbsp = phases.txt_nbsp_marker()
indent = int(self.Target_txt_indent)
width = int(self.Target_txt_width)
lines = []
for left, right in self.rows:
left, right = left.strip(), right.strip()
gap = width - indent - phases.txt_visible_length(left) - phases.txt_visible_length(right)
if gap >= 2:
lines.append(nbsp * indent + left + nbsp * gap + right)
else:
lines.append(nbsp * indent + left)
lines.append(nbsp * max(indent, width - phases.txt_visible_length(right)) + right)
return phases.txt_lay_out("\n".join(lines))