Files
klammertext/sks/link/link.py
Andy Kopra 59c1599bc9 Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared.  Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".

Two new spellings in a definition's name.  A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own.  And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.

The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.

kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all".  NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".

Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.

Four new test suites: target_list, coverage, command_option, kdesc.

(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00

117 lines
3.8 KiB
Python
Executable File

import re
import os
import tempfile
import sys
import klammer_base
import urllib
import kutil
def html_link(target, link_text, is_section, no_quotation_marks):
# [__link__target__text__]
if not link_text:
if is_section:
link_text = target if no_quotation_marks else f"{target}"
else:
# Allow long URLs to break at a slash:
link_text = re.sub('/', '/<wbr>', target)
link_text = re.sub('/<wbr>/<wbr>', '//', link_text)
link_text = f'<tt>{link_text}</tt>'
target = f"[{target}]" if is_section else target
#result = f"[__link__{target}__{link_text}__]"
#return result
if target.startswith("http") or ".html" in target:
url = target
elif is_section:
url = f"__sectionlink__{target}__"
else:
url = f"^#{target}"
result = f'<a href="{url}">{link_text}</a>'
return result
def add_latex_footnote_if_necessary(url, link_text):
result = ""
if (('http://' in url or 'https://' in url) and
('http://' not in link_text and 'https://' not in link_text)):
escaped_url = re.sub('#', '\\#', url)
escaped_url = re.sub('%', '\\%', escaped_url)
result += f'\\footnote{{\\\rule{{0pt}}{{12pt}}\\texttt{{{escaped_url}}}}}'
return result
def latex_link(target, link_text, is_section, no_quotation_marks, add_footnote):
if target.startswith("http"):
if link_text and link_text != "URL":
result = f"#/ \\href{{{target}}}{{{link_text}}} #/"
else:
#result = f"\\\url{{{target}}}"
result = f"#/ \\href{{{target}}}{{{target}}} #/"
elif is_section:
if not link_text:
link_text = target if no_quotation_marks else f"``{target}''"
result = f"\\hyperlink{{__seclink__{target}__}}{{{link_text}}}"
else:
result = f"\\hyperlink{{{target}}}{{{link_text}}}"
# if add_footnote:
# if self.footnote:
# result += add_latex_footnote_if_necessary(target, link_text)
# print(result)
return result
class Link(klammer_base.Klammer_base):
def __init__(self, K):
super().__init__(K)
# self.show("Link")
def html(self):
return html_link(self.target, self.text, self.section, self.nq)
def tex(self):
return latex_link(self.target, self.text, self.section, self.nq, self.footnote)
def txt(self):
text = f'{self.text} ' if self.text else ''
return f'{text}[{self.url}]'
class Target(klammer_base.Klammer_base):
def __init__(self, K):
super().__init__(K)
id = K.id.strip()
id = re.compile(r'\s+', re.S).sub('-', id)
self.id = re.sub('_', '-', id)
def html(self):
id = self.id.split(':')[-1]
return f'<span id="{id}">{self.text}</span>'
def tex(self):
result = f'\\hypertarget{{{self.id}}}{{{self.text}}}'
#result += '\\label{{{}-label}}'.format(id)
return result
# Better to fail than return nothing; not possible to have a target in a text file.
# def txt(self):
# return ""
class Email(klammer_base.Klammer_base):
def __init__(self, K):
super().__init__(K)
def html(self):
def val(attr, s):
return "{}={}&".format(attr, re.sub(" ", "%20", s))
domain = "&^#46;".join(self.domain.split("."))
address = "{}&^#64;{}".format(self.name, domain)
href = "mailto&^#58;{}?".format(address)
if self.subject:
href += val("subject", self.subject)
if self.body:
href += val("body", self.body)
href = href[:-1]
result = '<a href="{}" class="monospace">{}</a>'.format(href, address)
return result
def tex(self):
return r'\texttt{{{}^@{}}}'.format(self.name, self.domain)