Scripts for Quick LaTeX, scrot, and GraphViz Processing

Quick \(\LaTeX\) processing

Motivation

As is the case with my \(\LaTeX\) input method script, this script was motivated by the desire to typeset math for use in online discussions1 (held on a platform like Discord or Slack). This script was written after the previously-mentioned Unicode input script after I realized that using Unicode characters in free text was sometimes insufficient for proper math discussion, especially when summations, gratuitous super- or subscripts, and fractions are involved. This script operates like many Discord \(\LaTeX\) bots: it captures input in the form of \(\LaTeX\) source code, compiles it using \(\LaTeX\), converts the output into an image, and gives it to the user for insertion into the discussion. Since, however, this script operates outside of any online discussion platform. it can be used anywhere: places without a \(\LaTeX\) bot, DMs, and other messaging platforms.

Use

To use this script, I write \(\LaTeX\) source code in the composition box of whichever online messaging platform I'm using, select and copy the source code to the clipboard, and type Super+`. This takes the contents of the clipboard, inserts a \(\LaTeX\) document template around it, opens a floating xterm window in which the code is compiled, converts the result to an image, and copies that image to the clipboard. I then paste the image in the message and send it. The terminal window acts as a progress indication; once it closes, the process is complete. If an error occurs, the xterm window stays open with the \(\LaTeX\) log output.

To do this, my window manager i3 is configured to run xterm -class TexifyCont -e texify.zsh whenever Super+~`~ is pressed, and contains the line for_window [class="TexifyCont"] floating enable, which allows the newly-opened terminal to float.

scrot to clipboard

Drawing from the texify.zsh script, which outputs an image of typeset \(\LaTeX\) text to the clipboard, I wrote scr, a similar script that ran scrot, an X11 screenshot tool, and sent its output to the clipboard. Here, scrot is called with -l mode=edge to work around an odd bug that would otherwise occur under certain conditions when taking a screenshot of part of the screen.

Quick GraphViz processing

During Computibility and Complexity class discussions, I frequently needed to write state machine diagrams and present them to classmates. Typically, I would write the diagrams in GraphViz/~dot~ format in a Logseq2 code block. Thus, I wrote dotify.zsh to allow me to copy the contents of that code block, feed it to dot, and display the result (unlike texify.zsh, which copies the result to the clipboard). It's much simpler than texify.zsh, due to the fact that dot is less inclined to throw errors and already outputs image files. I have my window manager configured to launch it when I press Super+Shift+`.

Security considerations

This program accepts and compiles \(\LaTeX\) input without sanitization, modification, sandboxing, or limitation. \(\LaTeX\) is a Turing-complete programming language3 and is capable of reading arbitrary files, executing arbitrary commands (with \write18{xterm}, for example), writing arbitrary files, and doing other things. Thus, this script should never be run on untrusted input, and should never be used as part of an automated system.

Source code

For texify.zsh

There are several things worth noting here: first, signal() uses xgamma to rapidly blink the screen twice to signal to the user that something is happening; it's not useful given that texify.zsh always runs in a terminal now. The interrupt() function is similar, but it does still serve a purpose: if an error occurs, it pauses and waits for the user to press Enter, thus keeping the terminal open. Second, the grab(), putimg(), and putprim() functions allow the user to substitute in their own X11 copy/paste program.

 1#!/usr/bin/env zsh
 2
 3signal()
 4{
 5  if [[ ! tty ]]
 6  then
 7    xgamma -gamma 0.1
 8    sleep 0.1
 9    xgamma -gamma 1
10  fi
11}
12
13#grab()    {xclip -selection CLIPBOARD -o}
14grab()    {xcopy -b -r}
15#putimg()  {xclip -selection CLIPBOARD -t $1}
16putimg()  {nohup xcopy -b -a $1}
17putprim() {xcopy}
18cleanup()
19{
20  cd /
21  rm -r $tmpdir
22}
23
24interrupt()
25{
26  local ep=$?
27  if tty
28  then
29    read a
30  elif [[ -e $1 ]]
31  then
32    xterm -e less $1 &
33  else
34    signal
35    sleep 0.2
36    signal
37    sleep 0.2
38    signal
39    sleep 0.2
40  fi
41  cleanup
42  exit $ep
43}
44
45signal
46tmpdir=$(mktemp -d)
47cd $tmpdir
48grab | putprim
49cat - >textemp.tex <<EOF
50\documentclass{article}
51\pagenumbering{gobble}
52
53$(cat $(dirname $(realpath $0))/../stempl_math.tex)
54
55\begin{document}
56\begin{flushleft}
57$(grab)
58\end{flushleft}
59\end{document}
60EOF
61latex -halt-on-error textemp.tex || interrupt textemp.log
62dvipng -D 300 -T tight --png textemp.dvi || interrupt
63(convert textemp1.png -bordercolor white -border 50 png:- \
64  | putimg image/png) || interrupt
65signal
66cleanup

