\documentclass{beamer}
\usetheme{Luebeck}
\setbeamercovered{dynamic}
\usepackage{graphicx}
\usepackage{fontspec}
\beamertemplatenavigationsymbolsempty

\usepackage{etoolbox}
\makeatletter
\preto{\@verbatim}{\topsep=0pt \partopsep=0pt }
\makeatother

\title{\texttt{zsh} Protips}
\author{Jack Rosenthal}
\date{4 April 2016}

\logo{\includegraphics[width=30mm]{graphics/lug.pdf}}

\begin{document}

\begin{frame}
    \maketitle
\end{frame}
\logo{}

\begin{frame}
    \frametitle{What is \texttt{zsh}?}
    \texttt{zsh} is a UNIX shell with \texttt{bash}-like syntax and plenty of
    features.
    \pause
    \begin{itemize}[<+->]
        \item \texttt{zsh} features its own line editor, \texttt{zle}, with
            bindable widgets and the ability to make custom bindings
        \item \texttt{zsh} features its own history expansion engine with
            Readline compatibility
        \item \texttt{zsh} tries to avoid \texttt{bash}isms by making the
            syntax do what it looks like it is doing (eg. appending and writing
            to two files in the same command)
        \item \texttt{zsh} comes with plenty of syntactic sugar and features
            like floating point arithmetic
    \end{itemize}
\end{frame}

\begin{frame}
    \frametitle{Using \texttt{zsh} as your default shell (Personal machine)}
    \centering
    \Large
    \texttt{\$ chsh -s `which zsh`}
\end{frame}

\begin{frame}
    \frametitle{Using \texttt{zsh} as your default shell (School machine)}
    Put this line at the top of your \texttt{.bash\_profile}:

    \texttt{tty\hfill>/dev/null\hfill\&\&\hfill command\hfill
    -v\hfill zsh\hfill >/dev/null\hfill \&\&\hfill
    exec\hfill zsh}
    \medskip

    A few notes:
    \begin{itemize}
        \item You only have to do this because the \texttt{loginShell}
            LDAP attribute is used as your shell, and you don't have permission
            to change it.
        \item If you change it on one machine that uses \texttt{fermat} for its
            \texttt{/u}, then it will be changed on all.
    \end{itemize}
\end{frame}

\begin{frame}
    \frametitle{Setting up \texttt{zsh}}
    \textbf{Option 1}

    Use an ``instantly awesome zsh'' framework like \emph{Oh My Zsh} or
    \emph{Prezto}. This has the advantage of a \emph{Vundle}-like plugin system
    and less time spent configuring.

    \medskip

    \textbf{Option 2}

    Do it yourself. Allows more customisation and typically lighter.
\end{frame}

\begin{frame}[fragile]
    \frametitle{Writing a \texttt{.zshrc}}

    If you've decided to go with \textbf{Option 2}, you will need to write a
    \texttt{.zshrc}, a script that runs when you start \texttt{zsh}. Here are
    some things you may consider adding:
    \medskip

    \begin{tabular}{l l}
        \texttt{bindkey -v} \emph{or} \texttt{bindkey -e} & \texttt{vim} or
        \texttt{emacs} \texttt{zle} bindings \\
        \texttt{HISTFILE=\textasciitilde/.histfile} & Persistent history \\
        \texttt{HISTSIZE=1000} & Up to 1000 items in history \\
        \texttt{SAVEHIST=1000} & Up to 1000 items persistent \\
        \texttt{setopt appendhistory} & Append history to the history file \\
        \texttt{setopt histignoredups} & Ignore duplicates in history \\
        \texttt{setopt histignorespace} & Ignore lines which begin with a space \\
        \texttt{setopt autopushd} & Use the dirstack as you \texttt{cd}
    \end{tabular}

    \medskip

    Also don't forget to set your \texttt{EDITOR}, \texttt{PAGER}, etc.

\end{frame}

