diff options
Diffstat (limited to 'support/latex_maker/mk')
-rwxr-xr-x | support/latex_maker/mk | 1043 |
1 files changed, 1043 insertions, 0 deletions
diff --git a/support/latex_maker/mk b/support/latex_maker/mk new file mode 100755 index 0000000000..61d108f8c8 --- /dev/null +++ b/support/latex_maker/mk @@ -0,0 +1,1043 @@ +#!/bin/bash +# set -o nounset + Version=3.07 + Myname="${0##*/}" + +<<'DOC' += mk - a TeX and LaTeX maker + += Synopsis +mk [options] [file] + +== General options: +-h,--help print this help and exit +-H,--Help print full documentation via less and exit +-V,--version print version and exit +-v,--verbose be verbose + --noverbose be quiet (this is the default) +-r,--rc use STRING as an rc file, instead of |~/.mkrc|. + See the section /RC file and customization/ for more information. + --norc don´t read the |~/.mkrc| file + +== mk-specific options: +-f,--formatter=STRING Use STRING as the formatter: tex, latex, pdflatex, et cetera +-e,--edit=STRING use STRING as the file to be edited; by default, the file containing the + compilation error is presented for editing, or, if there are no errors, + the main source file. +-C,--Clean Remove all files generated by the compilation +-c,--clean Same, except for the pdf or postscript files + +== vpp-related options: +-b,--batch=STRING run in batch using STRING as a printing command for vpp. See the section + /Running in batch mode/ for more information. +-p,--printer=STRING print to printer named STRING + --view view the document after compilation + --noview do not view + --print offer printing interaction after viewing + --noprint do not offer printing interaction + +texlog_extract related options: +-w,--web web colouring instead of ANSI +-n,--nocolor no colouring instead of ANSI + +== Defaults: + --print --view --noverbose main + +Arguments for short options are given without a separator, so you can write +either |--rc=myrc| or |-rmyrc|. + += Description +mk is a Bash script that, in close collaboration with vpp (short for +View and Print PDF/PostScript), is helpful in the cyclic process of +editing, compiling, viewing, and printing a tex document. Essentially, +mk uses texi2dvi for compilation, vpp for viewing and printing. Any +TeX formatter can be handled, with the exception of those starting +with |ht| (such as httex and htlatex) and context (handle those with +texexec). + +Having an existing TeX document, say |main.tex| (see the section +/Locating the source/ for the creation of new documents and for other +extensions than |.tex|), you run mk by typing: + + $ mk main + +or, since /main/ happens to be mk´s default filename: + + $ mk + +Now, if |main.tex| is a valid TeX source, mk compiles it, including +any table of contents, indices, bibliography references, included +files, and so on, and /vpp/ takes over and displays the resulting +/PDF/ or /PostScript/ output. When you leave the viewer you will see a +prompt: + + vpp command (h for help): + +If you are satisfied with the displayed output, you can now decide to +print all or part of your document (see the section /Page selection/), +or you can simply quit by typing 'q'. On the other hand, if you decide +that you want to change the source and have another try, you can edit +the source by typing 'e' to get back to mk and (re)edit your source. +After saving your work and leaving your editor, another compilation +and display cycle will be performed, based on the new source. + +Essentially, mk uses /texi2dvi/ for compilation. /texi2dvi/ always +runs TeX at least once, even though this may be unnecessary. +Therefore, TeX will be run with the |--recorder| option, which reports +all the target´s dependencies in a |.fls| file. In every cycle, mk +analyzes the |.fls| and the tex and bibtex |.log| files to see if a +compilation is needed. When errors have occurred, mk uses the log +files to find out which file has to be edited, and at which line. This +can also be a file read with |\input|, a style file, or any other file on +which the target depends. However, files in the TEXMFMAIN tree are +excluded. + += Editor + +vpp uses the contents of environment variable EDITOR to find your +editor. If that variable is empty, /vim/ is used. Note that your +editor should not fork off your shell, so if you specify /gvim/, for +example, specify it with the option |--nofork|. + += Page selection + +As said in the introduction, after a successful compilation and +display of the resulting /PDF/ or /PostScript/ output, the user is +prompted with: + + vpp command (h for help): + +on typing 'h' /vpp/ displays examples of possible commands: + + Examples of print commands: + 5 to print page 5 + 5- to print pages 5 through the end + 5-7 to print pages 5, 6 and 7 + -7 to print the first 7 pages + 5-7,19- to print pages 5, 6, 7 and 19 through the end + a to print the whole document + - to print the whole document + a x3 to print 3 copies of the document + x3 the same + 5 x3 to print 3 copies of page 5 + t print the whole document two sided + t 2- print two sided starting at page 2 + b to print the whole document as an a5 size booklet + b -12 to print the first 12 pages as an a5 size booklet + Other commands: + e (if called by mk) edit the tex source and rerun mk + c (if called by mk) rerun mk + v (re)view the ps/pdf file + oxyz send pdf output to file xyz.pdf instead of printer + pxyz print to printer xyz + h display this help + ? display this help + q quit + +With these examples, no further explanation should be necessary, except that, +when two sided (|t|) or booklet (|b|) printing is selected for a single-sided +printer, printing will be performed in two shifts, one for the front side and +one for the backside. Between the shifts, another prompt appears: + + printer ready? then turn stack and type return + +You will have to arrange your printer such that, with the printed sides up, the +first page printed will be at the bottom of the stack, and the last page +printed will be on top. Normally you will then have your output come out the +back of your printer. 'Turn the stack' then means: rotate it over the long side +of the paper and feed it back into the printer for the other side to be +printed. + +For further information on /vpp/, look in its manpage by typing + + $ vpp --help + +or read the /vpp/ documentation. + += Locating the source + +mk locates the LaTeX source in several steps: (here the source +extension |.tex| is supposed, but |.ltx|, |.drv| and |.dtx| will also +be tried) + +- If you supply no arguments, the file |main.tex| in the current directory + is assumed. +- If you supply an argument (say /myfile/), mk adds a |.tex| extension if + it isn´t there and looks for |myfile.tex| in the current directory. +- If |myfile.tex| is not found in the current directory, mk looks in the + 'alternate directory' (say |/Docs|) if you have defined one (see the + section 'RC files'). +- If the source was not found in |/Docs|, mk thinks that you may have a + subdirectory /myfile/ in |/Docs| where the source may live under the name + |main.tex| +- If that file is not there, mk now concludes that the source does not + yet exist and reports this, telling at the same time which files have + been tried. +- Finally, if all the above did not lead to a source file, mk dies. + += The TeX formatter to be used + +mk determines the TeX formatter needed to compile the source as follows: +- if the |--formatter| option was used, its argument will be used; +- if the first line of the source starts with |%!|, the rest of that line + specifies the formatter; for example: + + %!xelatex + +- if the |--formatter| option was not used and the first line does not + start with |%!|, mk looks for a |\usepackage{fontspec}| or + |\RequirePackage{fontspec}| and, if found, uses /lualatex/. Those calls + may have options, but they must be on the same line. +- if still no decision could be made, mk looks for |\documentclass| and + chooses /pdflatex/; +- finally, if no match was found, /pdftex/ is assumed. += Running in batch mode + +If you don´t need to edit the source and to view the output, but just want +to compile and maybe print the result, the |--batch| option is useful. + +The |--batch=command| option prevents mk display the output and to +interrogate the user about pages to be printed. Instead the document is +printed according to the mandatory /command/, which mus be quoted if it +contains spaces. Thus the command + + mk --batch='2-3 x3' test + +prints 3 copies of pages 2 and 3 of |test.tex|, without viewing. If you +just want to compile without printing anything, use the |q| command: + + mk --batch=q test + +or + + mk -bq test + += RC file and customization + +Unless the option |--norc| has been used, the file |~/.mkrc| will be +sourced, if it exists, before reading the command line options. + +You can use this rc file to set the default values for the options, by +setting the global shell variable named after the long version of the +options. For example: + + verbose=true # run in verbose mode + +So if you usually like mk to work in verbose mode, you can indicate so in +your rc file and change your mind in some cases by using the |--noverbose| +option. + +Other variables, not having a corresponding command line option, that can +be set in the rc files, and their default values, are: + +EDITOR= + + sets your editor; You can also set your EDITOR in your system startup + files. Note that your editor should not fork; so if you set it to gvim, do: + + EDITOR='gvim --nofork' + +extraoptions= + + adds one or more extra options to the /tex/ (/latex, xelatex/ et + cetera) command. Example: |extraoptions='-shell-escape -quiet'| + +othercleans= + + can be set to a file regular expression; in the cleaning operation, + caused by the |--clean| option, this variable will be eval'ed, and + the resulting files will be removed. This is useful, for example, + when the |gnuplottex| package is used; this package generates + intermediate files named |$base-gnuplottex-fig*|, where the + variable |$base| contains the basename (without extension) of your + tex source file. So after adding: + + othercleans='$base-gnuplottex-fig*' + + to your |./mkrc| file, the cleaning operation will get rid of these + files, too. + +texi2dviquiet=false + + Normally, in verbose mode, you also see the complete tex log + output, because texi2dvi will be verbose, too. This obscures most + other output. You can keep texi2dvi quiet in verbose mode by + setting this variable to true: + + texi2dviquiet=true + +skip_pattern= + + can be set to a file wild card pattern. Files matching this pattern + on which the /(la)tex/ source file may depend will not be checked + for changes. For example, if you use a write-protected TeX-tree in + the directory mytextree it makes sense to set + |skip_pattern=mytextree| unless you set |skip_pattern| explicitly, + it will be set to match the TEXMFMAIN tree. + +altdir= + + If |altdir| is non-empty and a file to be compiled does not exist + in the current directory, it will be given another try after + prefixing it with the contents of |altdir|. So if you like to have + your LaTeX file in + |/Docs/myfile.tex| you can set |altdir| to |/Docs| and run + mk from any directory with: + + $ mk myfile + + However, a directory like |/Docs| does not make much sense if many + of your LaTeX documents do not consist of a single file, but are + constituted of an ensemble of a main LaTeX source and one or more + files read with |\include| or with |\input| such as graphics. + You will then probably prefer to have a subdirectory in |/Docs| for + every LaTeX document. Therefore, if mk does not find |myfile.tex| in the + alternate directory, it will assume that /myfile/ is a subdirectory with + a main LaTeX source in it, called |main.tex|. + +default=main + + This is the default for the base name of your LaTeX document. + +warnings_to_skip=() + + Warnings appearing in the log file will be reported after a + successful run. Warnings matching any of the regular expressions + in this array will be skipped, however. For example, one could + enter here: + + warnings_to_skip=( + 'Package hyperref Warning: Token not allowed in a PDFDocEncoded string' + 'Package array Warning: Column [XY] is already defined on ' + ) + + The first message appears when the /hyperref/ package is used and + section titles contain LaTeX-commands, the second message appears + when the /ctable/ package is used, because it intentionally changes + the X and Y column specifiers. + += TeXWorks and mk + +mk can be used for one-click typesetting: + +- edit -> preferences -> Typesetting +- add a new tool |mk| and give it three parameters: + --noview + --noprint + $basename +- Deselect "Auto-hide output panel unless errors occur" +- If you need an other formatter than the default, pdflatex, use the + |%!| line in your source, or define separate tools in TeXWorks with + an extra |--formatter=...| parameter. + +mk runs pdflatex with the |--synctex=1| option, so you will be +able to jump between source and pdf-ouput. + += Bugs +If, during the compile-edit-cycle, the |%!| line is changed, mk should +respond to it by changing the formatter. + +Currently, mk is only available for Linux. It depends on /texi2dvi/. Spaces +in the basename of TeX sources are not allowed (neither does the texi2dvi +script on which mk is based.) + +Required other programs: +vpp >= 3.07 [CTAN](ctan.org/tex-archive/support/view_print_ps_pdf/vpp) +texi2dvi >= 6290 [Texinfo](ftp.gnu.org/gnu/texinfo/texi2dvi) +tex and friends CTAN or /texlive/ package +kpsewhich from texlive +texi2dvi version 1.152 or greater, from texinfo +readlink from coreutils +getopt from util-linux + += Changes +Changes with respect to version 3.06: +- Option --doublesided removed; vpp does not need them anymore + + += Author +[Wybo Dekker](wybo@dekkerdocumenten.nl) + += Copyright +Released under the [GNU General Public License](www.gnu.org/copyleft/gpl.html) +DOC + +# globals: + +# env vars: EDITOR HOME PWD IFS + +# possibly set in rc file, but never here - prevent shellcheck +# issuing warning: +extraoptions='' othercleans='' +export extraoptions othercleans + + Err='\e[31;1m' # ] light red + Fil='\e[33m' # ] brown + Com='\e[34;1m' # ] light blue + Lin='\e[32;1m' # ] light green + War='\e[35;1m' # ] light magenta + Nor='\e[0m' # ] reset color + + altdir=. + base='' + batch='' + bibdeps= + Clean=false + clean=false + cleanext=( 4ct 4dx 4ix 4tc aux bbl blg chk dvi dvi + ent fls glg glo gls hd idv idx ilg ind ist lg + lof log lot out soc synctex.gz tmp toc tui tuo xdv xdy xref) + compileexit=98 + default=main + dir='' + dvips=dvips + edit='' + editexit=99 + ext='' + formatter='' + print=true + printer='' + pwd=$(pwd) + rc='' + skip_pattern=^$(kpsewhich --expand-var \$TEXMFMAIN) + target='' + targetext=pdf + texcommand='' + texdeps=() + texi2dviquiet=false + verbose=false + view=true + vpptargetext=pdf +warnings_to_skip=() + + die() { echo -e "$Myname: $Err${*}$Nor"; exit 1; } 1>&2 + Warn() { echo -e "$Myname: $War${*}$Nor"; } 1>&2 + warn() { $verbose && Warn "$@"; } +helpsrt() { sed -n '/^= Synopsis/,/^= /p' "$0"|sed '1s/.*/Usage:/;/^= /d'; exit; } +helpall() { sed -n '/^<<.DOC.$/,/^DOC$/p' "$0"|sed -n '1d;$d;p'|less; exit; } +install() { which instscript>&/dev/null && instscript --zip --pdf --markdown "$Myname"; exit; } + +<<'DOC' #------ function findsource -------------------------------------------- += findsource +parameters the script´s first and only argument, maybe nil +description find the file to be compiled. If the argument has no extension, + look for tex, ltx, drv, dtx, in that order. + If the argument is nil, look for main + If the argument is xxx, look for xxx or xxx/main, in that order, + in the current or the alternate directory. + If the argument is xxx.ext, look for xxx.ext in the current or + in the alternate directory. +globals set: base dir ext +globals used: IFS PWD altdir Nor +returns: 0 on succes, 1 otherwise +DOC +#------------------------------------------------------------------------------- +findsource() { + local tries fullpath arg + arg="${1%.}" # remove final . (may be there by auto completion) + [[ $arg =~ \ ]] && + die "mk cannot (yet) handle filenames with spaces, because texi2dvi can´t" + if [[ -z $arg ]]; then # nil argument + tries=(./"$default".{tex,ltx,drv,dtx}) + elif [[ ! $arg =~ [/.] ]]; then # argument has no path and no extension + tries=({.,"$altdir"}/{"$arg","$arg"/"$default"}.{tex,ltx,drv,dtx}) + elif [[ $arg =~ \.(tex|ltx|drv|dtx)$ ]]; then # argument has valid extension + tries=("$arg") + else # try valid extensions + tries=("$arg".{tex,ltx,drv,dtx}) + fi + for i in "${tries[@]}"; do + [[ -s "$i" ]] && { + fullpath=$(readlink -f "$i") + warn "source: $fullpath" + dir="${fullpath%/*}" + ext="${fullpath##*.}" + base="${fullpath:${#dir}+1:${#fullpath}-${#ext}-${#dir}-2}" + return + } + done + die "not found after trying:$Nor\n$(printf "%s\n" "${tries[*]}")" +} + +<<'DOC' #------ function run --------------------------------------------------- += run +parameters: command to be run, with its parameters +description: Run a command; show what´s run if |$verbose|. + If the command exits with 1, that´s considered an error, + other values have a special meaning and are supposed to be a + success +globals set: +globals used: Com Err Lin Nor +returns: the exit value of the command +DOC +#------------------------------------------------------------------------------- +run() { + eval "$@" + local ev=$? + if [ $ev -eq 0 ]; then + warn "$Nor${Fil}sys call: $Com$1$Lin - succeeded$Nor, exit status=$Err$ev" + else + warn "$Nor${Fil}sys call: $Com$1$Err - failed" + fi + return $ev +} + +<<'DOC' #------ function settexdeps -------------------------------------------- += settexdeps +parameters: - +description: Scans |$base.fls| for tex dependencies and places those in the + array texdeps. Any dependencies with future timestamps are + touched in order to prevent mk from looping. +globals set: texdeps +globals used: base PWD skip_pattern +returns: 0 +DOC +#------------------------------------------------------------------------------- +settexdeps() { + texdeps=() + local fls="$base.fls" n=0 c f tmp + test -e "$fls" || { + warn "no file $fls in $PWD" + return + } + while IFS=' ' read -r c f; do + let n++ + [[ $n == 1 && $c != PWD ]] && die "$fls is not a TeX fls file" + [[ $c == INPUT && ! $f =~ $skip_pattern ]] && texdeps+=($f) + done <"$fls" + texdeps=($(echo "${texdeps[@]}"|xargs -n1|sed 's/^\.\///'|sort -u)) + + tmp=$(mktemp -t mk.XXXXXXXXXX) + warn "tex dependencies:" + for i in "${texdeps[@]}"; do + warn " $i" + if [[ $i -nt $tmp ]]; then + Warn "Touching file with future filestamp: $i" + touch "$i" + fi + done + rm "$tmp" +} + +<<'DOC' #------ function setbibdeps -------------------------------------------- += setbibdeps +parameters: - +description: Scan aux file (|$base.aux|) for bib-files needed and places those + in the array bibdeps. Any dependencies with future timestamps are + touched in order to prevent mk from looping. +globals set: bibdeps +globals used: base +returns: - +DOC +#------------------------------------------------------------------------------- +setbibdeps() { + local i tmp + test -e "$base.aux" || return + bibdeps=$(sed -n ' + /\\bibdata{.*}/{ + s/.*\\bibdata{\(.*\)}.*/\1/ # a.bib,b,c.bib + s/\.bib//g # a,b,c + s/,/ /g # a b c + p + }' "$base.aux") + bibdeps=($bibdeps) + [[ ${#bibdeps[@]} -gt 0 ]] || return + + for i in "${!bibdeps[@]}"; do + local b=${bibdeps[i]} + # replace each bib with its full path found by kpsewhich + bibdeps[i]=$(kpsewhich "$b.bib") || die "bib file $b.bib not found" + done + bibdeps=($(echo "${bibdeps[@]}"|xargs -n1|sed 's/^\.\///'|sort -u)) + + tmp=$(mktemp -t mk.XXXXXXXXXXe) + warn "bib dependencies:" + for i in "${bibdeps[@]}"; do + warn " $i" + if [[ $i -nt $tmp ]]; then + Warn "Touching file with future filestamp: $i" + touch "$i" + fi + done + rm "$tmp" +} + +<<'DOC' #------ function compile -------------------------------------------- += compile +parameters: - +description: runs the command in |texcommand| +globals set: - +globals used: base bibdeps target texcommand texdeps +returns: 0 on success, else 1 +DOC +#------------------------------------------------------------------------------- +compile() { + local i go + # If there is an .fls file, and the target is there, then compile only if + # there are texdeps or bibdeps that are newer than target. + # If there are bibdeps newer than target, remove .bbl, forcing texi2dvi to run bibtex + # Returns true if a compilation was actually performed. + go=true + if [[ -e $base.fls && -e $target ]]; then + go=false + setbibdeps + settexdeps + for i in "${bibdeps[@]}"; do + if [ "$i" -nt "$target" ]; then + rm -f "$base.bbl" + warn "newer than target: $i" + go=true + break + fi + done + if ! $go; then + for i in "${texdeps[@]}"; do + if [ "$i" -nt "$target" ]; then + warn "newer than target: $i" + go=true + break + fi + done + fi + fi + if $go; then + rm -f "$target" # if compilation generates no output, we want to be able to detect that + run "$texcommand" || return 1 + # texi2dvi claims to be successful if it produces no output: + if [ -e "$target" ]; then + test "$targetext" = dvi && $dvips "$target" + return 0 + else + Warn "After compilation, $target was not found;" + Warn "were there any output generating statements in your source?" + return 1 + fi + else + warn "No compilation needed" + return 0 + fi +} + +<<'DOC' #------ function show_error_and_edit ----------------------------------- += show_error_and_edit +parameters: - +description: Show compilation errors via texlog_extract and (unless edit is empty) + edit the source file where the error is in, opening the editor at the line + where the error is.. +globals set: IFS +globals used: Lin base bibdeps edit target warnings_to_skip +returns: 0 +DOC +#------------------------------------------------------------------------------- +show_error_and_edit() { + local e m n i errorfile linenum ifsold=$IFS + test -e "$target" -a -n "$edit" && rm -f "$target" + + warn "${Lin}warnings_to_skip:" + for i in "${warnings_to_skip[@]}"; do warn "\t$i"; done + i="texlog_extract $tleoptions '$base'" + IFS=$'\n' m=($(eval "$i")) + n=true + for i in "${m[@]}"; do + if $n; then + IFS=$' ' read -r linenum errorfile <<<"$i" + n=false + else + echo "$i" + fi + done + IFS=$ifsold + + test -z "$edit" && exit + + : "${errorfile:="$edit"}" + errorfile="${errorfile%%[\{ ]*}" # remove {...} and spaces at the end + if [[ $errorfile =~ $base.bbl ]]; then + setbibdeps + if [[ ${#bibdeps[@]} -gt 1 ]]; then + # isolate the fragment containing the error. + # m[-2] contains something like: line nnn: error fragment + e=$(cut -d' ' -f 3- <<<"${m[-2]}") + # find the bib file containing the error fragment + for i in "${bibdeps[@]}"; do + if grep -F "$e" "$i" >/dev/null; then + edit "$i" 1 true && break + fi + done + else + edit "${bibdeps[0]}" 1 true && exit + fi + else + edit "$errorfile" "$linenum" true && exit + fi +} + +<<'DOC' #------ function edit -------------------------------------------------- += edit +parameters: 1 file to be edited; if empty: contents of edit variable is used + 2 line number where edit should start; if empty, use 1 + 3 true if an error was detected in the file and user must decide + if file shall be edited +description: Start the user´s editor to edit the file in argument 1; if the + call was induced by the detection of an error in that file, the + user will be asked if he want to edit the file, or to quit. +globals set: - +globals used: edit +returns: 1 if the file was edited, else 0 +DOC +#------------------------------------------------------------------------------- +edit() { # edfile,linenum,error + local edfile="$1" linenum=$2 error=$3 + if $error; then + Warn "error in $edfile" + test -t 1 || return 0 # return if stdout is not to a terminal + while true; do + echo -n "=====> e(dit) q(uit) " + read -r x + case "$x" in + (q) return;; + (e) break;; + (*) echo you must type e or q + esac + done + fi + : "${linenum:=1}" + : "${edfile:=$edit}" + test -e "$edfile" || edfile="$edit" # this happens when tex finds unexpected EOF + eval "$EDITOR +$linenum \"$edfile\"" + # user may have edited a bibfile: + setbibdeps + for i in "${bibdeps[@]}"; do + if [[ $i -nt $base.aux ]]; then + rm -f "$base".{bbl,aux} # force texi2dvi to rerun bibtex + break + fi + done + return 1 +} + +<<'DOC' #------ function handle_options ---------------------------------------- += handle_options +parameters: uses script´s arguments +description: Handles the options +globals set: Clean batch clean dvips edit input norc print + printer rc tleoptions verbose view +globals used: HOME verbose +returns: 0 +DOC +#------------------------------------------------------------------------------- +handle_options() { + local options + if ! options=$(getopt \ + -n "$Myname" \ + -o Ccf:e:b::p:vr:nwhHVI \ + -l Clean,clean,formatter:,ps,edit:,batch::,printer:,view,noview,\ +print,noprint,verbose,noverbose,rc:,norc,nocolor,web,help,Help,version -- "$@" + ); then exit 1; fi + eval set -- "$options" + while [ $# -gt 0 ]; do + case $1 in + # General options: + (-h|--help) # print this help and exit + helpsrt + ;; + (-H|--Help) # print full documentation via less and exit + helpall + ;; + (-V|--version) # print version and exit + echo $Version + exit + ;; + (-v|--verbose) # be verbose + verbose=true + shift + ;; + ( --noverbose) # be quiet (this is the default) + verbose=false + shift + ;; + (-r|--rc) # use STRING as an rc file, instead of |~/.mkrc|. + # See the section /RC file and customization/ for more information. + rc="$2" + shift 2 + test -e "$rc" || + die "RC-file $rc, given with the --rc option, does not exist" + ;; + ( --norc) # don´t read the |~/.mkrc| file + shift + # --norc is detected before option handling, so it can be skipped here + ;; + # mk specific options: + (-f|--formatter) # Use STRING as the formatter: tex, latex, pdflatex, et cetera + formatter="$2" + shift 2 + ;; + (-e|--edit) # use STRING as the file to be edited; by default, the file containing the + # compilation error is presented for editing, or, if there are no errors, + # the main source file. + edit="${2/\~/$HOME}" + shift 2 + ;; + (-C|--Clean) # Remove all files generated by the compilation + Clean=true + shift + ;; + (-c|--clean) # Same, except for the pdf or postscript files + clean=true + shift + ;; + ( --ps) die "The --ps option has been removed; use --formatter";; + # vpp-related options: + (-b|--batch) # run in batch using STRING as a printing command for vpp. + # See the section /Running in batch mode/ for more information. + batch="$2" + shift 2 + ;; + (-p|--printer) # print to printer named STRING + printer="$2" + shift 2 + ;; + ( --view) # view the document after compilation + view=true + shift + ;; + ( --noview) # do not view + view=false + shift + ;; + ( --print) # offer printing interaction after viewing + print=true + shift + ;; + ( --noprint) # do not offer printing interaction + print=false + shift + ;; + # texlog_extract-related options: + (-w|--web) # web colouring instead of ANSI + tleoptions+=' --web' + shift + ;; + (-n|--nocolor) # no colouring instead of ANSI + tleoptions+=' --nocolor' + shift + ;; + (-I) install;; + (--) shift; break;; + (*) break;; + esac + done + # verbose is now set: + $verbose || dvips='dvips -q' + # remaining argument, if any, is the input file: + input="$1" +} + +# if --rc was used, source its argument +# if not, execute ~/.${Myname}rc if it exists + +<<'DOC' #------ function read_rc ----------------------------------------------- += read_rc +parameters: - +description: If the |--norc| option was used, does nothing. Otherwise, sources + the file in variable |rc|; if that is empty, use the |~/.mkrc| if + it exists. +globals set: - +globals used: HOME Myname rc +returns: 0 +DOC +#------------------------------------------------------------------------------- +read_rc() { + : "${rc:=$HOME/.${Myname}rc}" + # shellcheck disable=SC1090 + [[ -n $rc && -s $rc ]] && { warn "Sourcing $rc"; source "$rc"; } +} + +# do we have all executables needed? + +<<'DOC' #------ function check_needs ------------------------------------------- += check_needs +parameters: - +description: Checks if all executables needed are available. +globals set: EDITOR +globals used: EDITOR print view +returns: 1 if there are missing executables, else 0 +DOC +#------------------------------------------------------------------------------- +check_needs() { + local j i needed=(kpsewhich texi2dvi $formatter) + [[ $targetext = dvi ]] && needed+=(dvips) + $print || $view && needed+=(vpp) + for i in "${!needed[@]}"; do + which "${needed[$i]}" >/dev/null && unset needed["$i"] + done + [[ ${#needed[@]} -gt 0 ]] && die "missing executables: ${needed[*]}" + # test texi2dvi´s version: + i=$(texi2dvi --version|head -1|sed -e "s/.* //") + test "$i" -ge 6290 || + die "Your texi2dvi is too old ($i);$Nor Get a new version with:\n$Com"\ + " wget ftp.gnu.org/gnu/texinfo/texi2dvi && chmod 755 texi2dvi$Nor\n"\ + " and move texi2dvi to a directory in your PATH." + # make sure we have an editor + : "${EDITOR:=vim}" +} + + +<<'DOC' #------ function setformatter -------------------------------------------- += setformatter +parameters: - +description: set |$formatter| to the tex formatter to be used +globals set: formatter targetext vpptargetext +globals used: base ext +returns: +DOC +#------------------------------------------------------------------------------- +setformatter () { + local preamble + if [[ -n $formatter ]]; then + # nothing to do if the |--formatter| option was used + warn "formatter ($formatter) was set by the --formatter option" + elif [[ $(head -1 "$base.$ext") =~ ^%!([[:alnum:]]+) ]]; then + # found formatter in first line of source: + formatter=${BASH_REMATCH[1]} + warn "formatter found in the first line of the source" + else + # still no formatter? Try the preamble + preamble=$(sed -n -e ' + /%.*/d + /\s*\\usepackage.*fontspec/p + /^\s*\\begin{document}/q + /^\s*\\documentclass/p + ' "$base.$ext") + + if [[ $preamble =~ fontspec ]]; then + formatter=lualatex + elif [[ $preamble =~ documentclass ]]; then + formatter=pdflatex + else + formatter=pdftex + fi + warn "I guessed from the preamble that $formatter should be used to format $base.$ext\n"\ + " If this is incorrect, then use the --formatter option\n"\ + " or specify the formatter in line 1 of your source" + fi + if [[ $formatter == tex || $formatter == latex ]]; then + targetext=dvi vpptargetext=ps + elif [[ $formatter =~ ^ht ]]; then + targetext=html vpptargetext='' + fi +} + +<<'DOC' #------ function set_vpp_options -------------------------------------------- += set_vpp_options +parameters: - +description: set options for vpp call +globals set: vppoptions +globals used: pwd verbose printer +returns: - +DOC +#------------------------------------------------------------------------------- +set_vpp_options () { + vppoptions="--mk='$pwd'" # tell vpp it´s called from mk and must write to $pwd + $verbose && vppoptions+=" --verbose" + test -n "$printer" && vppoptions+=" --printer=$printer" + + # validate --batch option: + if [[ -n $batch ]]; then + view=false # --batch implies --noview + j=($batch) + for i in "${j[@]}"; do + [[ $i =~ ^(q|b|t|a|x[0-9]+|([0-9]+-?[0-9]*|[0-9]*-?[0-9]+),?)+$|^o[a-zA-Z0-9_-]+$ ]] || + die "Illegal argument ($i) in --batch argument ($batch)\n"\ + "use q if you want no printout" + done + vppoptions+=" --batch='$batch'" + [[ $batch == *q ]] && print=false + fi + + $print && vppoptions+=" --print" || vppoptions+=" --noprint" + $view && vppoptions+=" --view" || vppoptions+=" --noview" +} + +[[ "$*" =~ --norc ]] || read_rc +handle_options "$@" +check_needs +findsource "$input" +set_vpp_options + +cd "$dir" || die "Could not cd to $dir" + +: "${edit:=$base.$ext}" +if [ -n "$edit" ]; then # if empty, then no editing + test -e "$edit" || die "can´t find source file ($edit)" + test -r "$edit" || die "can´t read source file ($edit)" + test -w "$edit" || die "can´t write source file ($edit)" +fi + +setformatter + +target="$base.$targetext" +vpptarget="$base.$vpptargetext" +if [[ -e $target && ! -w $target ]]; then + die "Target $target is write-protected, so I cannot re-compile it!" +fi + +if $clean || $Clean; then + for i in "${cleanext[@]}"; do + rm -f "$base.$i" + done + eval "othercleans=$othercleans" # othercleans may have been defined in rc file + for i in $othercleans; do rm -f "$i"; done + if $Clean; then + # It may be useful to protect target, in order to prevent that they become + # recompiled with changed style files: + for i in $(echo "$target $vpptarget" | xargs -n1 |sort -u); do + if [[ -e $i && ! -w $i ]]; then + echo "$i is write-protected, so I'll keep it!" 1>&2 + else + rm -f "$i" + fi + done + [[ $formatter =~ ^ht ]] && rm -f idxmake.{dvi,log} "$base.css" + fi + exit +fi + +if [[ $formatter =~ ^ht ]]; then + die "mk can't handle the $formatter formatter, except with the --clean and --Clean options" +fi + +# texi2dviquiet, if set to true in rc-file, keeps texi2dvi quiet, even in verbose mode +# extraoptions can be set in rc file; could be, e.g., -shell-escape +if [[ $texi2dviquiet || ! $verbose ]]; then q=--quiet; else q=''; fi + +# For ltxdoc (.dtx) files, we don´t want to use the default index processor, texindy, but +# we need makeindex, with the -s gind.ist option. +if [ "$ext" = 'dtx' ]; then + indexprefix="TEXINDY=false MAKEINDEX='makeindex -s gind.ist'" +fi + +texcommand="\ + $indexprefix \ + LATEX='$formatter -halt-on-error -recorder -synctex=1 $extraoptions' \ + texi2dvi --no-line-error $q '$base.$ext' 2>/dev/null" +while true; do + if compile; then + $view || $print && { + run "vpp $vppoptions \"$vpptarget\"" + case $? in + ($editexit) edit "$edit" 1 false || continue ;; + ($compileexit) rm -f "$target"; continue ;; + (0) break ;; + (*) edit "$edit" 1 true || continue ;; + esac + } + else + show_error_and_edit + continue + fi + break +done +edit= +# compilation was OK, but still show any warnings: +show_error_and_edit |