For stempl_math.tex

 1% Almost always used
 2\usepackage{amsmath,amssymb,pdfsync}
 3
 4% Discretionary
 5\usepackage[normalem]{ulem} % Strikethrough
 6\usepackage{siunitx}\sisetup{per-mode = symbol}
 7\usepackage{mathtools}
 8
 9\newcommand{\Rls}{\mathbb{R}}
10\newcommand{\Int}{\mathbb{Z}}
11\newcommand{\Rxi}{\mathbb{C}}
12\newcommand{\Rat}{\mathbb{Q}}
13\newcommand{\Nat}{\mathbb{N}}
14\newcommand{\rInt}[1]{\Int/#1\Int}
15\newcommand{\rpt}{\mathrm{Re}}
16\newcommand{\ipt}{\mathrm{Im}}
17\newcommand{\setei}[1]{\setcounter{enumi}{#1}\addtocounter{enumi}{-1}}
18
19% Prof Zajj's shortcuts
20%% Old amatrix env't
21%\newenvironment{amatrix}[1]{%
22%  \left(\begin{array}{@{}*{#1}{c}|c@{}}
23%}{%
24%  \end{array}\right)
25%}
26
27%% Generalized amatrix environment: optional argument is number of columns after
28%% pipe (default 1); req'd argument is number of columns before.
29\newenvironment{amatrix}[2][1]{%
30  \left(\begin{array}{@{}*{#2}{c}|*{#1}{c}@{}}
31}{%
32  \end{array}\right)
33}
34
35% System of equations
36\newenvironment{sys}{%
37  \left\{\begin{array}{@{}r@{\ }l}
38}{%
39  \end{array}\right.
40}
41
42\newenvironment{ans}{\medskip \color{black} \paragraph*{\emph{Answer}.}}
43  {\hfill \break  $~\!\!$ \dotfill \medskip }
44
45% Miscellaneous time-saving things
46\newcommand{\uu}{\textbf{u}}
47\newcommand{\vv}{\textbf{v}}
48\newcommand{\ww}{\textbf{w}}
49
50% Compatability additions
51\newcommand{\RR}{\Rls}
52\newcommand{\CC}{\Rxi}

For scr (a ZSH script)

1#!/usr/bin/env zsh
2#putimg() {nohup xcopy -b -a $1}
3putimg() {nohup xclip -selection clipboard -i -t $1}
4scrot -l mode=edge $@ - | putimg image/png

For dotify.zsh

1#!/usr/bin/env zsh
2xclip -o | dot -Gdpi=600 -Tpng | feh -. -g 900x900 --class DotifyRend -

The relevant parts of i3.conf

1for_window [class="TexifyCont"]   floating enable
2for_window [class="FloatingTerm"] floating enable
3for_window [class="DotifyRend"]   floating enable
4for_window [class="DotifyCont"]   floating enable
5
6bindsym $mod+Shift+grave exec --no-startup-id zsh -c 'dotify.zsh'
7bindsym $mod+grave       exec xterm -class TexifyCont -e texify.zsh

1

That I talk about math online with my friends often enough to justify writing this script says a lot about me and my friends. They're great, and quite nerdy.

2

Some day, I will write another post about Logseq and all the things it's done for me. Today is not that day—I have been writing late into the night to take advantage of my sudden motivation to write two write-ups of shell scripts I wrote, but cannot justify spending more extra work and study time sleeping time writing that post.