\begin{frame}
    \frametitle{More \texttt{setopt} options}
    \begin{itemize}
        \item \texttt{beep}/\texttt{nobeep} - Ring the terminal bell on \texttt{zle} error
        \item \texttt{notify} - Report the status of background jobs
            immediately
        \item \texttt{nomatch} - If a globbing pattern has no matches, print an
            error, instead of leaving it unchanged in the argument list.
        \item \texttt{autocd} - Change to a directory if you just type the name
        \item \texttt{correct} - Typo Correction
        \item \texttt{extendedglob} - Extended globbing, explained later
    \end{itemize}

    Read \texttt{man zshoptions}. There are many options.

\end{frame}

\begin{frame}
    \frametitle{Extended Globbing}
    With \texttt{setopt extendedglob}, you can use some cool extended globbing
    patterns:
    \begin{itemize}
        \item \texttt{**} matches any all of the child directories,
            recursively, including the current directory
        \item \texttt{***} is the same as above, but follows symlinks
    \end{itemize}

    If you enable \texttt{setopt globstarshort}, you can shorten \texttt{**/*}
    to \texttt{**} and \texttt{***/*} to \texttt{***}. This would cause
    \texttt{**.c} to match all files ending in \texttt{.c} recursively.
\end{frame}

\begin{frame}[fragile]
    \frametitle{More Cool Globbing}
    \textbf{Globbing What Its Not}
    \begin{verbatim}
zsh % ls
main.c      Makefile    README.md
zsh % echo ^*.c
Makefile README.md\end{verbatim}
    \pause

    \vfill
    \textbf{Numeric Ranges}
    \begin{verbatim}
zsh % ls
hello1234   hello1235   hello1400
zsh % echo hello<1230-1240>
hello1234 hello1235\end{verbatim}
    \pause

    \vfill
    \textbf{Perl-Style Or}
    \begin{verbatim}
zsh % ls
hello.txt   world.gif   zap.sh
zsh % echo *.(txt|gif)
hello.txt world.gif\end{verbatim}
\end{frame}

\begin{frame}[fragile]
    \frametitle{Brace Expansion}
    \begin{verbatim}zsh % echo hello_{one,two,three,four,five}
hello_one hello_two hello_three hello_four hello_five\end{verbatim}
\pause

    \begin{verbatim}zsh % echo hello{1..5}
hello1 hello2 hello3 hello4 hello5\end{verbatim}
\pause

    \begin{verbatim}zsh % echo hello{07..12}
hello07 hello08 hello09 hello10 hello11 hello12\end{verbatim}
\pause

    \begin{verbatim}zsh % echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z\end{verbatim}
\end{frame}

