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:
1 parent
9b0d0d7897
commit
0ead40f272
39 files changed
+734
-158
No files matched your search
+37
-6
@@ -14,6 +14,34 @@
|
||||
# :python_cast (lambda s : __import__("kutil").parse_length("tex", s))
|
||||
@@@
|
||||
|
||||
# Lengths on an axis (2026-09-16). A width and a height are different
|
||||
# types so that a value can only name a unit of its own axis: "w" and "pw"
|
||||
# belong to widths, "h" and "ph" to heights, and a mistake is an argument
|
||||
# error rather than a silent misreading. A BARE NUMBER is the natural
|
||||
# unit of the axis in every target -- characters for a width (a column in
|
||||
# txt, "ch" in html, the width of a digit in tex), lines for a height (a
|
||||
# newline in txt, "lh" in html, \baselineskip in tex) -- which is what lets
|
||||
# a klammer written for the page keep its meaning in a terminal. "length"
|
||||
# stays for the quantities with no axis (a rule thickness).
|
||||
@@@argtype width |
|
||||
a horizontal length. A bare number is that many characters (one column
|
||||
of plain text; in a proportional typeface, the width of a digit, so an
|
||||
indent or a column lines up across lines even where the letters do not).
|
||||
Otherwise a number with a unit: ^:width 2em, 12pt, 100px, .5w (that
|
||||
fraction of the text width), .5pw (of the page width); f or none for an
|
||||
element's natural width; a quoted string, whose set width is used where
|
||||
the target can measure it.
|
||||
:pattern 'float'^|'float'em^|'int'pt^|'int'px^|'float'w^|'float'pw^|f^|none^|"[^^"]+"
|
||||
@@@
|
||||
|
||||
@@@argtype height |
|
||||
a vertical length. A bare number is that many lines (blank lines in
|
||||
plain text; the line height of the surrounding text otherwise).
|
||||
Otherwise a number with a unit: ^:height 2em, 12pt, 100px, .5h (that
|
||||
fraction of the text height), .5ph (of the page height).
|
||||
:pattern 'float'^|'float'em^|'int'pt^|'int'px^|'float'h^|'float'ph
|
||||
@@@
|
||||
|
||||
@@@argtype lengths | a list of lengths
|
||||
:pattern ('length'^|\s+)*
|
||||
#:python_cast (lambda s : [__import__("kutil").parse_length("tex", e) for e in s.split()])
|
||||
@@ -37,15 +65,18 @@
|
||||
An offset has no meaning for a centered element and is ignored there.
|
||||
Written alone, ^:offset is the standard indentation (e.g. ^:hpos left
|
||||
^:offset), and a value overrides it (^:hpos right ^:offset 4em).
|
||||
# A single-purpose type, not a use of "length", because the two values
|
||||
# A single-purpose type, not a use of "width", because the two values
|
||||
# below are what the writer relies on and only a type can carry them: an
|
||||
# element is flush unless an offset is asked for (:default), and asking
|
||||
# without saying how much is the standard indentation (:alone). A general
|
||||
# length type must not declare :alone -- a bare option name has to read the
|
||||
# same way wherever it appears, and "2em" is meaningless for :width.
|
||||
:pattern 'length'
|
||||
:default 0pt
|
||||
:alone 2em
|
||||
# width type must not declare :alone -- a bare option name has to read the
|
||||
# same way wherever it appears, and "4" is meaningless for :width.
|
||||
# Both values are BARE numbers -- characters -- so that they mean the same
|
||||
# thing under txt as on the page (2026-09-16): four characters is about
|
||||
# the 2em the alone value used to be, and 0 is flush everywhere.
|
||||
:pattern 'width'
|
||||
:default 0
|
||||
:alone 4
|
||||
@@@
|
||||
|
||||
|
||||
|
||||
+49
-4
@@ -112,10 +112,27 @@ def _rest_split_level(s, dimensions):
|
||||
def rest_args(s, dimensions=1):
|
||||
return rest_split(s, dimensions)
|
||||
|
||||
def parse_length(target, s, rel_fraction):
|
||||
def choose(html_value, tex_value):
|
||||
def parse_length(target, s, rel_fraction=1, axis="width"):
|
||||
"""A length argument as the target's own length.
|
||||
|
||||
Returns (text, number, unit). `axis` is "width" or "height" and gives
|
||||
a BARE number its meaning -- characters or lines, the natural unit of
|
||||
the axis in every target (sks/kutil/kutil.k, the width and height
|
||||
argtypes): under txt the integer count itself; under html "ch" and
|
||||
"lh" (a consumer of "lh" writes the em fallback first, see
|
||||
css_height); under tex the width of a digit in the current font
|
||||
(\\fontcharwd) and \\baselineskip. `target` "txt" is accepted for the
|
||||
bare units only, since plain text has no other.
|
||||
"""
|
||||
def choose(html_value, tex_value, txt_value=None):
|
||||
if target == "txt" or target == "ansi":
|
||||
if txt_value is None:
|
||||
unit = "characters" if axis == "width" else "lines"
|
||||
raise Exception(f'The {axis} "{s}" has no meaning in plain text: '
|
||||
f'give a bare number of {unit}')
|
||||
return txt_value
|
||||
return html_value if target == "html" else tex_value
|
||||
pat = re.compile(r'(?:([0-9.]+)([a-z]+))|(none|f)|(?:"([^"]+)")')
|
||||
pat = re.compile(r'(?:([0-9.]+)([a-z]*))|(none|f)|(?:"([^"]+)")')
|
||||
#pat = re.compile(r'(?:([0-9.]+)([a-z]+))|(none|f)|(?:{([^}]+)})')
|
||||
|
||||
|
||||
@@ -138,6 +155,14 @@ def parse_length(target, s, rel_fraction):
|
||||
result = choose("", f"\\textwidth - \\widthof{{ {text[1:]}}}")
|
||||
else:
|
||||
result = choose("", f"\\widthof{{ {text}}}")
|
||||
elif units == "":
|
||||
# The natural unit of the axis.
|
||||
if axis == "height":
|
||||
result = choose(f"{num}lh", f"{num}\\baselineskip", str(round(num)))
|
||||
units = "lines"
|
||||
else:
|
||||
result = choose(f"{num}ch", f"{num}\\fontcharwd\\font`0 ", str(round(num)))
|
||||
units = "ch"
|
||||
elif units == "w":
|
||||
result = choose(f"{100 * num}vw", f"{num}\\textwidth")
|
||||
elif units == "h":
|
||||
@@ -149,11 +174,31 @@ def parse_length(target, s, rel_fraction):
|
||||
elif units == "px":
|
||||
result = choose(f"{round(num)}", f"{num}px")
|
||||
else:
|
||||
result = f"{num}{units}"
|
||||
# em, pt: the same text in html and tex; none in plain text.
|
||||
result = choose(f"{num}{units}", f"{num}{units}")
|
||||
result = re.sub("\t", "\\t", result)
|
||||
return result, num, units
|
||||
|
||||
|
||||
def parse_width(target, s, rel_fraction=1):
|
||||
return parse_length(target, s, rel_fraction, "width")
|
||||
|
||||
def parse_height(target, s, rel_fraction=1):
|
||||
return parse_length(target, s, rel_fraction, "height")
|
||||
|
||||
def css_height(prop, value):
|
||||
"""A CSS declaration for a height from parse_height's html text. The
|
||||
"lh" unit is recent (2023 in every major browser); an older browser
|
||||
ignores a declaration it cannot parse and keeps the previous one, so
|
||||
the em equivalent is written FIRST and lh second -- the standard
|
||||
fallback idiom, no detection needed."""
|
||||
if value.endswith("lh"):
|
||||
# A short decimal, not the float's full expansion (1.5 * 1.2 is
|
||||
# 1.7999999999999998 in binary).
|
||||
em = f"{float(value[:-2]) * 1.2:.4g}"
|
||||
return f"{prop}: {em}em; {prop}: {value}"
|
||||
return f"{prop}: {value}"
|
||||
|
||||
def old_parse_length(target, s):
|
||||
pat = re.compile(r'(?:([0-9.]+)([a-z]+))|(none|f)|("([^"]+)")')
|
||||
match = pat.match(s)
|
||||
|
||||
Reference in new issue
Block a user