using AutoHotKey to streamline LaTeX document authoring

Here is a script I created over time and improve occasionally for my personal use.

Features:

  • Instant completion for single brackets (,[,{. You can also delete surrounding characters with [Shift] + [Backspace]

    enter image description here


  • Create \left* \right* environments for any two characters with [Ctrl] + 7

    enter image description here


  • Single letter Tab autocompletion to greek letters (case sensitive)

    enter image description here


  • Insert brackets (,[,{ around a selection with [Ctrl] + 8,9,0

    enter image description here


  • As requested by Mr.Robot, you can now jump between bullets, which are included in some of the autocompletion commands. This can be done via [Ctrl] + Space

    enter image description here


  • Environment Tab completion assistant

    enter image description here


  • A lot of autocompletions, I will not list here. Feel free to have a look at the code. It is mostly commented.

Code (new version):

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

#a::Suspend, Toggle ; pause script
#Hotstring EndChars `t ; [Tab] triggers Hotstrings

; Reset Hotstring for CTRL+Backspace and CTRL+A (otherwise hostrings won't trigger)
Ctrl & Backspace::
    SendInput ^`b
    Hotstring("Reset")
    Return

Ctrl & a::
    SendInput ^a
    Hotstring("Reset")
    Return

; :o:   omit ending character
; :?:   triggers hotstring even between characters
; :c:   case sensitive
; :*:   no trigger
; ^     ctrl
; +     shift
; <!    left alt



; /// 1. BRACKETS //////////////////////////////////////////////////////////////////////////////////

; instant complete (), [], {}
:o*?:(::(){Left}
:o*?:[::[]{Left}
:o*?:{::{{}{}}{Left}

:o:abs::\left|  \right| {Left 9} ; Absolut Value: \left| \right|
:o:abs2::\left|  \right|{^}2 {Left 11} ; Absolut Value: \left| \right|
^4:: Send $${Left} ; $$

; \left* \right*
; (instruction: place the cursor between the opening and the closing symbol, then hit ctrl+7)
^7::
    SendInput, {Left}\left{Right}  \right{Left 7}
    Return

; put brackets around selection
; (warning: this might not work in some applications!)
^8::
    ClipBackup := ClipboardAll
    clipboard := ""
    SendInput, ^x
    SendInput, (){Left}
    SendInput, ^v
    SendInput, {Right}
    Sleep 1000
    Clipboard := ClipBackup
    Return

^9::
    ClipBackup := ClipboardAll
    clipboard := ""
    SendInput, ^x
    SendInput, []{Left}
    SendInput, ^v
    SendInput, {Right}
    Sleep 1000
    Clipboard := ClipBackup
    Return

^0::
    ClipBackup := ClipboardAll
    clipboard := ""
    SendInput, ^x
    SendInput, {{}{}}{Left}
    SendInput, ^v
    SendInput, {Right}
    Sleep 1000
    Clipboard := ClipBackup
    Return




; /// 2. OTHER /////////////////////////////////////////////////////////////////////////////////////

; Jump to first occurance of • in the current line. (Continues search in the next line.)
^Space::
    ClipBackup := ClipboardAll
    clipboard := ""
    SendInput, {Home}+{End}
    SendInput, ^c
    Sleep 50 ; increase this number, if it doesn't work
    SearchedText := clipboard
    ; MsgBox, %SearchedText%    
    StringGetPos, pos, SearchedText, •
    if (pos >= 0)
        ; MsgBox, %Target% was found at %pos%.
        SendInput, {Home}{Right %pos%}+{Right}
    else
        SendInput, {Down}
        SendInput, {Home}+{End}
        SendInput, ^c
        Sleep 50 ; increase this number, if it doesn't work
        SearchedText := clipboard
        ; MsgBox, %SearchedText%    
        StringGetPos, pos, SearchedText, •
        if (pos >= 0)
            ; MsgBox, %Target% was found at %pos%.
            SendInput, {Home}{Right %pos%}+{Right}
        else
            SendInput, {End}
    Clipboard := ClipBackup
    Return

; Comfort
+Backspace:: Send,{BackSpace}{Delete} ; delete surrounding characters
^Enter:: Send,{End}{Enter} ; instant create new line, even from within words.

; Shift+Space: escape to the right and insert a space
+Space::
    SendInput, {Right}{Space}
    Return

; Whitespaces
:o:qd::\quad
:o:qq::\qquad
:o?: ::\{Space}{Space}
:o?:,::\,
:o:clp::\clearpage

; Environments
:o:bg::
    InputBox, OutputVar, Environment,,, 200, 120,,,,, align
    SendInput, \begin{{}%OutputVar%{}}`r`r\end{{}%OutputVar%{}}{Up}`t
    Return

:o:bga::\begin{{}align{}}`r`r\end{{}align{}}{Up}`t ; align
:o:bgas::\begin{{}align{}}\begin{{}split{}}`r`r\end{{}split{}}\end{{}align{}}{Up}`t ; align with split

:o:itmz::\begin{{}itemize{}}`r{Home}`r\end{{}itemize{}}{Up}`t\item{Space} ; align
:o:itm::\item{Space}



; /// 3. TEXT FORMATTING ///////////////////////////////////////////////////////////////////////////

; Sections
:o:sc::\section{{}•{}}{Left}+{Left} ; \section
:o:ss::\subsection{{}•{}}{Left}+{Left} ; \subsection
:o:sss::\subsubsection*{{}•{}}{Left}+{Left} ; \subsubsection*

; Text
:o:tx::\text{{}•{}}{Left}+{Left} ; \text
:o:tbf::\textbf{{}•{}}{Left}+{Left} ; \textbf
:o:tit::\textit{{}•{}}{Left}+{Left} ; \textit
:o:em::\emph{{}•{}}{Left}+{Left} ; \emph
:o:sf::\textsf{{}•{}}{Left}+{Left} ; sans serif
:o:sc::\textsc{{}•{}}{Left}+{Left} ; small caps

:o:bf::\mathbf{{}•{}}{Left}+{Left} ; \mathbf
:o:cal::\mathcal{{}•{}}{Left}+{Left} ; \mathcal
:o:scr::\mathscr{{}•{}}{Left}+{Left} ; \mathscr
:o:bb::\mathbb{{}•{}}{Left}+{Left} ; \mathbb
:o:bbm::\mathbbm{{}•{}}{Left}+{Left} ; \mathbbm



; /// 4. MATH STUFF ////////////////////////////////////////////////////////////////////////////////

; Common Operations
:o:fr::\frac{Space} ; \frac
:o:fra::\frac{{}•{}}{{}•{}}{Left 4}+{Left} ; \frac{•}{•}
:o:tfr::\tfrac{Space} ; \tfrac
:o:su::\sum{Space} ; \sum
:o:sum::\sum_{{}•{}}{^}{{}•{}}{Left 5}+{Left} ; \sum_{•}^{•}
:o:pro::\prod_{{}•{}}{^}{{}•{}}{Left 5}+{Left} ; \prod_{•}^{•}
:o:in::\int{Space} ; \int
:o:oin::\oint{Space} ; \oint
:o:int::\int_{{}•{}}{^}{{}•{}}{Left 5}+{Left} ; \int_{•}^{•}
:o:sq::\sqrt{{}•{}}{Left}+{Left} ; \sqrt{ } \sqrt{}

; alt+^ instantly yields ^{•}
<!^::
    SendInput, {^}{{}•{}}{Left}+{Left}
    Return

; Relations
:o:<=>::\Leftrightarrow ; <=>
:o:=>::\Rightarrow ; =>
:o:<=::\Leftarrow ; <=
:o?:-->::\longrightarrow ; -->
:o:->::\rightarrow ; ->
:o:!=::\overset{{}{!}{}}{{}={}}{Space} ; ! over =
:o?:=::\ =\{Space}
:o:eq::\ \equiv\{Space}
:o:~::\sim

; Other / Symbols
:o:cnc::\cancel{{}•{}}{Left}+{Left} ; \cancel{}
:o:del::\partial
:o:dell::\frac{{}\partial{}}{{}\partial •{}}{Left}+{Left}
:o:ovs::\overset{{}•{}}{{}•{}}{Left 4}+{Left}
:o:inf::\infty
:o:°::{^}\circ 
:o:cd::\cdot{Space}
:o:dg::{^}\dagger
:o:dd::\text{{}d{}}•+{Left} ; used for differentials e.g. dx



; /// 5. MATRICES //////////////////////////////////////////////////////////////////////////////////

; Matrices
:o:pm2::\begin{{}pmatrix{}}`r• & • \\`r• & • \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t+{Right}
:o:bm2::\begin{{}bmatrix{}}`r• & • \\`r• & • \\`r\end{{}bmatrix{}}{Left 13}{Up}`t{Left}{Up}`t+{Right}
:o:pm3::\begin{{}pmatrix{}}`r• & • & • \\`r• & • & • \\`r• & • & • \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t+{Right}
:o:bm3::\begin{{}bmatrix{}}`r• & • & • \\`r• & • & • \\`r• & • & • \\`r\end{{}bmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t+{Right}
:o:pm4::\begin{{}pmatrix{}}`r• & • & • & • \\`r• & • & • & • \\`r• & • & • & • \\`r• & • & • & • \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t{Left}{Up}`t+{Right}
:o:bm4::\begin{{}bmatrix{}}`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r\end{{}bmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t{Left}{Up}`t+{Right}

; LGS
:o:lgs::\begin{{}matrix{}}`r• &=& • \\`r• &=& • \\`r\end{{}matrix{}}{Left 12}{Up}`t{Left}{Up}`t+{Right}

; Vectors
:o:v2::\begin{{}pmatrix{}}`r• \\`r• \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t+{Right}
:o:v3::\begin{{}pmatrix{}}`r• \\`r• \\`r• \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t+{Right}
:o:v4::\begin{{}pmatrix{}}`r• \\`r• \\`r• \\`r• \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t{Left}{Up}`t+{Right}



; /// 6. GREEK /////////////////////////////////////////////////////////////////////////////////////

:o:a::\alpha  
:o:b::\beta
:o:c::\chi
:oc:d::\delta
:oc:D::\Delta
:o:e::\epsilon
:o:ve::\varepsilon
:oc:f::\phi
:oc:F::\Phi
:o:vf::\varphi
:oc:g::\gamma
:oc:G::\Gamma
:o:h::\eta
:o:i::\iota
:o:k::\kappa
:oc:l::\lambda
:oc:L::\Lambda
:o:m::\mu
:o:n::\nu
:oc:p::\pi
:oc:P::\Pi
:oc:q::\theta
:oc:Q::\Theta
:o:vq::\vartheta
:o:r::\rho
:oc:s::\sigma
:oc:S::\Sigma
:o:t::\tau
:oc:u::\upsilon
:oc:U::\Upsilon
:o:v::\digamma
:oc:w::\omega
:oc:W::\Omega
:oc:x::\xi
:oc:X::\Xi
:oc:y::\psi
:oc:Y::\Psi
:o:z::\zeta

Old version from my original answer:

; /// HEAD /////////////////////////////////////////////////////////////////////

; :o:   omit ending character
; :?:   triggers hotstring even between characters
; :c:   case sensitive
; ^     CTRL

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

#a::Suspend, Toggle ; toggle suspend script
#Hotstring EndChars `t ; [Tab] triggers Hotstrings

; Reset Hotstring for CTRL+Backspace and CTRL+A (otherwise hostrings won't trigger)
Ctrl & Backspace::
    SendInput ^`b
    Hotstring("Reset")
Return

Ctrl & a::
    SendInput ^a
    Hotstring("Reset")
Return


; /// COMFORT //////////////////////////////////////////////////////////////////

+Backspace:: Send,{BackSpace}{Delete} ; delete surrounding characters
^Enter:: Send,{End}{Enter} ; instant jump to new line, even from between characters


; /// BRACKETS /////////////////////////////////////////////////////////////////

; instant complete std brackets
:o*?:(::(){Left}
:o*?:[::[]{Left}
:o*?:{::{{}{}}{Left}

; left right brackets
^8:: Send \left(  \right) {Left 9} ; \left( \right)
^9:: Send \left[  \right] {Left 9} ; \left[ \right]
^<:: Send \left<  \right> {Left 9} ; \left< \right>
^7:: Send \left\{{}  \right\{}} {Left 10} ; \left{ \right}

^4:: Send $${Left} ; $$
:o:abs::\left|  \right| {Left 9} ; Absolut Value: \left| \right|


; /// GENERAL SHORTS ///////////////////////////////////////////////////////////

:o:baln::\begin{{}align{}}`r`r\end{{}align{}}{Up}`t ; align
:o:bgas::\begin{{}align{}}\begin{{}split{}}`r`r\end{{}split{}}\end{{}align{}}{Up}`t ; align with split
:o:sc::\section{{}•{}}{Left}+{Left} ; \section
:o:ss::\subsection{{}•{}}{Left}+{Left} ; \subsection
:o:clp::\clearpage

; Text
:o:tx::\text{{}•{}}{Left}+{Left} ; \text
:o:tbf::\textbf{{}•{}}{Left}+{Left} ; \textbf
:o:tit::\textit{{}•{}}{Left}+{Left} ; \textit
:o:em::\emph{{}•{}}{Left}+{Left} ; \emph
:o:bf::\mathbf{{}•{}}{Left}+{Left} ; \mathbf
:o:cal::\mathcal{{}•{}}{Left}+{Left} ; \mathcal
:o:scr::\mathscr{{}•{}}{Left}+{Left} ; \mathscr
:o:bb::\mathbb{{}•{}}{Left}+{Left} ; \mathbb
:o:bbm::\mathbbm{{}•{}}{Left}+{Left} ; \mathbbm

; Operations, Symbols, Relations
:o:fra::\frac{Space} ; frac
:o:sum::\sum_{{}•{}}{^}{{}•{}}{Left 5}+{Left} ; \sum
:o:pro::\prod_{{}•{}}{^}{{}•{}}{Left 5}+{Left} ; \prod
:o:int::\int_{{}•{}}{^}{{}•{}}{Left 5}+{Left} ; \int

:o:del::\partial
:o:ovs::\overset 
:o:inf::\infty
:o:°::{^}\circ 
:o:cd::\cdot
:o:dg::{^}\dagger
:o:dd::\text{{}d{}}
:o:qd::\quad
:o:qq::\qquad

:o:<=>::\Leftrightarrow
:o:=>::\Rightarrow
:o:->::\rightarrow
:o:!=::\overset{{}{!}{}}{{}={}}
:o?:=::\ =\{Space}
:o:eq::\ \equiv\{Space}
:o:~::\sim


; /// MATRICES & VECTORS ///////////////////////////////////////////////////////

; Matrices
:o:pm2::\begin{{}pmatrix{}}`r0 & 0 \\`r0 & 0 \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t
:o:bm2::\begin{{}bmatrix{}}`r0 & 0 \\`r0 & 0 \\`r\end{{}bmatrix{}}{Left 13}{Up}`t{Left}{Up}`t
:o:pm3::\begin{{}pmatrix{}}`r0 & 0 & 0 \\`r0 & 0 & 0 \\`r0 & 0 & 0 \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t
:o:bm3::\begin{{}bmatrix{}}`r0 & 0 & 0 \\`r0 & 0 & 0 \\`r0 & 0 & 0 \\`r\end{{}bmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t
:o:pm4::\begin{{}pmatrix{}}`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t{Left}{Up}`t
:o:bm4::\begin{{}bmatrix{}}`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r0 & 0 & 0 & 0 \\`r\end{{}bmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t{Left}{Up}`t

; LGS
:o:lgs::\begin{{}cases{}}\;`r\begin{{}matrix{}}`rf  & = & a & b \\`rf  & = & c & d \\`r\end{{}matrix{}}`r\end{{}cases{}}{Left 11}{Up 2}`t{Left}{Up}`t

; Vectors
:o:v2::\begin{{}pmatrix{}}`r0 \\`r0 \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t
:o:v3::\begin{{}pmatrix{}}`r0 \\`r0 \\`r0 \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t
:o:v4::\begin{{}pmatrix{}}`r0 \\`r0 \\`r0 \\`r0 \\`r\end{{}pmatrix{}}{Left 13}{Up}`t{Left}{Up}`t{Left}{Up}`t{Left}{Up}`t


; /// GREEK ////////////////////////////////////////////////////////////////////

:o:a::\alpha  
:o:b::\beta
:o:c::\chi
:oc:d::\delta
:oc:D::\Delta
:o:e::\epsilon
:o:ve::\varepsilon
:oc:f::\phi
:oc:F::\Phi
:o:vf::\varphi
:oc:g::\gamma
:oc:G::\Gamma
:o:h::\eta
:o:i::\iota
:o:k::\kappa
:oc:l::\lambda
:oc:L::\Lambda
:o:m::\mu
:o:n::\nu
:oc:p::\pi
:oc:P::\Pi
:oc:q::\theta
:oc:Q::\Theta
:o:vq::\vartheta
:o:r::\rho
:oc:s::\sigma
:oc:S::\Sigma
:o:t::\tau
:oc:u::\upsilon
:oc:U::\Upsilon
:o:v::\digamma
:oc:w::\omega
:oc:W::\Omega
:oc:x::\xi
:oc:X::\Xi
:oc:y::\psi
:oc:Y::\Psi
:o:z::\zeta

In general, I'm very inaccurate when typing things like "\", "{", "$" etc. It's especially cumbersome to navigate text with the Left, Right, Up and Down keys and you do all of these things constantly when typing tex.

I haven't spent much time learning how to write scripts with AHK, but I did write a few things to make a few shortcuts and to save the amount of which my wrists have to bend while typing tex.

For example, these I wrote for my preference.

^space:: Send {{}{}}{Left}
CapsLock:: Send {$}{$}{Left}
^9:: Send {(}{)}{Left}
^l:: Send {Right}
^j:: Send {Left}
^i:: Send {Up}
^m:: Send {Down}
^k:: Send {Down}
+^l:: Send +{Right}
+^j:: Send +{Left}
+^i:: Send +{Up}
+^m:: Send +{Down}
+^k:: Send +{Down}
^f:: Send {^}
^p:: Send \pause{Enter}{Enter}
^h:: Send \
^n:: Send \{{}\{}}{Left}{Left}
^;:: Send {End}
^Backspace:: Send {Delete}
^=:: Send {&}={&}

I came here because I too was wondering if someone with professional knowledge of AHK had written something useful for writing tex.


By accident I found this question and also by accident I found an answer a long time ago:

http://uweziegenhagen.de/?tag=autohotkey

The guy there, Mr. Ziegenhagen, blogs some useful scripts in order to make the LaTeX life easier. Some examples:

!e::
InputBox, UserEnv, Environment, Please enter an environment!, , 240, 120
If ErrorLevel
    return
Else 
if( RegExMatch(UserEnv, "(.*?)(\d+)$", splitted) ) {
    Send \begin{{}%splitted1%{}}{Enter}
        Loop %splitted2% {
            Send \item {Enter}
        }
    Send \end{{}%splitted1%{}}{Up}
    count2 := splitted2 - 1 
    Loop %count2% {
        Send {Up}
    }           
} 
Else 
    Send \begin{{}%UserEnv%{}}{Enter 2}\end{{}%UserEnv%{}}{Up}
return

If you press Alt+e and enter e. g. itemize3 then the script will insert

\begin{itemize}
\item
\item 
\item 
\end{itemize} 

I think that's great! Here are some more examples:

:*:ch#::\chapter{{}{}}{LEFT}
:*:s#::\section{{}{}}{LEFT}
:*:ss#::\subsection{{}{}}{LEFT}
:*:sss#::\subsubsection{{}{}}{LEFT}

:*:b#::\begin{{}{}}{LEFT}
:*:e#::\end{{}{}}{LEFT}

:*:bf#::\textbf{{}{}}{LEFT}
:*:tt#::\texttt{{}{}}{LEFT}
:*:it#::\textit{{}{}}{LEFT}

:*:desc#::\begin{{}description{}}`r\item[]`r\item[]`r\item[]`r\end{{}description{}}{UP 3}{LEFT}
:*:enum#::\begin{{}enumerate{}}`r\item `r\item `r\item `r\end{{}enumerate{}}{UP 3}
:*:item#::\begin{{}itemize{}}`r\item `r\item `r\item `r\end{{}itemize{}}{UP 3}

See also this question. Here are more examples from Mr. Ziegenhagen's blog:

http://uweziegenhagen.de/?s=Autohotkey

Tags:

Automation