Option sets: a .o target for shared parameters

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)
This commit is contained in:
2026-08-06 13:11:37 +02:00
parent 4306dcd490
commit 6e7596ab2e
37 changed files with 2198 additions and 267 deletions

View File

@@ -591,10 +591,11 @@ class Table(klammer_base.Klammer_base):
result, "Table", self.number, self.caption,
self.caption_font, hpos=self.hpos,
side=self.caption_side,
font_size=self.caption_font_size, max_width="100%")
font_size=self.caption_font_size, max_width="100%",
offset=self.offset)
else:
result.attr("style", "max-width: 100%")
result = html_util.hpos_container(result, self.hpos).str()
result = html_util.hpos_container(result, self.hpos, self.offset).str()
return result
colgroup, layout, table_width = self.html_colgroup()
result = E("table").body(colgroup + result)
@@ -607,13 +608,14 @@ class Table(klammer_base.Klammer_base):
result = html_util.add_caption(
result, "Table", self.number, self.caption, self.caption_font,
hpos=self.hpos, side=self.caption_side,
font_size=self.caption_font_size, width=table_width)
font_size=self.caption_font_size, width=table_width,
offset=self.offset)
else:
# An uncaptioned table still gets the position container, so
# html and tex agree on where the table sits.
if table_width:
result.attr("style", f"{layout}width: {table_width}")
result = html_util.hpos_container(result, self.hpos).str()
result = html_util.hpos_container(result, self.hpos, self.offset).str()
return result
# LaTeX
@@ -768,14 +770,25 @@ class Table(klammer_base.Klammer_base):
# by its :hpos wrapper instead; its glue is left neutral (\fill on
# both sides collapses in the exactly-fitting box), because a fixed
# length would overflow the box. A length is the left margin.
# :offset insets the table from the margin :hpos names -- the same
# rule the boxed path gets from latex_util.caption_wrapper, here
# expressed as the fixed side of the glue pair.
inset = latex_util.offset_length(self.offset)
if not self.allow_break:
left, right = "\\fill", "\\fill"
elif self.hpos == "center":
left, right = "\\fill", "\\fill"
elif self.hpos == "left":
left, right = "0pt", "\\fill"
left, right = inset, "\\fill"
elif self.hpos == "right":
left, right = "\\fill", "0pt"
left, right = "\\fill", inset
elif self.hpos == "none":
# No positioning container: the table starts at the text margin
# like ordinary text, which is what "none" does in html (the
# hpos_none class is inline-flex). A longtable cannot flow
# inline, so flush left is as close as the target gets. The
# offset names no margin here and is ignored, as when centered.
left, right = "0pt", "\\fill"
else:
length, _, _ = kutil.parse_length("tex", self.hpos, 1)
left, right = length, "\\fill"
@@ -824,9 +837,9 @@ class Table(klammer_base.Klammer_base):
result, "Table", self.number, self.caption, "\\tableboxwidth",
hpos=self.hpos, side=self.caption_side,
font_symbol=self.caption_font,
font_size=self.caption_font_size)
font_size=self.caption_font_size, offset=self.offset)
else:
result = latex_util.caption_wrapper(result, self.hpos)
result = latex_util.caption_wrapper(result, self.hpos, offset=self.offset)
result = measure + result
result = f"\\hypertarget{{{name}}}{{}}\\label{{Label-{name}}}\n{result}"
@@ -845,7 +858,11 @@ class Table(klammer_base.Klammer_base):
+ self.tex_fill_widths()
+ result)
result = re.sub(r"\newline", r"\\\\", result)
return result
# A boxed table is box material: it must sit in vertical mode or it
# is typeset beside any text it follows. (A page-breaking longtable
# breaks the paragraph itself, but \par on both sides is a no-op
# there, so the rule stays unconditional.)
return latex_util.block(result)
def txt(self):
return "Table in .txt format not implemented"