Thursday, March 18, 2010

PDF shorthand


There are periods of time when I have to do a lot of article editing or book writing, and I usually do that in LaTeX. I find that writing dockets in LaTeX helps me focus on the content, maintain coherent style throughout the document, and produce better-looking results... and I lost my patience with office suites in general.

There is however, one thing that annoys me. Since I tend to just use a text editor (vim, or kate, or gedit) I usually need to go into terminal and type in the four commands to compile the document into a pdf:

pdflatex meh.tex && \
bibtex meh && \
pdflatex meh.tex && \
pdflatex meh.tex

And since I'm kinda compulsive I do that kind of often. And when it's not in the history of commands (because e.g., I'd been writing a script during a break in editing) I get annoyed.

So I figured I could do a simple script that would take care of those commands. A simple script that just takes the name of the tex file and returns a pdf. And I did just that.

And then I started fiddling with it and adding silly features: making it quiet, interactive, whatever; and then a getopt interface on top of it all. So it got kind of convoluted by the end. Feature-wise it probably lays smack in the middle between lightweight and feature-rich. I.e., it is slightly too complex but doesn't have the feature you want.

But I still like it.

If you're looking for fun stuff, the usage function is interesting, even if I say so myself. Instead of writing out a sequence of echo commands explaining what the program does, I decided to use the comments I write on the top of the scripts always. So the usage command finds and parses the script file, and then, using awk yanks the large comment, strips it of the hash character in front, and prints it out to the user. It saved time, and I should remember to sue it in the future in this context.

Some examples of usage now. First, make pdf from tex, bibliography and all:

pdfshorthand top.tex

To make it not produce all those pesky temporary documents (ask before removing each file or not):

pdfshorthand -c top.tex
pdfshorthand -cf top.tex

And if you have no bibliography in your docket, you need to use the b flag:

pdfshorthand -b top.tex
pdfshorthand -bc top.tex
pdfshorthand -bcf top.tex

The code:
 
1 #!/bin/bash
2 #
3 # My shorthand for pdflatex
4 #
5 # Because I'm sick and tired of always putting in the same command over and
6 # over again just to compile a file into a PDF. This script does it for me.
7 # It's basically the equivalent for writing:
8 # pdflatex top.tex && bibtex top && pdflatex top.tex && pdflatex top.tex and
9 # then cursing because I'd have much preferred it to halt on error but that is
10 # way too much writing.
11 #
12 # Usage:
13 # shorthand [OPTION ...] FILE [FILE ...]
14 #
15 # The FILE can but doesn't have to end with the extension 'tex'. If it isn't,
16 # one will be added before passing the file to pdflatex; if it is, it will be
17 # removed before passing the file to bibtex.
18 #
19 # Options:
20 # -n|--no-colors Do not use colors in output. Normally, colors are used
21 # for key messages: on success, on failure, and when
22 # compilation starts.
23 #
24 # -b|--no-biblio Do not attempt to generate a bibliography using bibtex.
25 #
26 # -i|--interactive Run pdflatex in interactive mode (halt on error).
27 # Otherwise the compilation is run in non-stop mode.
28 #
29 # -q|--quiet Do not show any output from the command whatsoever.
30 # Else, compilation produces a lot of output (be advised).
31 #
32 # -c|--clean-up Clean up after the compilation - remove aux, blg, bbl,
33 # and log files from the working directory. The files will
34 # be backed up in /tmp/ec.XXX/ just in case though, and
35 # you will be asked before the actual removal of each file
36 # takes place.
37 #
38 # -f|--force When used with -c or --clean-up, the script will not ask
39 # before removing each temporary file from the working
40 # directory.
41 #
42 # -h|--help Print usage information.
43 #
44 # --latex-command Specify a command to run instead of pdflatex. It will be
45 # given some arguments that pdflatex would have been given
46 # i.e., -interaction MODE and -non-stop-mode.
47 #
48 # --bibtex-command Specify a command to run instead of bibtex.
49 #
50 # Example:
51 # shorthand top.tex
52 #
53 # Requires:
54 # pdflatex
55 # bibtex
56 #
57 # Author:
58 # Konrad Siek <konrad.siek@gmail.com>
59 #
60 # License:
61 # Copyright 2010 Konrad Siek
62 #
63 # This program is free software: you can redistribute it and/or modify it
64 # under the terms of the GNU General Public License as published by the Free
65 # Software Foundation, either version 3 of the License, or (at your option)
66 # any later version. See <http://www.gnu.org/licenses/> for details.
67 #
68
69 texcommand=pdflatex # name or path to command
70 bibcommand=bibtex # name or path to command
71 quiet=$false # true or $false
72 interactive=$false # true or $false
73 colors=true # true or $false
74 cleanup=$false # true or $false
75 force=$false # true or $false
76 no_biblio=$false # true or $false
77
78 # Print usage information.
79 usage () {
80 gawk '/^#/ && NR>1 {sub(/^#[ \t]?/,""); print; next} NR>1 {exit}' "$0"
81 }
82
83 # Print stuff to standard error.
84 stderr() {
85 echo $@ &> 2
86 }
87
88 # Parse options.
89 options=$(\
90 getopt \
91 -o ciqnhfb \
92 --long clean-up,interactive,quiet,latex-command:,bibtex-command:,no-colors,force,help,no-biblio \
93 -n $0 -- "$@" \
94 )
95
96 # Stop if there's some sort of problem.
97 if [ $? != 0 ]
98 then
99 [ $quiet ] && syserr "Argh! Parsing went pear-shaped!"
100 exit 1
101 fi
102
103 # Set the parsed command options and work with the settings.
104 eval set -- "$options"
105 while true
106 do
107 case "$1" in
108 --latex-command) texcommand="$2"; shift 2;;
109 --bibtex-command) bibcommand="$2"; shift 2;;
110 -c|--clean-up) cleanup=true; shift;;
111 -n|--no-colors) colors=$false; shift;;
112 -f|--force) force=true; shift;;
113 -i|--interactive) interactive=true; shift;;
114 -q|--quiet) quiet=true; shift;;
115 -h|--help) usage; exit 1;;
116 -b|--no-biblio) no_biblio=true; shift;;
117 --) shift; break;;
118 *) syserr "Ack! She cannae take it anymore, captain!"; exit 3;;
119 esac
120 done
121
122 # Various messages printed out by the script.
123 SUCCESS="Huzzah!"
124 FAIL="Your shipment of fail has arrived."
125 PROCESSING="Processing file <{}>"
126
127 # If no params given, print usage and quit with an error.
128 [ $# -lt '1' ] && (usage; exit 1)
129
130 # Specify the params for pdflatex for whatever level of interactiveness the
131 # user expects. We do this beforehand.
132 if [ $interactive ]
133 then
134 iparams="-interaction errorstopmode -halt-on-error"
135 else
136 iparams="-interaction nonstopmode"
137 fi
138
139 clean_up () {
140 if [ $cleanup ]
141 then
142 dir=`mktemp --tmpdir -d "$1.XXX"` && \
143 for ext in bbl blg log aux out nav snm
144 do
145 f="$1.$ext"; cp -v "$f" "$dir/$f"
146 if [ -f "$f" ]
147 then
148 [ $force ] && rm -vf "$f" || rm -vi "$f"
149 else
150 "Omitting file: $f"
151 fi
152 done
153 cp -v "$1.tex" "$dir/"
154 fi
155 }
156
157 # If the user wants colors, the messages can be prepared beforehand.
158 if [ $colors ]
159 then
160 # Add coloring control characters to the message strings:
161 # success, green; fail, red; processing, white; all bold.
162 SUCCESS="\033[32m\033[1m$SUCCESS\033[m"
163 FAIL="\033[31m\033[1m$FAIL\033[m"
164 PROCESSING="\033[37m\033[1m$PROCESSING\033[m"
165 fi
166
167 # If bibtex is not supposed to be run at all, run the 'true' command instead.
168 # The 'true' command will take whatever parameters and do absolutely nothing,
169 # then it'll report a success. So it fits perfectly with the other commands.
170 if [ $no_biblio ]
171 then
172 bibcommand=true
173 fi
174
175 # The shorthand method for the pdflatex/bibtex combination.
176 shorthand () {
177 # Cut off the extension, if any to create the bibtex argument,
178 dir=`dirname "$1"`
179 base=`basename "$1" .tex`
180 stump="$dir/$base"
181
182 # And now stick the extension back on to create the pdflatex argument.
183 full="$stump.tex"
184
185 # Print out what file is being processed.
186 echo -e ${PROCESSING//\{\}/$full}
187
188 # The pipe, where all the magic happens:
189 $texcommand $iparams "$full" && \
190 $bibcommand "$stump" && \
191 $texcommand $iparams "$full" && \
192 $texcommand $iparams "$full" && \
193 (clean_up "$base"; echo -e $SUCCESS) || echo -e $FAIL
194
195 # Finally print out an information whether the processing was a success or
196 # a failure.
197 }
198
199 # Do the thing.
200 for arg
201 do
202 # If quiet mode is on, send all results to the black hole.
203 [ $quiet ] && shorthand "$arg" 1> /dev/null 2>/dev/null || shorthand "$arg"
204 done


The code is also available at GitHub as bash/pdfshorthand.

No comments: