import os
import re
import inspect
import html_util
from html_util import E
def black_text():
return "\033[0;30m"
def blue_text(text):
return f"\033[0;34m{text}\033[0m"
def red_text(text):
return f"\033[31m{text}\033[0m"
def msg(text=""):
frame = inspect.currentframe().f_back
print(blue_text(f"[{os.path.basename(frame.f_code.co_filename)}:{frame.f_lineno}]"), text)
def escape(s):
result = s
#result = re.sub(r"\b", r"\b", result)
#result = re.sub(r"\t", r"\t", result)
#result = re.sub("\f", r"\\f", result)
#result = re.sub("\v", r"\\v", result)
#result = re.compile("\\(.)").sub(r"\\\1", result)
return result
def klammertext_dir():
var = 'KLAMMERTEXT_HOME'
kdir = os.environ.get(var)
if kdir is None:
raise Exception(
f"The environment variable {var} must be defined as the top-level Klammertext directory")
return kdir
def cache_directory(relative_pathname, basename):
directory = relative_pathname
if not os.path.isdir(directory):
os.makedirs(directory)
result = directory + "/_klammertext_cache/" + basename
return result;
def sks_dirs():
result = 'kutil book document block font link section list image table code color'.split()
k = klammertext_dir()
result = [[e, f"{k}/sks/{e}"] for e in result]
return result
def sks_files_of_type(extension):
result = []
for base, sks_dir in sks_dirs():
filename = f'{sks_dir}/{base}.{extension}'
if os.path.exists(filename):
result.append([base, filename])
return result
def make_dir_if_necessary(d, delete_contents=False):
if not os.path.exists(d):
os.makedirs(d)
if delete_contents:
os.system(f'rm -rf {d}/*')
def protect_klammertext_special_characters(text):
result = text
result = re.compile(r"\^").sub("H̅", result)
result = re.compile(r"@").sub("A̅", result)
result = re.compile(r":").sub("̅C̅", result)
result = re.compile(r"\|").sub("̅B̅", result)
return result
# When did this ever make sense? Before the new word patterns, probably.
def bar_delimiter():
return "\3"
def double_bar_delimiter():
return "\4"
def caption_delimiter():
return "__CAPTION__"
def caption_marker(name, caption, delimiter=" - "):
caption = re.sub("\n", " ", caption)
d = caption_delimiter()
if caption:
caption = f"{delimiter}{caption}"
return f"{d}{name}{d}{caption}{d}"
def rest_split(s, dimensions=1):
"""Split bar-delimited text into nested lists, one level per dimension.
The delimiter for dimension n is a run of exactly n bar characters:
| separates elements, || separates lists of elements, ||| lists of
lists, and so on. This is the cast behind the rest(N) argument type.
One trailing top-level delimiter (the customary dangling separator
before a closing @) is removed; all other empty elements are
preserved, so a trailing | still makes an empty final cell.
"""
s = s.strip()
if not s:
return [] if dimensions > 0 else s
delimiter = "|" * dimensions
if s.endswith(delimiter) and not s.endswith("|" + delimiter):
s = s[:-len(delimiter)]
return _rest_split_level(s, dimensions)
def _rest_split_level(s, dimensions):
if dimensions <= 0:
return s.strip()
pattern = re.compile("(? 0:
result = '\n\n{}\n\n'.format(result)
return result
def filename_list(text):
"""Split a filename list; the Python twin of resolve_filename_list()
in mac/file.cpp (keep the two in sync). A standalone "/" (whitespace
on both sides) separates names, whose inner spacing is preserved;
without a separator, whitespace-separated tokens that do not name
existing files are rejoined with their neighbors into names that do.
A leading ~ expands to the home directory."""
text = text.strip()
if not text:
return []
parts = re.split(r'(?:^|(?<=\s))/(?:\s|$)', text)
if len(parts) > 1:
return [os.path.expanduser(p.strip()) for p in parts if p.strip()]
tokens = text.split()
result, i = [], 0
while i < len(tokens):
if os.path.isfile(os.path.expanduser(tokens[i])):
result.append(tokens[i])
i += 1
continue
acc, j, found = tokens[i], i + 1, False
while j < len(tokens):
acc += " " + tokens[j]
j += 1
if os.path.isfile(os.path.expanduser(acc)):
result.append(acc)
i = j
found = True
break
if not found:
result.append(tokens[i])
i += 1
return [os.path.expanduser(p) for p in result]