]> git.scottworley.com Git - paperdoorknob/commitdiff
Learning TeX: Do Layouts with TeX macros
authorScott Worley <scottworley@scottworley.com>
Mon, 1 Jan 2024 06:11:25 +0000 (22:11 -0800)
committerScott Worley <scottworley@scottworley.com>
Mon, 1 Jan 2024 06:22:06 +0000 (22:22 -0800)
This is more elegant and reduces the size of the .tex output by 33%

h/t https://tex.stackexchange.com/a/537222 by Steven B. Segletes
for the \ifnotempty technique

args.py
glowfic.py
paperdoorknob.py
paperdoorknob_test.py
spec.py

diff --git a/args.py b/args.py
index ede847118dd4bfdd5cc7f62843252790fac52405..de6fc01f58d353c26cb245352640a0ad1970cc0b 100644 (file)
--- a/args.py
+++ b/args.py
@@ -16,7 +16,7 @@ from xdg_base_dirs import xdg_cache_home
 
 from domfilter import ApplyDOMFilters, DOMFilters
 from fetch import CachingFetcher
 
 from domfilter import ApplyDOMFilters, DOMFilters
 from fetch import CachingFetcher
-from glowfic import BesideIconLayout, BelowIconLayout, Layout
+from glowfic import BesideIconLayout, BelowIconLayout
 from htmlfilter import ApplyHTMLFilters, HTMLFilters
 from texfilter import ApplyTexFilters, TexFilters
 from images import DiskImageStore
 from htmlfilter import ApplyHTMLFilters, HTMLFilters
 from texfilter import ApplyTexFilters, TexFilters
 from images import DiskImageStore
@@ -87,11 +87,11 @@ See https://faculty.bard.edu/bloch/geometry.pdf for details
 def spec_from_commandline_args() -> Iterator[Spec]:
     args = _command_line_parser().parse_args()
     texifier = PandocTexifier(args.pandoc or 'pandoc')
 def spec_from_commandline_args() -> Iterator[Spec]:
     args = _command_line_parser().parse_args()
     texifier = PandocTexifier(args.pandoc or 'pandoc')
-    layout: Layout
+    layout: bytes
     if args.layout == 'below':
     if args.layout == 'below':
-        layout = BelowIconLayout(texifier)
+        layout = BelowIconLayout
     elif args.layout == 'beside':
     elif args.layout == 'beside':
-        layout = BesideIconLayout(texifier)
+        layout = BesideIconLayout
     else:
         raise ValueError(f'Unknown layout: {args.layout}')
     log = (lambda _: None) if args.quiet else _print_status
     else:
         raise ValueError(f'Unknown layout: {args.layout}')
     log = (lambda _: None) if args.quiet else _print_status
index b7e7ba740b33f82fbebd43ea9c1c4ffa36bc1973..012bd069aca5a3066b443640bc66904d796e44ee 100644 (file)
@@ -5,7 +5,6 @@
 # Free Software Foundation, version 3.
 
 
 # Free Software Foundation, version 3.
 
 
-from abc import ABC, abstractmethod
 from dataclasses import dataclass
 import itertools
 from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
 from dataclasses import dataclass
 import itertools
 from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
@@ -111,36 +110,27 @@ def makeChunk(chunk_dom: Tag, image_store: ImageStore) -> Chunk:
                  content)
 
 
                  content)
 
 
