The ansi target, txt table styles, kdesc reference from ref/, typeface and table-width fixes (from dev fcec5e2e77ac)
Since the previous release: Machine::read_string() (the fs::path/std::string overload pair split); kdesc -c and -u rendered from the ref/ reflection klammerset; a fit column's tex width measured in TeX over every entry; @typeface resolving to the family its css declares (a store directory name now works in html) and hieroglyphs in @unicode_examples set in their typeface; the ansi target -- plain text with the type styles a terminal can show, identical to txt once the escape sequences are stripped -- with the txt @table carrying :header_style, :style and :hline; @block anchoring, @table spacing and the Image_quality state variable; and the rewritten doc/klammertext_for_llm.md.
This commit is contained in:
1 parent
760fda5470
commit
9b0d0d7897
34 files changed
+895
-394
No files matched your search
+77
-11
@@ -1,7 +1,7 @@
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
import kutil
|
||||
import klammer_base
|
||||
|
||||
# Emitted by @vspace.txt (sks/block/block.k), one marker per line of space.
|
||||
# An @eval result consisting only of whitespace is trimmed away by the
|
||||
@@ -25,6 +25,75 @@ def txt_vspace_marker():
|
||||
def txt_nbsp_marker():
|
||||
return "__KTEXTNBSP__"
|
||||
|
||||
# The type-style markers, emitted by @b.txt, @i.txt, @u.txt and @ri.txt
|
||||
# (sks/font/font.k) around their text. Plain text has no bold, but a
|
||||
# terminal does: the txt target STRIPS these in its last phase
|
||||
# (txt_strip_styles) and the ansi target, which :includes txt, RESOLVES
|
||||
# them to SGR escape sequences in its last phase (ansi_resolve_styles).
|
||||
# So the two targets differ in nothing but that phase, and stripping the
|
||||
# escape sequences from an ansi render gives the txt render byte for byte
|
||||
# (sks/tst/ansi_test.sh pins it). Every phase before the last measures
|
||||
# them as ZERO width -- txt_visible_length below, which txt_wrap and the
|
||||
# table layout use -- or a bold word would cost thirteen columns of line
|
||||
# that the reader never sees.
|
||||
#
|
||||
# The OFF sequences are the specific resets (22 ends bold, 23 italic, 24
|
||||
# underline), never "\033[0m": @b @i x @ y @ must leave y bold, and a
|
||||
# blanket reset would cancel the outer style with the inner one.
|
||||
TXT_STYLES = {
|
||||
"bold": ("\033[1m", "\033[22m"),
|
||||
"italic": ("\033[3m", "\033[23m"),
|
||||
"underline": ("\033[4m", "\033[24m"),
|
||||
}
|
||||
|
||||
def txt_style_marker(style, on=True):
|
||||
if style not in TXT_STYLES:
|
||||
raise ValueError(f"unknown type style {style!r}; one of {sorted(TXT_STYLES)}")
|
||||
return f"__KTEXT{style.upper()}{'' if on else 'OFF'}__"
|
||||
|
||||
_STYLE_MARKER_RGX = re.compile(
|
||||
"|".join(re.escape(txt_style_marker(s, on))
|
||||
for s in TXT_STYLES for on in (True, False)))
|
||||
|
||||
def txt_strip_styles(text, K):
|
||||
return _STYLE_MARKER_RGX.sub("", text)
|
||||
|
||||
def ansi_resolve_styles(text, K):
|
||||
for style, (on, off) in TXT_STYLES.items():
|
||||
text = text.replace(txt_style_marker(style), on)
|
||||
text = text.replace(txt_style_marker(style, False), off)
|
||||
return text
|
||||
|
||||
def txt_visible_length(s):
|
||||
"""How many columns s occupies once its markers resolve: a KTESC
|
||||
marker is one glyph, an nbsp marker one space, a style marker nothing.
|
||||
len() is the wrong measure for anything laid out (see txt_util)."""
|
||||
s = _STYLE_MARKER_RGX.sub("", s)
|
||||
return len(klammer_base.unescape_ktesc(s).replace(txt_nbsp_marker(), " "))
|
||||
|
||||
def txt_wrap(text, width, subsequent_indent=""):
|
||||
"""textwrap.wrap(text, width, break_long_words=False) measured by
|
||||
VISIBLE width. textwrap counts characters, so a marker inside a word
|
||||
-- a bold word carries a thirteen-character marker at each end -- made
|
||||
it break lines a dozen columns early. Whitespace runs are kept as
|
||||
written (sentence spacing survives), a word longer than the measure
|
||||
stands on its own line, and no word is broken at a hyphen."""
|
||||
chunks = re.split(r"(\s+)", text.strip())
|
||||
lines, line, sep = [], "", ""
|
||||
for i in range(0, len(chunks), 2):
|
||||
word = chunks[i]
|
||||
if word:
|
||||
if line and (txt_visible_length(line) + len(sep)
|
||||
+ txt_visible_length(word) > width):
|
||||
lines.append(line)
|
||||
line = subsequent_indent + word
|
||||
else:
|
||||
line += sep + word
|
||||
sep = " " * len(chunks[i + 1]) if i + 1 < len(chunks) else ""
|
||||
if line:
|
||||
lines.append(line)
|
||||
return lines
|
||||
|
||||
# The tex line break, carried as a marker.
|
||||
#
|
||||
# @nl.tex used to emit "\\newline" directly, and that is destroyed the moment
|
||||
@@ -92,8 +161,8 @@ def txt_justify_blocks(text, K):
|
||||
nbsp = txt_nbsp_marker()
|
||||
if par and par[0] != ' ' and not par.startswith(nbsp):
|
||||
label = re.match("(?:" + re.escape(nbsp) + r")*\[\d+\] ", par)
|
||||
par = "\n".join(textwrap.wrap(
|
||||
par, width=int(K.Target_txt_width), break_long_words=False,
|
||||
par = "\n".join(txt_wrap(
|
||||
par, int(K.Target_txt_width),
|
||||
subsequent_indent=" " * len(label.group(0)) if label else ""))
|
||||
result += par + "\n\n"
|
||||
result = re.sub(" *" + txt_vspace_marker() + " *", "\n", result)
|
||||
@@ -121,15 +190,12 @@ def txt_insert_captions(text, K):
|
||||
caption = f"{name} {caption_number} - {text}"
|
||||
else:
|
||||
caption = text
|
||||
caption_width = len(caption) + indent
|
||||
if len(caption) > indented_width:
|
||||
caption = textwrap.wrap(
|
||||
# Visible widths throughout: a caption may carry style markers.
|
||||
if txt_visible_length(caption) > indented_width:
|
||||
caption = "\n".join(txt_wrap(
|
||||
caption, indented_width,
|
||||
#initial_indent ="~"*indent,
|
||||
subsequent_indent=txt_nbsp_marker()*indent)
|
||||
caption = "\n".join(caption)
|
||||
caption_width = indented_width
|
||||
line_length = max([len(e) for e in caption.split("\n")])
|
||||
subsequent_indent=txt_nbsp_marker()*indent))
|
||||
line_length = max([txt_visible_length(e) for e in caption.split("\n")])
|
||||
line = txt_nbsp_marker() * indent + "-" * line_length
|
||||
return caption + "\n" + line
|
||||
result = caption_rgx.sub(replace, text)
|
||||
|
||||
Reference in new issue
Block a user