\documentclass[aspectratio=1610]{beamer} \usetheme{lug} \usepackage{xcolor} \usepackage{fontspec} \usepackage{minted} \setminted{autogobble} \usemintedstyle{lovelace} \beamertemplatenavigationsymbolsempty \setbeamercovered{dynamic} \title{Readline Ninja Skills} \author{Jack Rosenthal} \date{2016-03-07 \\ 2018-03-08} \begin{document} \begin{frame} \maketitle \end{frame} \begin{frame} \frametitle{Readline} \begin{itemize}[<+->] \item A library for interactive line editing that your shell probably uses. \item Responsible for things like tab completion, history expansion, and all of those useful keystrokes \item Readline saves you keystrokes. \item Some readline things can make you look like a total ninja. \item Some readline things make you feel like a total ninja. \end{itemize} \end{frame} \section{Using Readline \& History} \begin{frame} \frametitle{History} Readline can track your history, most shells let you use the \texttt{history} builtin to view your history. You can navigate your history using the up and down keys. \end{frame} \begin{frame} \frametitle{Tab completion} Most of us already know what this and would die without it. \end{frame} \begin{frame} \frametitle{Event Designators} \begin{itemize}[<+->] \item \texttt{!} - begin history expansion \item \texttt{!!} - refer to the last command \item \texttt{!$n$} - refer to the $n$-th command in history \item \texttt{!-$n$} - refer to the current command minus $n$ \item \texttt{!\#} - refer to the current command you are typing \item \texttt{!$search$} - refer to the last commmand that starts with $search$ \item[] \texttt{!?$search$?} - refer to the last command with $search$ anywhere in the command \end{itemize} \pause[\thebeamerpauses] Examples: \begin{itemize}[<+->] \item \texttt{sudo !!} - run the last command with \texttt{sudo} in front \item \texttt{!grep} - run the last command you typed beginning with \texttt{grep} \end{itemize} \end{frame} \begin{frame} \frametitle{Word Designators} Often times you will want only part of a command, so you can use word designators to select which parts you want.\pause{} Follow an event designator with a colon (\texttt{:}) and then a word designator. \pause \begin{itemize}[<+->] \item \texttt{:$n$} - select argument $n$ (zero indexed) \item \texttt{:$n$-$m$} - select arguments $n$ through $m$ \item \texttt{:\$} - select the last argument (think of a regex) \item \texttt{:*} - select all arguments, omitting the command name (equivalent to \texttt{:1-\$}) \item[] \texttt{:\%} - select the argument that matches \texttt{?$search$?} \end{itemize} \pause[\thebeamerpauses] Examples: \begin{itemize}[<+->] \item \texttt{cd !!:1} - \texttt{cd} to the first argument of the last command. \item \texttt{vim !-2:\$} - edit the file that is the last argument of two commands ago \end{itemize} \end{frame} \begin{frame} \frametitle{Modifiers} \only<1-8>{ Modifiers let you chop up the history expansion in ways that you like. You can chain any amount of modifiers that you would like onto your expansion. } \begin{itemize} \item<2-> \texttt{:r} - Chop off the extension of a filename \item<3-> \texttt{:h} - Remove the filename component, leaving only the directory (think of head) \item<4-> \texttt{:t} - Remove the directory component, leaving only the filename (think of tail) \item<5-> \texttt{:q} - Quote each of the arguments \item<6-> \texttt{:s/$search$/$replace$/} - \texttt{sed} style substitution \item<7-> \texttt{:gs/$search$/$replace$/} - \texttt{sed} style substitution, globally \item<8-> \texttt{:p} - print the history expansion, don't execute quite yet \end{itemize} \only<9->{ Examples: \begin{itemize} \item<10-> \texttt{mv important.png !\#:1:r.gif} - rename \texttt{important.png} to \texttt{important.gif} \item<11-> \texttt{touch mydir/file.txt} \item<12-> \texttt{cd !\$:h} \end{itemize} } \end{frame} \begin{frame} \frametitle{Abbreviations Allowed} \begin{itemize}[<+->] \item \texttt{!!:\ldots} can be shortened to \texttt{!:\ldots} \item The \texttt{:} can be removed from word designators where it is unambiguous. So \texttt{!\$} and \texttt{!*} are allowed. \item The trailing \texttt{/} in a substitution can be omitted if it is unambigous that the substitution has ended. \item The trailing \texttt{?} in a \texttt{!?$search$?} can be ommitted for the same reason. \item Any delimiter can be used in a substitution, so \texttt{!:sx$find$x$replace$x} is legal. \end{itemize} \end{frame} \begin{frame} \frametitle{Editing Modes} Readline provides editing modes similar to \texttt{vi} and \texttt{emacs}. Learn one and learn to love it. Most shells and programs have \texttt{emacs} as the default. \end{frame} \begin{frame} \frametitle{History Incremental Search} \texttt{} (\texttt{vi: /}) brings you to an search of your history. \texttt{} will reverse the direction of your search (You may need to \texttt{stty -ixon}). \end{frame} \section{Readline Programming in C/C++} \begin{frame}[fragile=singleslide] \frametitle{C/C++ Readline Library} \inputminted{c}{codesnip/readlineinclude.c} Allocates memory to read a line, reads it from standard input (displaying \mintinline{c}{prompt} as the prompt line). Returns the line you read. You really should \mintinline{c}{free} the memory it allocated. \end{frame} \begin{frame}[fragile] \frametitle{Using History Features} \begin{minted}{c} void using_history(void); \end{minted} Must be called before using history features. \pause \begin{minted}{c} int read_history(const char *filename); int write_history(const char *filename); \end{minted} For reading/writing saved history. Returns non-zero on failure and sets \mintinline{c}{errno}. \pause \begin{minted}{c} void add_history(const char *line); \end{minted} Add a line to the history. \pause \inputminted{c}{codesnip/historylist.c} List history. \end{frame} \begin{frame}[fragile] \frametitle{History Expansion (for free!)} \begin{minted}{c} int history_expand(char *string, char **output); \end{minted} Expand string, placing the result into output, a pointer to a string. Returns: \begin{tabular}{l l} 0 & If no expansions took place \\ 1 & If expansions did take place \\ -1 & If there was an error in expansion \\ 2 & If the line should be displayed, but not executed (\texttt{:p}) \\ \end{tabular} If an error occurred in expansion, then output contains a descriptive error message. \end{frame} \begin{frame}[fragile]{A Complete Example: 31-line UNIX shell} \tiny \inputminted[linenos]{c}{codesnip/progexample.c} \end{frame} \section{Readline Programming in Python} \begin{frame}[fragile]{\texttt{import readline}} To use Readline from Python, type \texttt{import readline}, and the \texttt{input} function will magically become readlineifyed. \begin{minted}{python3} import sys import readline while True: try: cmd = input(">>> ") except KeyboardInterrupt: continue except EOFError: sys.exit(0) print(exec(cmd)) \end{minted} \end{frame} \begin{frame}[fragile]{Tab Completion} The \texttt{readline} module provides an interface for you to add your own completer: \begin{minted}{python3} readline.set_completer(function) \end{minted} \mintinline{python3}{function} should be a function which takes two parameters: \begin{tabular}{l l} \texttt{text} & The current completion text \\ \texttt{state} & \texttt{0}, \texttt{1}, \ldots \\ \end{tabular} \pause Then, set your delimiters and completion keys: \begin{minted}{python3} readline.set_completer_delims(' ') readline.parse_and_bind("tab: complete") \end{minted} \end{frame} \begin{frame}[fragile]{Custom Completion in the Wild: \texttt{iels}} \fontsize{9pt}{10pt}\selectfont \begin{minted}[linenos]{python3} def completer(text, state): def gen(): variables = reduce(set.union, map(dict.keys, els.vars), set()) for s in '%', '$': for v in variables: if (s + v).startswith(text): yield s + v for op in els.operators: if op.startswith(text): yield op for syntax in 'begin', 'end': if syntax.startswith(text): yield syntax if state == 0: completer.it = gen() try: return next(completer.it) except StopIteration: return None \end{minted} \end{frame} \begin{frame}{Alternatives to Readline for Python} While Readline is a well written piece of software, it feels a little bit out of place in Python, with the bindings reflective of the state-maintaining C code they talk to. Prompt Toolkit is a pure-Python alternative with fancy features: \begin{center} \includegraphics[width=0.8\textwidth]{graphics/ptpython.png} \end{center} \end{frame} \section{Further Resources} \begin{frame}{More Info} \begin{enumerate} \item \texttt{man 3 readline} \item \texttt{man 3 history} \item \texttt{pydoc readline} \item RTFM: Read The \emph{Fine} Manual \end{enumerate} \end{frame} { \setbeamercolor{background canvas}{bg=csmblue} \begin{frame} \begin{center} \Huge\headingfont \color{white}{Questions?} \end{center} \end{frame} } \end{document}