-class Layout(ABC):
+def renderChunk(texifier: Texifier, chunk: Chunk) -> bytes:
+    return b''.join([
+        br'\glowhead{',
+        br'\glowicon{%s}' % chunk.icon.encode('UTF-8') if chunk.icon else b'',
+        b'}{',
+        texifier.texify(chunk.character) if chunk.character else b'',
+        b'}{',
+        texifier.texify(chunk.screen_name) if chunk.screen_name else b'',
+        b'}{',
+        texifier.texify(chunk.author) if chunk.author else b'',
+        b'}',
+        texifier.texify(chunk.content)])
 
 
-    @abstractmethod
-    def renderChunk(self, chunk: Chunk) -> bytes:
-        raise NotImplementedError()
 
 
+ContentOnlyLayout = br'''
+\newcommand{\glowhead}[4]{}
+'''
 
 
-class ContentOnlyLayout(Layout):
 
 
-    def __init__(self, texifier: Texifier) -> None:
-        self._texifier = texifier
-
-    def renderChunk(self, chunk: Chunk) -> bytes:
-        return self._texifier.texify(chunk.content) + b'\n'
-
-
-class BelowIconLayout(Layout):
-
-    def __init__(self, texifier: Texifier) -> None:
-        self._texifier = texifier
-
-    def renderChunk(self, chunk: Chunk) -> bytes:
-        meta = []
-        if chunk.icon:
-            meta += [br'\glowicon{%s}' % chunk.icon.encode('UTF-8')]
-        meta += [self._texifier.texify(x)
-                 for x in [chunk.character, chunk.screen_name, chunk.author]
-                 if x is not None]
-
-        return br'''\wrapstuffclear
+BelowIconLayout = br'''
+\newcommand{\glowhead}[4]{\wrapstuffclear
 \begin{wrapstuff}[l]
 \fbox{
 \begin{varwidth}{0.5\textwidth}
 \begin{wrapstuff}[l]
 \fbox{
 \begin{varwidth}{0.5\textwidth}
@@ -152,7 +142,10 @@ class BelowIconLayout(Layout):
   }\\*}
   \vspace{-1em}
 \begin{center}
   }\\*}
   \vspace{-1em}
 \begin{center}
