Verbatim-safe typography, ^-punctuation quoting, full-range ^UUUU^, polyglot html
Typographic transforms (---, quote pairs, ~) no longer touch verbatim text: @c/@code/@source_listing content and ^'...'^ spans show exactly the characters written. "^" before any punctuation character quotes it in every target (the apostrophe excepted: ^' opens a literal span), with the new :resolve option on @@@target declaring per-target renderings. The ^UUUU^ code-point form accepts 4-6 hex digits, the full Unicode range. The html output and transform spellings are polyglot (XML-valid), in preparation for an EPUB target. New suites: transform_test, character_test (engine), typography_test (SKS). (from dev 07ce5ea86a0a)
This commit is contained in:
@@ -9,49 +9,77 @@ paragraph pass recognizes as a block and leaves alone, and \par in
|
||||
vertical mode is a no-op.
|
||||
]#
|
||||
|
||||
@@par.k s : A paragraph of text @@
|
||||
# Paragraph
|
||||
|
||||
@@par.k s : A paragraph of text. @@
|
||||
|
||||
@@par.html :: <p>*s*</p> @@
|
||||
@@par.tex ::
|
||||
\par
|
||||
*s*
|
||||
\par
|
||||
@@
|
||||
|
||||
@@par.tex :: \par *s* \par @@
|
||||
|
||||
# In plain text a paragraph is delimited by blank lines, which
|
||||
# phases.justify_blocks then fills; #/2 inserts them without depending on
|
||||
# the definition body's own whitespace surviving extraction.
|
||||
@@par.txt :: #/2*s*#/2 @@
|
||||
|
||||
|
||||
# Non-breaking space
|
||||
|
||||
@@sp.k : Non-breaking space character @@
|
||||
@@sp.html :: &^#160; @@
|
||||
@@sp.tex :: ~ @@
|
||||
|
||||
# TODO: Easy in LaTeX; how to handle in HTML and plain text?
|
||||
# @@footnote.k s : Footnote (TBD) @@
|
||||
# @@footnote :: [*s*] @@
|
||||
# Indented block
|
||||
|
||||
@@indent.k s :w.int 3 :linebreak.bool false : Indented block @@
|
||||
@@indent.k s :left.int 8 :right.int -1 :ragged.bool false :
|
||||
Indented block. The *left* and *right* values are the number of characters for
|
||||
indentation (as roughtly defined by "ex"). By default, *right* is set to the
|
||||
*left* value (with -1 as the sentinel).
|
||||
@@
|
||||
@@indent.html,tex,txt :: @eval block.Indent(K) eval@ @@
|
||||
|
||||
@@quote.k s :w.int 1 :source : Quotation block @@
|
||||
|
||||
@@quote.html ::
|
||||
<div class="quote">
|
||||
# Right justification
|
||||
|
||||
@@right.k s :margin 0 :top_margin 2 : Right-justified text @@
|
||||
|
||||
@@right.html ::
|
||||
<div style="text-align: right; margin: *top_margin*ex *margin*ex 2ex 0;">*s*</div>
|
||||
@@
|
||||
|
||||
@@right.tex ::
|
||||
{\setlength{\topsep}{0pt}\setlength{\partopsep}{0pt}\setlength{\parskip}{*top_margin*ex}
|
||||
\begin{flushright}
|
||||
\raggedleft\rightskip=*margin*ex
|
||||
*s*
|
||||
</div>
|
||||
\end{flushright}}
|
||||
@@
|
||||
|
||||
@@quote.tex ::
|
||||
\quoteblock{*s*}{*source*}
|
||||
@@right.txt ::
|
||||
@eval import textwrap; "\n".join([line.rjust(*Target_txt_width*, "~")
|
||||
for line in textwrap.wrap("""*s*""", *Target_txt_width*)]) @
|
||||
@@
|
||||
|
||||
@@quote.txt ::
|
||||
@eval block.block_indent(K) eval@
|
||||
@@
|
||||
|
||||
@@note.k s :label Note :color 1.0,1.0,0.9 :bordercolor 0.2,0.2,0.2 :level.int 0 :width
|
||||
: Rectangular block for a special note @@
|
||||
# Quote with attribution
|
||||
|
||||
@@note.html,tex :: @eval block.Note(K) eval@ @@
|
||||
@@quote.k text | attribution : A block quote with attribution. @@
|
||||
@@quote.html,tex ::
|
||||
@indent *text* :left 8 @
|
||||
@right *attribution* :margin 8
|
||||
:top_margin @cond @eval "*K_target*" == "html" @ | -1 | 1 cond@ @
|
||||
@@
|
||||
|
||||
|
||||
# Highlighted note in text
|
||||
|
||||
@@note.k s :label Note :color 1.0,1.0,0.9 :border_color 0.2,0.2,0.2 :level.int 0 :width.float 0.5
|
||||
: Rectangular block for an editorial note @@
|
||||
|
||||
@@note.html,tex :: @eval block.Note(K) @ @@
|
||||
|
||||
|
||||
# Center
|
||||
|
||||
@@center.k s : Center text @@
|
||||
|
||||
@@ -62,42 +90,46 @@ vertical mode is a no-op.
|
||||
@@
|
||||
|
||||
@@center.html ::
|
||||
<p>
|
||||
<div class="center">
|
||||
*s*
|
||||
</div>
|
||||
</p>
|
||||
@@
|
||||
|
||||
@@right.k s : Right-justified text @@
|
||||
|
||||
@@right.html ::
|
||||
<b>TBD</b> *s*
|
||||
@@
|
||||
|
||||
@@right.tex ::
|
||||
\begin{flushright}
|
||||
*s*
|
||||
\end{flushright}
|
||||
@@
|
||||
# Newline
|
||||
|
||||
@@nl.k : Newline character @@
|
||||
@@nl.html :: <br> @@
|
||||
@@nl.html :: <br/> @@
|
||||
@@nl.tex :: \newline @@
|
||||
@@nl.txt :: \n @@
|
||||
@@nl.txt :: @eval phases.txt_nl_marker() @ @@
|
||||
|
||||
|
||||
# New page
|
||||
|
||||
@@newpage.k : Start new page @@
|
||||
@@newpage.html :: @@
|
||||
@@newpage.tex :: \newpage @@
|
||||
@@newpage.txt :: @@
|
||||
|
||||
|
||||
# Extend page
|
||||
|
||||
@@extendpage.k linecount : Extenad current page @@
|
||||
@@extendpage.html :: @@
|
||||
@@extendpage.tex :: \enlargethispage{*linecount*\baselineskip} @@
|
||||
@@extendpage.txt :: @@
|
||||
|
||||
|
||||
# Vertical space
|
||||
|
||||
@@vspace.k lines.float : Vertical space, in multiples of the current line height @@
|
||||
@@vspace.tex :: \vspace{*lines*\baselineskip} @@
|
||||
@@vspace.html :: <div style="height: *lines*lh"></div> @@
|
||||
@@vspace.txt :: @eval "__VSPACE__" * round(*lines*) @ @@
|
||||
@@vspace.txt :: @eval phases.txt_vspace_marker() * round(*lines*) @ @@
|
||||
|
||||
# Vertical fill to end of page
|
||||
|
||||
@@vfill.k :
|
||||
Fill the vertical space so that any following text is flush with the bottom
|
||||
@@ -112,6 +144,8 @@ only makes some vertical space. @@
|
||||
@@vfill.txt :: @vspace 3 @ @@
|
||||
|
||||
|
||||
# Questions and answers
|
||||
|
||||
@@qa.k question | answer : Question and answer formatting @@
|
||||
@@qa.html,tex,txt ::
|
||||
@b Q: @ *question*
|
||||
@@ -119,6 +153,9 @@ only makes some vertical space. @@
|
||||
@b A: @ *answer*
|
||||
@@
|
||||
|
||||
|
||||
# Absolute positioning
|
||||
|
||||
@@@argtype coords | x and y coordinates :pattern 'float'\s+'float' @@@
|
||||
|
||||
@@block.k : to.coords | content :width.float .5 :point.coords 0.0 0.0
|
||||
@@ -126,18 +163,51 @@ only makes some vertical space. @@
|
||||
|
||||
@@block.tex :: @eval block.Block(K) eval@ @@
|
||||
|
||||
|
||||
# Preserved line endings
|
||||
|
||||
@@lines.k s : Maintain line breaks @@
|
||||
@@lines.html,tex,txt :: @eval block.Lines(K) eval@ @@
|
||||
|
||||
@@twocolumns.k s : Format *s* in two columns @@
|
||||
@@twocolumns.tex ::
|
||||
\begin{multicols}{2}
|
||||
|
||||
# Multiple columns of text
|
||||
|
||||
@@multicolumn.k s :n 2 :gap 3 : Format *s* in *n* columns (default: 2). The *gap* is in "ex" units. @@
|
||||
|
||||
@@multicolumn.tex ::
|
||||
{\setlength{\columnsep}{*gap*ex}
|
||||
\setlength{\multicolsep}{\parskip}
|
||||
\begin{multicols}{*n*}
|
||||
*s*
|
||||
\end{multicols}
|
||||
\end{multicols}}
|
||||
@@
|
||||
|
||||
@@left_right.k left | right : Text left- and right- justified on one line @@
|
||||
|
||||
@@left_right.tex ::
|
||||
\makebox[\dimexpr\linewidth+\labelindent\relax]{*left*\hfill *right*}
|
||||
@@multicolumn.html ::
|
||||
<p>
|
||||
<div style="column-count: *n*; column-gap: *gap*ex; text-align: justify;">
|
||||
*s*
|
||||
</div>
|
||||
</p>
|
||||
@@
|
||||
|
||||
|
||||
# Text justified left and right on one line
|
||||
|
||||
@@left_right.k parts.rest(2) :
|
||||
Pairs of text left- and right- justified. First, left lines are written with a
|
||||
bar (|) between each line. Then, two bars (||), and the right lines with a bar
|
||||
betwen them.
|
||||
@@
|
||||
|
||||
@@left_right.html,tex :: @eval block.Left_right(K) @ @@
|
||||
|
||||
|
||||
# Footnote
|
||||
|
||||
@@footnote.k s : Footnote @@
|
||||
@@footnote.html :: <kt-footnote>*s*</kt-footnote> @@
|
||||
@@footnote.tex :: \unskip\footnote{*s*} @@
|
||||
@@footnote.txt :: __ #- @eval phases.txt_footnote_marker() @ *s* @eval phases.txt_footnote_marker() @ #- __ @@
|
||||
|
||||
# This doesn't work, either, so it isn't the @eval:
|
||||
# @@footnote.txt :: __ #- marker *s* marker #- __ @@
|
||||
|
||||
@@ -5,72 +5,60 @@ import pprint
|
||||
import klammer_base
|
||||
import kutil
|
||||
import latex_util
|
||||
import html_util
|
||||
from html_util import E
|
||||
import color
|
||||
|
||||
class Indent(klammer_base.Klammer_base):
|
||||
def __init__(self, K):
|
||||
super().__init__(K)
|
||||
self.s = kutil.escape(self.s)
|
||||
# Doesn't do anything now:
|
||||
# self.s = kutil.escape(self.s)
|
||||
if self.right < 0:
|
||||
self.right = self.left
|
||||
self.reduce = self.left + self.right
|
||||
|
||||
def html(self):
|
||||
return "FIX: INDENT " + self.s
|
||||
|
||||
text_align = "justify" if not self.ragged else "left"
|
||||
return E("div").body(self.s)\
|
||||
.sty("margin", f"0.5rem {self.right}ex 0.5rem {self.left}ex")\
|
||||
.sty("text-align", text_align)\
|
||||
.str()
|
||||
def tex(self):
|
||||
tab = f"\\hspace*{{{self.w}ex}}"
|
||||
result = ""
|
||||
|
||||
if self.linebreak:
|
||||
for e in self.s.split("\n"):
|
||||
result += f"{tab}{e}\\\\\n"
|
||||
result = result[:-3]
|
||||
result = re.sub(r"\t", r"\\t", result)
|
||||
else:
|
||||
result = tab + latex_util.minipage(
|
||||
"\\raggedright " + self.s, f"\\textwidth - {self.w}ex", center=False, vmargin="4pt")
|
||||
#print(result)
|
||||
return latex_util.block(result)
|
||||
if self.ragged:
|
||||
self.s = "\\raggedright " + self.s
|
||||
result = rf"\hspace*{{{self.left}ex}}" + latex_util.minipage(
|
||||
self.s, rf"\linewidth - {self.reduce}ex", center=False)
|
||||
result = latex_util.block(result)
|
||||
return result
|
||||
|
||||
def txt(self):
|
||||
indent = " " * self.w
|
||||
indent = "~" * self.left # Removed in phases.justify_blocks
|
||||
width = int(self.Target_txt_width) - self.left - self.right + 1 # Off-by one for textwrap
|
||||
result = self.s
|
||||
result = re.sub("KK0022", '"', result)
|
||||
result = indent + f"\n{indent}".join(textwrap.wrap(result, width=70, break_on_hyphens=False))
|
||||
return f"@lit\n{result}\nlit@"
|
||||
result = indent + f"\n{indent}".join(textwrap.wrap(result, width=width, break_on_hyphens=True))
|
||||
return result
|
||||
|
||||
|
||||
class Note(klammer_base.Klammer_base):
|
||||
def __init__(self, K):
|
||||
super().__init__(K)
|
||||
|
||||
def html(self):
|
||||
color = ",".join([f"{float(e)*100}%" for e in self.color.split(",")])
|
||||
result = f'''<div class="box" style="background-color: rgb({color}); border-color: rgb({self.bordercolor}) ;">
|
||||
<b>{self.label}:</b> {self.s}
|
||||
</div>'''
|
||||
result = E("div").cls("box")\
|
||||
.sty("width", f"{self.width*100}%")\
|
||||
.sty("background-color", html_util.color(self.color))\
|
||||
.sty("border-color", html_util.color(self.border_color))\
|
||||
.sty("margin-left", "auto")\
|
||||
.body(f"<b>{self.label}:</b> {self.s}")\
|
||||
.str()
|
||||
return result
|
||||
|
||||
def tex(self):
|
||||
if self.width:
|
||||
width = r'{}\\textwidth'.format(self.width)
|
||||
else:
|
||||
#width = r'\\textwidth - 16pt - {}\\leftmargin'.format(self.level)
|
||||
width = r'\\linewidth - \\leftmargin + 2pt'
|
||||
|
||||
# The \par on each side comes from latex_util.block() below: an
|
||||
# \fcolorbox is box material and must sit in vertical mode.
|
||||
result = '''
|
||||
\\begingroup
|
||||
COLOR\\setlength{\\fboxsep}{8pt}
|
||||
\\fcolorbox{bordercolor}{localcolor}{
|
||||
\\parbox{WIDTH}{\\raggedright\\setlength{\\parskip}{8pt}
|
||||
\\textbf{LABEL:} TEXT
|
||||
}}\\endgroup
|
||||
'''
|
||||
result = re.sub('LABEL', self.label, result)
|
||||
result = re.sub('TEXT', re.sub(r'\\', r'\\\\', self.s), result)
|
||||
result = re.sub('COLOR', r'\\definecolor{{localcolor}}{{rgb}}{{{}}}\nCOLOR'.format(self.color), result)
|
||||
result = re.sub('COLOR', r'\\definecolor{{bordercolor}}{{rgb}}{{{}}}\n'.format(self.bordercolor), result)
|
||||
result = re.sub('WIDTH', width, result)
|
||||
print(result)
|
||||
return latex_util.block(result)
|
||||
return latex_util.color_box(
|
||||
f"\\textbf{{{self.label}:}} {self.s}",
|
||||
self.width, self.color, self.border_color)
|
||||
|
||||
|
||||
class Block(klammer_base.Klammer_base):
|
||||
@@ -95,13 +83,12 @@ class Block(klammer_base.Klammer_base):
|
||||
class Lines(klammer_base.Klammer_base):
|
||||
def __init__(self, K):
|
||||
super().__init__(K)
|
||||
self.s = kutil.escape(self.s)
|
||||
self.lines = self.s.split("\n")
|
||||
|
||||
def html(self):
|
||||
result = ""
|
||||
for line in self.lines:
|
||||
result += line + "<br>\n"
|
||||
result += line + "<br/>\n"
|
||||
return result
|
||||
|
||||
def tex(self):
|
||||
@@ -109,3 +96,24 @@ class Lines(klammer_base.Klammer_base):
|
||||
|
||||
def txt(self):
|
||||
return self.lines
|
||||
|
||||
class Left_right(klammer_base.Klammer_base):
|
||||
def __init__(self, K):
|
||||
super().__init__(K)
|
||||
self.rows = list(zip(self.parts[0], self.parts[1]))
|
||||
|
||||
def html(self):
|
||||
result = ""
|
||||
for left, right in self.rows:
|
||||
result += E("div").body(
|
||||
E("span").cls("left_right").body(left).str() + \
|
||||
E("span").cls("left_right").sty("text-align", "right").body(right).str()).str();
|
||||
result = E("p").body(result).str()
|
||||
return result
|
||||
|
||||
def tex(self):
|
||||
result = ""
|
||||
for left, right in self.rows:
|
||||
result += rf"\parbox{{\linewidth}}{{{left} \hfill {right}}}" + " \\\\\n"
|
||||
result = result[:-3]
|
||||
return result
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
p {
|
||||
margin: .5rem 0 .5rem 0;
|
||||
margin: 1ex 0;
|
||||
}
|
||||
|
||||
.quote {
|
||||
@@ -15,10 +15,8 @@ p {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.centered {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: fit-content;
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.indent {
|
||||
@@ -49,3 +47,8 @@ p {
|
||||
.vfill {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.left_right {
|
||||
display: inline-block;
|
||||
width: calc((100vw - 60px) / 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user