\begin{frame}
    \frametitle{Parameter Expansion}
    \texttt{\$\{}...\texttt{\}} is a parameter expansion. A parameter expansion
    will always involve a variable.
    \begin{itemize}[<+->]
        \item \texttt{\$\{VAR\}} will expand to the value of \texttt{VAR}.
        \item \texttt{\$\{\#VAR\}} will expand to the length of \texttt{VAR}.
        \item If \texttt{VAR} is a filename, \texttt{\$\{VAR:h\}} will expand
            to the directory of the file, \texttt{:t} to the name of the file,
            and \texttt{:r} to the file without its extension.
        \item \texttt{\$\{VAR:s/$find$/$replace$/\}} will do \texttt{sed}-style
            substitution
    \end{itemize}

    \pause

    Read \texttt{man zshexpn} for more. I take no responsibility for brain
    damage.
\end{frame}

\begin{frame}
    \frametitle{Suffix Aliases}
    \centering
    Say you want \texttt{.tex} files to open in your \texttt{\$EDITOR}.

    \medskip
    {\Large\ttfamily alias -s tex=\$EDITOR\par}
    \medskip

    Then type just the filename as the command.
\end{frame}

\begin{frame}
    \frametitle{Global Aliases}
    \centering
    Global aliases expand anywhere in the command.

    \medskip
    {\Large\ttfamily
    \begin{tabular}{l}
    alias -g ...='../..' \\
    alias -g ....='../../..' \\
    alias -g .....='../../../..' \\
    \end{tabular}
    }
\end{frame}

\begin{frame}
    \frametitle{Multiple Redirection}
    \texttt{zsh} can redirect to and from multiple inputs/outputs at the same
    time. So...

    \medskip
    \small
    \begin{tabular}{l l}
        Rather than typing & You can type \\ \hline
        \texttt{w >file1; w >file2; w >file3} & \texttt{w >file\{1..3\}} \\
        \texttt{cat file\{1,2\} | less} & \texttt{less <file\{1,2\}} \\
        \texttt{./server | tee log | grep ERR} &
        \texttt{./server >log | grep ERR} \\
    \end{tabular}
\end{frame}

\begin{frame}
    \frametitle{Process Substitution}
    You can substitute a command in, like it's a file.
    \begin{itemize}
        \item \texttt{<($\ldots$)} is used to read output from a command
        \item \texttt{>($\ldots$)} is used to write to the stdin of a command
        \item \texttt{=($\ldots$)} is like \texttt{<($\ldots$)}, however
            creates a temporary file (so seek is allowed)
    \end{itemize}

    For example, to compare the output of two commands:

    \texttt{diff <(command1) <(command2)}
\end{frame}

\begin{frame}
    \frametitle{Kill command for later use}
    Say you start typing a command but then realise you have to do something
    else first. Bind a key to \texttt{push-line}. I use \texttt{q} in
    \texttt{vi} normal mode:

    \medskip
    \texttt{bindkey -M vicmd q push-line}
    \medskip

    Then, press \texttt{<Esc>q} when you have another command to run first.
    Your old command will reappear when the first one finishes.
\end{frame}

\begin{frame}[fragile]
    \frametitle{Making custom key widgets}
    Write a function, then bind it with \texttt{zle -N}. Example:

    \medskip

    \begin{verbatim}
function __zkey_prepend_sudo {
    if [[ $BUFFER != "sudo "* ]]; then
        BUFFER="sudo $BUFFER"
        CURSOR+=5
    fi
}
zle -N prepend-sudo __zkey_prepend_sudo
bindkey -M vicmd "s" prepend-sudo\end{verbatim}

    \medskip

    Now \texttt{<Esc>s} will put \texttt{sudo} at the beginning of the command.
\end{frame}

\begin{frame}
    \frametitle{Completion}
    To add intelligent completion to \texttt{zsh}, add this line to your
    \texttt{\textasciitilde/.zshrc}:

    \medskip
    \centering \Large
    \texttt{autoload -U compinit \&\& compinit}
\end{frame}

\begin{frame}
    \frametitle{Completion Automagic Rehash}
    \centering \Large
    \texttt{zstyle ':completion:*' rehash true}
\end{frame}

\begin{frame}
    \frametitle{Completion Case Correction}
    \centering
    \texttt{zstyle ':completion:*' matcher-list 'm:\{a-z\}=\{A-Z\}'}
\end{frame}

\begin{frame}
    \frametitle{Approximate Completion}
    \centering
    Allow one error for every three letters typed.

    \medskip
    \texttt{zstyle ':completion:*:approximate:' max-errors
    'reply=(\$(((\$\#PREFIX+\$\#SUFFIX)/3 )) numeric )'}
\end{frame}

\begin{frame}[fragile]
    \frametitle{Misc: Directory Hashing}
    Hash directories like their home direcories for quick and convenient
    access:
    \medskip

    \begin{verbatim}zsh % hash -d os=~/classes/cs/os
zsh % cd ~os\end{verbatim}
    \medskip

    \pause
    \begin{block}{Protip}
        \small
        If you copy your \texttt{\textasciitilde/.zshrc} between systems, it may be
        convenient to set up hashes on a per system basis:
        \smallskip
        \begin{verbatim}case $(hostname) in
    toilers)
        hash -d web=/home/www
        ;;
    mastergo)
        hash -d web=/var/www
        ;;
    ...
esac\end{verbatim}
    \end{block}
\end{frame}

\end{document}
