import re, glob import kutil import font def tex_style(): result = "" for basename, filename in kutil.sks_files_of_type("sty"): with open(filename) as fp: src = fp.read() result += f"% {basename}.sty\n{src.strip()}\n\n" return result # \usepackage{quoting} def block(material): r"""Return tex material as a block: vertical mode on both sides. A block element -- a table, an image, a code listing -- is box material. Appended to a non-empty horizontal list (an @image written after text on the same line, with no blank line between) a box is typeset BESIDE the text rather than below it, and text following it flows to its right. A \par on each side ends the paragraph in progress and starts a new one after. \par in vertical mode is a no-op, so this is safe wherever it is applied: a block klammer needs no knowledge of what preceded it. Every SKS klammer whose tex output is box material returns it through this function. LaTeX ENVIRONMENTS -- center, flushright, quote, itemize, verbatim -- already break the paragraph themselves and do not need it. The paragraph policy this serves: in an @document, paragraphs are made from blank-line-separated text (@par is the explicit form for a fragment rendered without @document), and the author is never required to know that a target distinguishes horizontal from vertical mode. Asserted by sks/tst/paragraph_test.sh. """ return "\\par\n" + material.strip("\n") + "\n\\par\n" def environment(name, body, required=None, optional=None): req = f"{{{required}}}" if required else "" opt = f"[{optional}]" if optional else "" result = f"""\\begin{{{name}}}{opt}{req} {body} \\end{{{name}}} """ return result def page(title, subtitle, leading, pointsize, ragged_right, body): title = f"\\textsf{{\\Large {title}}}" if title else "" subtitle = f"\\vspace*{{4pt}}\\textsf{{\\large {subtitle}}}" if subtitle else "" #leading = f"\\renewcommand{{\\baselinestretch}}{{{leading}}}" leading = f"\\setstretch{{{leading}}}" raggedright = "\\raggedright" if ragged_right else "" if title or subtitle: title = f"\\begin{{center}}{title} \\\\ {subtitle}\\end{{center}}\n\n" result = f"""\\documentclass[a4paper,{pointsize}]{{article}} {tex_style()} {leading} {raggedright} \\begin{{document}} \\thispagestyle{{empty}} """ result += title + body + "\n\\end{document}\n" return result TARGET_ID = 0 #def add_caption(element, label, numbered, caption_text, center, side, width, side_center, vmargin, caption_margin): def minipage(content, width="\\textwidth", vertical="c", center=True, vmargin="", outline=False): vertical = f"[{vertical}]" if vertical else "" center = "\n\\centering" if center else "" vmargin = f"\n\\vspace*{{{vmargin}}}" if vmargin else "" result = f"""\\begin{{minipage}}{vertical}{{{width}}}{center}{vmargin} {content}{vmargin} \\end{{minipage}}""" if outline: result = f"\\fbox{{{result}}}" return result def offset_length(offset): r"""An :offset as a LaTeX length, or "0pt" when there is none.""" if not offset or offset in ("0", "0pt"): return "0pt" return kutil.parse_length("tex", offset, 1)[0] def offset_space(offset): r"""An :offset as an \hspace*, or "" when there is none.""" length = offset_length(offset) return "" if length == "0pt" else f"\\hspace*{{{length}}}" def caption_wrapper(element, hpos, bottom_margin=.67, offset=None): # hpos is left, center, right, none (no wrapper), or a length, which # becomes the left margin. The element is a box on a line inside a # full-width minipage; \hfill on the empty side pushes it into place. # # offset insets the element from the margin hpos names -- from the left # for "left", from the right for "right". A centered element has no # such margin, so the offset is ignored there rather than being an # error: the two arguments are independent, and :hpos is what decides # whether the offset has anything to measure from. (The html # counterpart is html_util.hpos_container.) vmargin = f"{bottom_margin}\\baselineskip" inset = offset_space(offset) if hpos == "center": return minipage(element, vmargin=vmargin) if hpos == "left": return minipage(inset + element + "\\hfill", vmargin=vmargin, center=False) if hpos == "right": return minipage("\\hfill" + element + inset, vmargin=vmargin, center=False) if hpos == "none": return element length, _, _ = kutil.parse_length("tex", hpos, 1) return minipage(f"\\hspace*{{{length}}}" + element + "\\hfill", vmargin=vmargin, center=False) def make_caption_text(number, label, text, font_symbol, font_size): caption = None if number: caption = kutil.caption_marker(label, text) elif text: # caption = text # f"{{\\small \\it \\par {caption_text}}}" caption = text if caption is None: return "" caption = font.tex_fontify(caption, font_symbol, font_size) return caption def add_caption(element, caption_label, number, caption_text, latex_width, hpos="center", side="bottom", font_symbol="i", font_size=.9, offset=None): top_margin = .75 if "includegraphics" in element else .5 caption = make_caption_text(number, caption_label, caption_text, font_symbol, font_size) if caption: if side in {"left", "right"}: caption_margin_size = "12pt" caption_margin = f"\\hspace{{{caption_margin_size}}}" caption_width = f"\\textwidth - {latex_width} - {caption_margin_size}" else: #caption_margin = "\\vspace*{8pt}" # caption_margin = "\\vstrut{.25\\baselineskip}\n" pass if side == "left": element = minipage(minipage(caption, caption_width, center=False) + #, vmargin=top_margin) + caption_margin + minipage(element, latex_width)) elif side == "right": element = minipage(minipage(element, latex_width) + caption_margin + minipage(caption, caption_width, center=False)) elif side == "bottom": element = minipage(element + "\n\\vstrut{1.33\\baselineskip}" + caption, # minipage(element, vertical="t") + # caption_margin + "\n" + # minipage(caption), latex_width, vertical="t") elif side == "top": # A depth strut: the bottom-caption case uses \vstrut (height) # above the caption; a top caption needs the mirror image, # space below its line. element = minipage(caption + "\\rule[-0.75\\baselineskip]{0pt}{0pt}\n" + element, latex_width, vertical="t") return caption_wrapper(element, hpos, offset=offset)