-%s
+#1\ifnotempty
+{#1}{\\*}#2\ifnotempty
+{#2}{\\*}#3\ifnotempty
+{#3}{\\*}#4
 \end{center}
 \end{varwidth}
 }
 \end{center}
 \end{varwidth}
 }
@@ -160,40 +153,25 @@ class BelowIconLayout(Layout):
 
 \strut
 
 
 \strut
 
-\noindent %s
-''' % (
-            br'\\*'.join(meta),
-            self._texifier.texify(chunk.content))
+\noindent}'''
 
 
 
 
-class BesideIconLayout(Layout):
+# Why is \textwidth not the width of the text?
+# Why is the width of the text .765\textwidth?
+BesideIconLayout = br'''
+\newcommand{\glowhead}[4]{
 
 
-    def __init__(self, texifier: Texifier) -> None:
-        self._texifier = texifier
-
-    def renderChunk(self, chunk: Chunk) -> bytes:
-        meta = [
-            chunk.character,
-            chunk.screen_name,
-            chunk.author,
-        ]
+\strut
 
 
-        # Why is \textwidth not the width of the text?
-        # Why is the width of the text .765\textwidth?
-        return br'''\noindent\fbox{
-%s
+\noindent\fbox{
+#1
 \parbox[b]{.765\textwidth}{
 \begin{center}
 \parbox[b]{.765\textwidth}{
 \begin{center}
-%s
+#2\ifnotempty
+{#2}{\\*}#3\ifnotempty
+{#3}{\\*}#4
 \end{center}
 }
 }\\*
 \vspace{-0.75em}\\*
 \end{center}
 }
 }\\*
 \vspace{-0.75em}\\*
-\noindent %s
-
-\strut
-
-''' % (
-            br'\glowicon{%s}' % chunk.icon.encode('UTF-8') if chunk.icon else b'',
-            br'\\*'.join(self._texifier.texify(x) for x in meta if x is not None),
-            self._texifier.texify(chunk.content))
+\noindent}'''
index 0fb3fe18c1f5c8c34e9cf8ace6052b15a030995e..86b8766e659601b6d05a1c2dcd28e6c7f2fbb868 100644 (file)
@@ -9,7 +9,7 @@ from typing import Any, Iterable
 from bs4 import BeautifulSoup
 
 from args import spec_from_commandline_args
 from bs4 import BeautifulSoup
 
 from args import spec_from_commandline_args
-from glowfic import chunkDOMs, flatURL, makeChunk
+from glowfic import chunkDOMs, flatURL, makeChunk, renderChunk
 from spec import Spec
 
 
 from spec import Spec
 
 
@@ -40,7 +40,10 @@ def process(spec: Spec) -> None:
 \newcommand{\glowicon}[1]{\includegraphics[
   width=\glowiconsize,height=\glowiconsize,keepaspectratio
 ]{#1}}
 \newcommand{\glowicon}[1]{\includegraphics[
   width=\glowiconsize,height=\glowiconsize,keepaspectratio
 ]{#1}}
-''' % spec.icon_size)
+\newcommand{\ifnotempty}[2]{\expandafter\ifx\expandafter\relax
+  \detokenize{#1}\relax\else #2\fi}
+%s
+''' % (spec.icon_size, spec.layout))
     url = flatURL(spec.url)
     spec.log('Fetching HTML...\r')
     html = spec.fetcher.fetch(url)
     url = flatURL(spec.url)
     spec.log('Fetching HTML...\r')
     html = spec.fetcher.fetch(url)
@@ -53,7 +56,7 @@ def process(spec: Spec) -> None:
         spec.log(f'Processing chunk {i} of {num_chunks} ({percent:.1f}%)\r')
         spec.domfilter(r)
         chunk = makeChunk(r, spec.images)
         spec.log(f'Processing chunk {i} of {num_chunks} ({percent:.1f}%)\r')
         spec.domfilter(r)
         chunk = makeChunk(r, spec.images)
-        spec.texout.write(spec.texfilter(spec.layout.renderChunk(chunk)))
+        spec.texout.write(spec.texfilter(renderChunk(spec.texifier, chunk)))
     spec.log('')
     spec.texout.write(b'\\end{document}\n')
 
     spec.log('')
     spec.texout.write(b'\\end{document}\n')
 
index 28408d6138003d0ce616bc0e034cb9f9d52a250f..f2cd5f1115e21576d9f771eacfd03d130b93082d 100644 (file)
@@ -45,7 +45,7 @@ class BaseTestProcess(ABC):
             texifier,
             lambda x: x,
             20,
             texifier,
             lambda x: x,
             20,
-            ContentOnlyLayout(texifier),
+            ContentOnlyLayout,
             'margin=20mm',
             buf,
             lambda _: None)
             'margin=20mm',
             buf,
             lambda _: None)
@@ -54,12 +54,9 @@ class BaseTestProcess(ABC):
 (\\usepackage{[a-z]+}\n)+\\usepackage\[margin=20mm\]{geometry}
 \\begin{document}
 (.|\n)*
 (\\usepackage{[a-z]+}\n)+\\usepackage\[margin=20mm\]{geometry}
 \\begin{document}
 (.|\n)*
-This is \\href{https://glowfic.com}{glowfic}
-
-You \\emph{sure}\?
-
-Pretty sure.
-
+\\glowhead{}{}{}{}This is \\href{https://glowfic.com}{glowfic}
+\\glowhead{}{}{}{}You \\emph{sure}\?
+\\glowhead{}{}{}{}Pretty sure.
 \\end{document}
 ''', buf.getvalue())
 
 \\end{document}
 ''', buf.getvalue())
 
@@ -76,7 +73,7 @@ Pretty sure.
             texifier,
             lambda x: x,
             20,
             texifier,
             lambda x: x,
             20,
-            ContentOnlyLayout(texifier),
+            ContentOnlyLayout,
             None,
             buf,
             lambda _: None)
             None,
             buf,
             lambda _: None)
@@ -94,7 +91,7 @@ Pretty sure.
                 texifier,
                 lambda x: x,
                 20,
                 texifier,
                 lambda x: x,
                 20,
-                BesideIconLayout(texifier),
+                BesideIconLayout,
                 None,
                 out,
                 lambda _: None)
                 None,
                 out,
                 lambda _: None)
diff --git a/spec.py b/spec.py
index 3aa72920843103c737aa9c93982d8fabde74837c..5d708e2fd0ee7bf72ba484beca0f3bef9a044b67 100644 (file)
--- a/spec.py
+++ b/spec.py
@@ -12,7 +12,6 @@ from typing import Callable, IO
 from bs4.element import Tag
 
 from fetch import Fetcher
 from bs4.element import Tag
 
 from fetch import Fetcher
-from glowfic import Layout
 from images import ImageStore
 from texify import Texifier
 
 from images import ImageStore
 from texify import Texifier
 
@@ -28,7 +27,7 @@ class Spec:
     texifier: Texifier
     texfilter: Callable[[bytes], bytes]
     icon_size: float
     texifier: Texifier
     texfilter: Callable[[bytes], bytes]
     icon_size: float
-    layout: Layout
+    layout: bytes
     geometry: str | None
     texout: IO[bytes]
     log: Callable[[str], None]
     geometry: str | None
     texout: IO[bytes]
     log: Callable[[str], None]