Initial commit: Klammertext source distribution
Curated source subset assembled by klammertext-dev's doc/make_dist.sh: the Klammermachine (mac), the Standard Klammer Set (sks), the commands (com), editor plugins and install guides (doc), a test subset (tst), and lib/bin placeholders. Builds with 'make -C com'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
467
sks/list/list.py
Normal file
467
sks/list/list.py
Normal file
@@ -0,0 +1,467 @@
|
||||
import pprint
|
||||
import re
|
||||
import textwrap
|
||||
import kutil
|
||||
import klammer_base
|
||||
import itertools
|
||||
import math
|
||||
from html_util import E
|
||||
|
||||
class List(klammer_base.Klammer_base):
|
||||
def __init__(self, K, list_type):
|
||||
super().__init__(K)
|
||||
self.list_type = list_type
|
||||
self.items = kutil.rest_args(self.list_items)
|
||||
if self.items[-1].strip() == "":
|
||||
self.items = self.items[:-1]
|
||||
word_count = max([len(e.strip().split()) for e in self.items])
|
||||
self.compressed = False #and word_count < int(self.List_compressed_word_max)
|
||||
|
||||
def html(self):
|
||||
body = ""
|
||||
word_count = 0
|
||||
for e in self.items:
|
||||
body += f"<li>\n{kutil.format_for_paragraphs(e.strip())}\n</li>\n"
|
||||
cls = "compressed" if self.compressed else ""
|
||||
result = E(self.list_type).cls(cls).body(body.strip()).str().strip() + "\n"
|
||||
return result
|
||||
|
||||
def tex(self):
|
||||
body = "\n\n".join([f"\\item {e}" for e in self.items])
|
||||
command = {'ol' : 'enumerate', 'ul' : 'itemize'}[self.list_type]
|
||||
init = ""
|
||||
if self.__dict__.get("initial") and self.initial != 1:
|
||||
init = "\\addtocounter{enumi}{" + str(int(self.initial) - 1) + "}"
|
||||
#topsep = '[noitemsep,topsep=0pt]'
|
||||
topsep = "[noitemsep,topsep=0pt," if self.compressed else "[topsep=0pt,itemsep=2pt,"
|
||||
topsep += "leftmargin=16pt]"
|
||||
listsep = '\\setlist{nolistsep}' if self.cmp == 'true' else ''
|
||||
result = f'{listsep}\n\\begin{{{command}}}{topsep}{init}\n{body}\n\\end{{{command}}}\n'
|
||||
return result
|
||||
|
||||
def txt(self):
|
||||
n = 1
|
||||
result = ""
|
||||
for item in self.items:
|
||||
prefix = f"{n:3}. " if self.list_type == "ol" else " • " # U+2022
|
||||
print("prefix", prefix)
|
||||
formatted_item = "\n".join(
|
||||
textwrap.wrap(item.strip(), width=80, subsequent_indent=" "*(len(prefix))))
|
||||
result += f"{prefix}{formatted_item}\n"
|
||||
if not self.compressed:
|
||||
result += "\n"
|
||||
n += 1
|
||||
print(result)
|
||||
return result
|
||||
|
||||
|
||||
class Define(klammer_base.Klammer_base):
|
||||
def __init__(self, K):
|
||||
super().__init__(K)
|
||||
self.items = kutil.rest_args(self.descriptions, 2)
|
||||
#self.show()
|
||||
#pprint.pprint(self.items)
|
||||
|
||||
def html(self):
|
||||
def fontify(s):
|
||||
return {"r" : s,
|
||||
"i" : f"<i>{s}</i>",
|
||||
"b" : f"<b>{s}</b>",
|
||||
"t" : f'<span class="monospace">{s}</span>',
|
||||
"c" : f'<span class="monospace">{s}</span>',
|
||||
"s" : f'<span class="sansserif">{s}</span>'}[self.font]
|
||||
result = "\n\n".join([f"<dt>{fontify(term)}</dt>\n<dd>{definition}</dd>"
|
||||
for term,definition in self.items])
|
||||
result = f"<dl>\n{result}\n</dl>"
|
||||
return result
|
||||
|
||||
def tex(self):
|
||||
def fontify(s):
|
||||
font = {'r' : r'\normalfont',
|
||||
'i' : r'\normalfont\itshape',
|
||||
'b' : r'\normalfont\bfseries',
|
||||
't' : r'\normalfont\ttfamily',
|
||||
'c' : r'\normalfont\ttfamily',
|
||||
's' : r'\normalfont\sffamily'}[self.font]
|
||||
return f"{font} {s}"
|
||||
result = "\n\n".join([f"\\item[{fontify(term)}]\\hfill\n\\newline {definition}"
|
||||
for term,definition in self.items])
|
||||
result = f"\\begin{{description}}[labelindent=12pt,nosep,itemsep=6pt]\n{result}\n\\end{{description}}"
|
||||
return result
|
||||
|
||||
def txt(self):
|
||||
return "TXT DEFINITIONS"
|
||||
|
||||
|
||||
class Lines(klammer_base.Klammer_base):
|
||||
def __init__(self, K):
|
||||
super().__init__(K)
|
||||
|
||||
def html(self):
|
||||
#return " <br>".join(self.s.strip().split("\n"))
|
||||
#return f'<pre style="font-family: var(--serif)">{self.s}</pre>'
|
||||
#return f'<pre>{self.s}</pre>'
|
||||
result = self.s
|
||||
result = re.sub("\n", "<br>\n", result)
|
||||
result = re.sub(" ", "&^#160;", result)
|
||||
return result
|
||||
|
||||
def tex(self):
|
||||
return r"\\\newline\n".join(self.s.strip().split("\n"))
|
||||
|
||||
def txt(self):
|
||||
return self.s.strip()
|
||||
|
||||
|
||||
"""
|
||||
def lines(K):
|
||||
return {'html' : html_lines,
|
||||
'tex' : tex_lines,
|
||||
'pdf' : tex_lines}[K._target](K)
|
||||
|
||||
def tex_lines(K):
|
||||
return " \\\\\n".join(K.s.strip().split("\n"))
|
||||
|
||||
def html_lines(K):
|
||||
return " <br>".join(K.s.strip().split("\n"))
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
def definition_item(K):
|
||||
if K._format == 'html':
|
||||
return '<dt>{}</dt>\n<dd>{}</dd>'.format(
|
||||
format_for_paragraphs(K.term),
|
||||
format_for_paragraphs(K.desc))
|
||||
else:
|
||||
leading = '' if K.inlist else '\\vspace*{-16pt}'
|
||||
return '\\item[{}]\\leavevmode{}\n\n{}'.format(
|
||||
K.term, leading, K.desc)
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
def list(K, list_type):
|
||||
items = kutil.rest_args(K.list_items)
|
||||
return {'html' : html_list,
|
||||
'tex' : tex_list,
|
||||
'pdf' : tex_list}[K._target](K, list_type, items)
|
||||
|
||||
def html_list(K, list_type, items):
|
||||
body = "\n" + "".join([E("li").body(e).str()+"\n" for e in items])
|
||||
result = E(list_type).body(body).str().rstrip()
|
||||
return result
|
||||
|
||||
def tex_list(K, list_type, items):
|
||||
body = "\n\n".join([f"\\item {e}" for e in items])
|
||||
command = {'ol' : 'enumerate', 'ul' : 'itemize'}[list_type]
|
||||
topsep = '[topsep=0pt]'
|
||||
listsep = '\\setlist{nolistsep}' if K.cmp != 'false' else ''
|
||||
result = f'{listsep}\n\\begin{{{command}}}{topsep}\n{body}\n\\end{{{command}}}\n'
|
||||
return result
|
||||
|
||||
def describe(K):
|
||||
items = "\n\n".join(kutil.rest_args(K.descriptions))
|
||||
return {'html' : html_describe,
|
||||
'tex' : tex_describe,
|
||||
'pdf' : tex_describe}[K._target](K, items)
|
||||
|
||||
def html_describe(K, items):
|
||||
return E("dl").body(items).str()
|
||||
|
||||
def tex_describe(K, items):
|
||||
return f'\\begin{{description}}\n{items}\n\\end{{description}}'
|
||||
|
||||
|
||||
def entry(K):
|
||||
return {'html' : html_entry,
|
||||
'tex' : tex_entry,
|
||||
'pdf' : tex_entry}[K._target](K)
|
||||
|
||||
def html_entry(K):
|
||||
#return f'<dt>{K.item}</dt>\n<dd>{K.description}</dd>'
|
||||
return E("dt").body(K.item).str(0) + E("dd").body(K.description).str(0)
|
||||
|
||||
def tex_entry(K):
|
||||
return f'\\item[{K.item}]\n{K.description}\n'
|
||||
|
||||
|
||||
def lines(K):
|
||||
return {'html' : html_lines,
|
||||
'tex' : tex_lines,
|
||||
'pdf' : tex_lines}[K._target](K)
|
||||
|
||||
def tex_lines(K):
|
||||
return " \\\\\n".join(K.s.strip().split("\n"))
|
||||
|
||||
def html_lines(K):
|
||||
return " <br>".join(K.s.strip().split("\n"))
|
||||
|
||||
"""
|
||||
|
||||
|
||||
r"""
|
||||
# List items
|
||||
|
||||
paragraph_separator_re = re.compile('\n *\n', re.S)
|
||||
|
||||
def format_for_paragraphs(s):
|
||||
result = s
|
||||
if len(paragraph_separator_re.findall(result)) > 0:
|
||||
result = '\n\n{}\n\n'.format(result)
|
||||
return result
|
||||
|
||||
def li(K):
|
||||
if K._format == 'html':
|
||||
result = K.s.strip()
|
||||
result = format_for_paragraphs(result)
|
||||
result = '<li>{}</li>'.format(result)
|
||||
else:
|
||||
#result = '\\item{{\\Kinlisttrue {}}} '.format(K.s.strip())
|
||||
#result = '\\item\\begin\\Kinlisttrue {}\\end '.format(K.s.strip())
|
||||
#result = '\\item\\parbox{{\\linewidth}}{{\\Kinlisttrue {}}} '.format(K.s.strip())
|
||||
#result = '\\item\\Kinlisttrue {} '.format(K.s.strip())
|
||||
result = '\\item {} '.format(K.s.strip())
|
||||
|
||||
if K.keep:
|
||||
result = '\\parbox{{\\linewidth}}{{{}}}'.format(result)
|
||||
return result
|
||||
|
||||
def mli(K):
|
||||
result = '@0item {} | @0ulc\n'.format(K.args[0])
|
||||
result += "\n".join(['@0li {} li@'.format(e) for e in K.args[1:]]) + '\n'
|
||||
result += ' ulc@ item@\n'
|
||||
return result
|
||||
|
||||
|
||||
# Ordered and unordered lists:
|
||||
|
||||
def list_html(K, list_type):
|
||||
result = ''
|
||||
if K.list_items[0][0:4] != '<li>':
|
||||
result = "\n".join(['<li>{}</li>'.format(e) for e in K.list_items])
|
||||
else:
|
||||
result = K.list_items[0]
|
||||
tag = 'ol'
|
||||
if list_type == 'ul':
|
||||
tag = 'ul style="list-style-type:{};"'.format(K.bullet)
|
||||
cls = 'compressed' if K.cmp else ''
|
||||
if list_type == 'ul' and K.bullet == 'none':
|
||||
cls += ' nobullet'
|
||||
cls = ' class="{}"'.format(cls.strip())
|
||||
|
||||
result = '<{}{}>\n{}\n</{}>\n'.format(tag, cls, result, list_type)
|
||||
return result
|
||||
|
||||
def list_latex(K, list_type):
|
||||
result = ''
|
||||
first_word = K.list_items[0][:5]
|
||||
if first_word not in {'\\item', '\\parb'}:
|
||||
result = " " + "\n".join(['@0li {} li@'.format(e.strip()) for e in K.list_items])
|
||||
else:
|
||||
result = K.list_items[0]
|
||||
#options = 'nosep,itemsep=1pt,topsep=0pt,partopsep=8pt,parsep=4pt'
|
||||
options = 'nosep,itemsep={}pt'.format(2 if K.cmp else 6)
|
||||
if K.cmp:
|
||||
itemsep=',nosep'
|
||||
else:
|
||||
itemsep=''
|
||||
|
||||
'''
|
||||
if list_type == 'ul' and K.bullet == 'none' and K.indent:
|
||||
left_margin = ',leftmargin=18pt'
|
||||
else:
|
||||
left_margin = ''
|
||||
'''
|
||||
|
||||
left_margin = ''
|
||||
if K.in_define:
|
||||
if list_type == 'ul':
|
||||
left_margin = ',leftmargin=4pt'
|
||||
else:
|
||||
left_margin = ',leftmargin=16pt'
|
||||
|
||||
if K.parsep:
|
||||
parsep = K.parsep
|
||||
else:
|
||||
parsep = 2 if K.cmp else 6
|
||||
|
||||
#options = '[nosep,parsep={}pt{},{}]'.format(parsep, left_margin,itemsep)
|
||||
options = '[parsep={}{}{}]'.format(parsep, left_margin, itemsep)
|
||||
|
||||
'''
|
||||
if K.cmp:
|
||||
options = '[nosep]'
|
||||
else:
|
||||
options = ''
|
||||
'''
|
||||
|
||||
#options = '[itemsep={}]'.format(K.itemsep) if K.itemsep else ''
|
||||
|
||||
#options = '[topsep=0pt,parsep={}pt]'.format(2 if K.cmp else 6)
|
||||
#options = '\\setlength{{\\topsep}{0pt}}\n\\setlength{{\parsep}}{{{}}}\n'.format(
|
||||
bullet = ''
|
||||
if list_type == 'ul' and K.bullet == 'none':
|
||||
bullet = '\\renewcommand\\labelitemi{\\hspace*{-8pt}}'
|
||||
itemsep = '\n\\setlength{{\\itemsep}}{{{}}}\n'.format(K.itemsep) if K.itemsep else ''
|
||||
#result = '''\\listvmargin%
|
||||
result = '''\\begin{{{0}}}{1}{2}
|
||||
{3}
|
||||
{4}
|
||||
\\end{{{0}}}
|
||||
'''.format('itemize' if list_type == 'ul' else 'enumerate',
|
||||
options, itemsep, bullet, result.strip())
|
||||
result = re.compile('\n\n', re.S).sub('\n', result)
|
||||
result = re.compile(r' +\\begin', re.S).sub(r'\\begin', result)
|
||||
if K.uncover:
|
||||
N = 1
|
||||
def replace(match):
|
||||
nonlocal N
|
||||
result = '{}<{}-> '.format(match.group(1), N)
|
||||
N += 1
|
||||
return result
|
||||
result = re.compile(r'(\\item(\[|\s))').sub(replace, result)
|
||||
return result
|
||||
|
||||
#\\listvmargin
|
||||
|
||||
def ul(K):
|
||||
if K._format == 'html':
|
||||
return list_html(K, 'ul')
|
||||
elif K._format == 'latex':
|
||||
return list_latex(K, 'ul')
|
||||
else:
|
||||
util.format_not_defined(K._format, 'ul')
|
||||
|
||||
def ol(K):
|
||||
if K._format == 'html':
|
||||
return list_html(K, 'ol')
|
||||
elif K._format == 'latex':
|
||||
return list_latex(K, 'ol')
|
||||
else:
|
||||
util.format_not_defined(K._format, 'ol')
|
||||
|
||||
# Definitions
|
||||
|
||||
def definition_item(K):
|
||||
if K._format == 'html':
|
||||
return '<dt>{}</dt>\n<dd>{}</dd>'.format(
|
||||
format_for_paragraphs(K.term),
|
||||
format_for_paragraphs(K.desc))
|
||||
else:
|
||||
leading = '' if K.inlist else '\\vspace*{-16pt}'
|
||||
return '\\item[{}]\\leavevmode{}\n\n{}'.format(
|
||||
K.term, leading, K.desc)
|
||||
|
||||
def dfont(K):
|
||||
if K._format == 'latex':
|
||||
result = {'r' : '\\normalfont',
|
||||
'i' : '\\normalfont\\itshape',
|
||||
'b' : '\\normalfont\\bfseries',
|
||||
't' : '\\normalfont\\ttfamily',
|
||||
's' : '\\normalfont\\sffamily\\large'
|
||||
}[K.font]
|
||||
elif K._format == 'html':
|
||||
s = K.term
|
||||
result = {'r' : s,
|
||||
'i' : '<i>{}</i>'.format(s),
|
||||
'b' : '<b>{}</b>'.format(s),
|
||||
't' : '<span class="monospace">{}</span>'.format(s),
|
||||
's' : '<span class="sansserif">{}</span>'.format(s)
|
||||
}[K.font]
|
||||
else:
|
||||
error.Klammertext_error(
|
||||
'There is not defined format named "{}".'.format(K._format))
|
||||
return result
|
||||
|
||||
def escape_code_term(s):
|
||||
def replace(match):
|
||||
left, term, right = match.groups()
|
||||
term = re.sub('\[', r'$\\lbrack$\\,', term)
|
||||
term = re.sub('\]', r'\\,$\\rbrack$', term)
|
||||
#term = re.sub('\[', '\\[', term)
|
||||
#term = re.sub('\]', '\\]', term)
|
||||
term = re.sub('--', '-{}-', term)
|
||||
result = '{}{}{}'.format(left, term, right)
|
||||
return result
|
||||
pat = re.compile(r'(\\item\[)(.*?)(\]\\)', re.S)
|
||||
return pat.sub(replace, s)
|
||||
|
||||
def define(K):
|
||||
if K._format == 'latex':
|
||||
#itemsep=1pt,topsep=2pt,partopsep=8pt,parsep=4pt,%
|
||||
options = 'nosep,parsep=4pt,leftmargin=32pt'
|
||||
fontname = {'r' : '\\normalfont',
|
||||
'i' : '\\normalfont\\itshape',
|
||||
'b' : '\\normalfont\\bfseries',
|
||||
't' : '\\normalfont\\ttfamily',
|
||||
's' : '\\normalfont\\sffamily',
|
||||
'si' : '\\normalfont\\sffamily\\itshape',
|
||||
'sb' : '\\normalfont\\sffamily\\bfseries',
|
||||
'c' : '\\normalfont',
|
||||
}[K.font]
|
||||
term = K.s
|
||||
if K.font == 'c':
|
||||
term = escape_code_term(term)
|
||||
#term = re.compile('item\[(.*?)\]', re.S).sub(r'item[\\verb+\1+]', term)
|
||||
#term = re.compile('
|
||||
return '''
|
||||
\\listvmargin \\begin{{description}}[{},
|
||||
labelindent=16pt,%
|
||||
style=nextline,font={}]
|
||||
%\\raggedright
|
||||
{}
|
||||
\\end{{description}} \\listvmargin\n'''.format(options,fontname, term)
|
||||
|
||||
elif K._format == 'html':
|
||||
term_class = {'r' : 'normal',
|
||||
'i' : 'italic',
|
||||
'b' : 'bold',
|
||||
't' : 'monospace',
|
||||
's' : 'sansserifbody',
|
||||
'si' : 'sansserifitalic',
|
||||
'sb' : 'sansserifbold',
|
||||
'c' : 'normal',
|
||||
}[K.font]
|
||||
term = K.s
|
||||
if K.font == 'c':
|
||||
#term = re.sub('–', '‐'*2, term)
|
||||
term = re.sub('–', '- __UNSPACE__ -', term)
|
||||
body = re.sub('<dt>', '<dt class="{}">'.format(term_class), term)
|
||||
return '''
|
||||
<dl>
|
||||
{}
|
||||
</dl>'''.format(body)
|
||||
"""
|
||||
|
||||
|
||||
def make_column_lists(lst, count):
|
||||
cols = math.ceil(len(lst) / count)
|
||||
result = []
|
||||
for i in range(count):
|
||||
#print(i * cols, (i + 1) * cols)
|
||||
result.append(lst[i * cols : (i+1) * cols])
|
||||
return list(itertools.zip_longest(*result, fillvalue=""))
|
||||
|
||||
def xmake_column_lists(lst, column_count):
|
||||
count = len(lst)
|
||||
row_count = math.ceil(count / column_count)
|
||||
print(count, column_count, row_count)
|
||||
i = 0
|
||||
while i < count:
|
||||
i += 1
|
||||
|
||||
def columns(K):
|
||||
rows = make_column_lists(K.items.split(), K.n)
|
||||
result = "@table\n" # :lines false :header_line false :leading 1.1 :vmargin false |\n"
|
||||
for row in rows:
|
||||
#print("row:", row)
|
||||
result += " | ".join(row) + " ||\n"
|
||||
result += "table@\n"
|
||||
if K.K_target == "latex":
|
||||
result = f"\\vspace*{{-12pt}}\n{result}"
|
||||
return result
|
||||
Reference in New Issue
Block a user