Basic Unix/C workflow

This chapter uses the source code of the GNU Readline library as an example. You can grab it (by cding to a directory of your choice and then issuing the shell command git clone git://git.savannah.gnu.org/readline.git[1]) or follow along using your own C or C++ code.

c-mode

Start Emacs and open (C-x C-f) the file readline/examples/rl.c.

 

-U:--- *scratch* All L1 (Lisp Interaction)----------------------------------------

Find file: .../readline/examples/rl.c

The minibuffer

If you accidentally invoke C-x C-f again, or any other command that is expecting some kind of input from you, remember you can cancel by making sure the minibuffer has focus and pressing C-g.

Because this is a C source file, Emacs has automatically activated an editing mode called “c-mode”, which provides some custom keybindings and knowledge of C indentation rules and syntax highlighting. We will study c-mode in depth later on.

shell

Run the shell command (that is, M-x shell RET).

This creates a new buffer running the shell specified by environment variable SHELL.[2] The buffer is called *shell* (the asterisks are part of the name, so you have to type them when switching to this buffer with C-x b).

cd to the readline directory and run the following shell commands:

./configure
make

The *shell* buffer’s editing mode is shell-mode. You can run almost any shell command inside shell-mode; the exceptions are anything that requires real terminal support, like pagers (less) and curses-based programs. You lose bash’s readline completion and any custom bash-completion scripts, or the equivalent in your shell of choice (though Emacs provides its own command history and tab-completion). For these reasons, I tend to have a real terminal running (outside of Emacs) for some tasks, as well as a shell in Emacs. (Trying to do everything in Emacs reaches a point of diminishing returns.)

The big advantage of shell-mode is that all output is available for you to search through, copy, paste, and otherwise act upon, all with the standard Emacs commands; you don’t have to move your hand to the mouse just to select some text.

Shell-mode adds a number of keybindings:

.../examples/rl.c

gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00) /usr/llvm-gcc-4.2/bin/../libexec/gcc/i686-apple-darwin11/4.2.1/collect2 -dynamic -dylib -dylib_compatibility_version 6 -dylib_current_version 6.2 -arch x86_64 -dylib_install_name /usr/local/lib/libhistory.6.2.dylib -dynamic -macosx_version_min 10.3 -undefined dynamic_lookup -weak_referen ce_mismatches non-weak -undefined dynamic_lookup -o libhistory.6.2.dylib -ldylib1.o -L/us r/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin11/4.2.1/x86_64 -L/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 readline$  
--:--- *shell* Bot L404 (Shell:run)------------------------------
Shell mode: Major mode for interacting with an inferior shell. RET after the end of the process' output sends the text from the end of process to the end of the current line. RET before end of process output copies the current line minus the prompt to the end of the buffer and sends it (C-c RET just copies the current line). M-x send-invisible reads a line of text without echoing it, and sends it to the shell. This is useful for entering passwords. Or, add the function `comint-watch-for-password-prompt' to `comint-output-filter-functions'.
-U:%%- *Help* Top L1 (Help View)------------------------------

Type C-x 1 to delete the help window, C-M-v to scroll help.

The Help window

Type C-h m and read the documentation on shell-mode and its keybindings.

(For now, don’t bother reading the help text about customization—the variables and hooks shell-mode provides to modify its behavior. After shell-mode comes documentation for all the active minor modes; you don’t need to read that either.)

Of particular interest are pressing RET or C-c RET on a previous input line; C-<up> and C-<down> (or M-p and M-n) to cycle through previous commands; and M-x dirs.

Figure out how to send signals (e.g. C-c) to the shell. (Hint: search the help buffer for “interrupt” and “stop”.)

Figure out what C-M-l (that’s the letter ell) and C-c C-s do (these are both useful after running a shell command that produces a lot of output).[3]

eshell

If you’re not particularly wedded to bash or any other shell, instead of shell you might consider using eshell, a shell totally implemented in Emacs lisp. Among other advantages, running eshell on Windows doesn’t require Cygwin; you can enter lisp code or any Emacs command by name directly at the shell prompt; and you can redirect command output to the Emacs clipboard or to any open Emacs buffer.

I don’t use eshell myself, but many do. For now it might be simplest to stick with the shell you know (running inside Emacs).

ansi-term

The final option for running a shell under Emacs is ansi-term. This is a full terminal emulator, and it will pass most key presses directly to the program running in the terminal. This includes TAB, so it will be the shell, not Emacs, performing tab-completion for you.

C-x and C-c are still processed by Emacs; for M-x you’ll have to type C-x M-x. You can switch from “raw” character mode to “line” mode to get normal Emacs behavior back (e.g. for moving the cursor around so you can copy some previous output); nothing will be sent to the terminal until you press return.

To find out how, you can’t use C-h m because C-h is passed to the shell (where it probably means backspace). Instead of C-h use <f1>, or invoke describe-mode by name.

shell-command

To run a one-off shell command without opening a full shell buffer, use shell-command (M-!).

M-! date RET

shell-command-on-region (M-|) is similar but sends the current region to the shell command’s standard input. Let’s use it to calculate the line count of rl.c’s main function:

Switch to buffer rl.c (with C-x b).

Move the point to the main function (by searching with C-s). Now move the point so that it is directly on the main function’s opening { bracket.

Press C-SPC to set the mark.

Press C-M-f to move point forward to the matching } bracket. The region (the area between the mark and the point) now covers the full body of main.

M-| wc -l RET

printf ("%s\n", temp); exit (0); }
--:--- rl.c Bot L158 Git-master (C/l Abbrev)-----------------------------------

Shell command on region: wc -l

If you forget the names of these commands, type M-x shell TAB TAB.

Read the help for shell-command-on-region. You can look it up by keybinding (C-h k) or by function name (C-h f).

The help for this one is pretty long, but the important information is near the top. Ignore the paragraph on coding systems, and everything about noninteractive arguments (which are for calling this function from lisp scripts, as opposed to interactively like we have been doing).

The sentence “Prefix arg means replace the region with [the output of the shell command]” refers to providing a numeric argument to the command. You’ll remember numeric arguments from the tutorial. In this case the value of the argument doesn’t matter, so M-2 M-| or C-u M-| will do.

Try it!

 

--:**- rl.c Bot L158 Git-master (C/l Abbrev)-----------------------------------

Unsaved modifications indicator

And now undo (C-/) what you’ve done to the buffer. Note the modeline indicator when the buffer has unsaved modifications.

sh-mode

Open the file readline/configure.

If you are not particularly comfortable with shell scripting, I apologize for dumping you into a 12,000-line programmatically-generated script, but it’s the closest one I had for an example.

The mode for editing shell scripts is sh-mode (as opposed to shell-mode for running an interactive shell session, which we’ve seen already). If Emacs didn’t figure out that the file is a shell script (perhaps it’s missing the hash-bang interpreter directive on the first line) you can enter sh-mode with, you guessed it, M-x sh-mode.

I don’t really have much to say about sh-mode. It will do syntax highlighting and indentation for a variety of shells; and it provides keybindings to run the script, and to insert certain shell constructs (case statements, for loops, etc.) with the correct syntax for the current shell. If Emacs gets it wrong (again with the missing hash-bang!) you can tell Emacs which shell to use.

By now you know where to find out how.

Info documentation

Back in the configure script, invoke info-lookup-symbol and when prompted enter test.

Assuming that the Info documentation for the bash shell is correctly installed on your system (which should be the case for any Linux or OS X system, at least) you will see an Info window showing the bash manual at the very line for the test command.

Follow the link to “Bash Conditional Expressions”. If you don’t want to use the mouse, TAB moves the point to the next link and RET does the obvious thing.

As usual, C-h m will show all the keybindings for info mode. For once, though, don’t bother remembering all the keybindings, nor reading through the rather tedious Info tutorial. All you need to know is:

As you can see from the Info directory, there are many Info manuals, including manuals for Emacs itself, an Emacs Lisp reference and intro, and manuals for the more complex Emacs editing modes like cc-mode.

I can’t overstate how useful the Info documentation is. If you’re maintaining a Makefile you can look up the meaning of esoteric symbols like $@. Need to do some socket programming? In a later chapter we will install the Info manuals for glibc (the GNU implementation of the Unix standard library).

info-lookup-symbol uses the mode of the current buffer to determine which manual to look in. Sometimes it can’t tell, so it will prompt you: Enter sh-mode or makefile-mode or c-mode or whatever (TAB to show all possible options). With a C-u prefix, info-lookup-symbol will always ask.

compile

Switch to buffer rl.c (with C-x b) if necessary.

Move the point to the main function (by searching with C-s). Introduce a deliberate compilation error just after main’s opening { bracket, as in the example below, and save your change.

M-x compile (and accept the default shell command of make -k).

rl.c

int main (argc, argv) int argc; char **argv; { failhere  char *temp, *prompt; struct stat sb; int opt, fd, nch; FILE *ifp;
--:--- rl.c 59% L84 Git-master (C/l Abbrev)-----------------------------------
make -k rm -f rl.o gcc -DHAVE_CONFIG_H -DREADLINE_LIBRARY -DRL_LIBRARY_VERSION='"6.2"' -I. -I.. -I.. -g -O -c rl.c rl.c: In function ‘main’: rl.c:84: error: ‘failhere’ undeclared (first use in this function) rl.c:84: error: (Each undeclared identifier is reported only once rl.c:84: error: for each function it appears in.) rl.c:85: error: expected ‘;’ before ‘char’ rl.c:97: error: ‘prompt’ undeclared (first use in this function) rl.c:150: error: ‘temp’ undeclared (first use in this function)
-U:%*- *compilation* Top L1 (Compilation:exit [2])-----------------------------------

Compilation exited abnormally with code 2

With the active cursor still in the rl.c window, type C-x 0 (zero) to maximize the *compilation* window.

(C-x 1, which you learned in the tutorial, hides all windows except the currently selected one; C-x 0 does the opposite.)

While you’re at it, try out C-x 2 and C-x 3. C-x o (the letter oh) cycles between windows.

Anyway, back to the *compilation* window. Compilation-mode has its own special keybindings, of course:

Get help on compilation-mode and its keybindings (C-h m). Good news: the help for this mode is quite short. Again, don’t bother reading the help for all the active minor modes, unless you want to.

Try out the keybindings for compilation-next-error and compilation-previous-error. If next-error-follow-minor-mode sounded intriguing, try that out too.

The compilation command is run from the buffer’s associated directory; normally this is the directory containing the buffer’s file. To run make on a different Makefile, you could specify the -C (--directory) or -f (--makefile) make options; or you can change the buffer’s default directory with M-x cd before M-x compile.

rgrep

To search for all occurrences of a string (or regular expression) in a project, use rgrep.[4] This puts the matches in a new buffer, which you can navigate just like the compilation buffer (in fact, grep-mode inherits its functionality and keybindings from compilation-mode).

Use rgrep to search the readline source (*.[ch] files) for “rl_insert_comment” (make sure you search in the readline directory, not in readline/examples).

You can control the exact grep command line used: Read the documentation for rgrep to find out how, or use grep or grep-find instead. The C-h f documentation is an adequate reference, but the Info manual (C-h F rgrep) provides a better introduction.

vc

Emacs has a set of commands, all starting with “vc-”, that provide a consistent interface to various version control systems. The readline files we are using in this tutorial are in a git repository, but the basic commands are the same for subversion or cvs. More advanced commands (such as altering repository settings, or pushing and pulling to remote repositories in git and other distributed vc systems) you will still have to do outside of Emacs.

Switch to buffer rl.c (with C-x b) if necessary.

(If you find yourself missing clickable tabs for switching between buffers, remember that C-x b is more scalable—it works better when you have hundreds of buffers open. Later on we will see how to save a lot of typing under C-x b.)

rl.c probably has changes from when we were messing with it earlier. Invoke vc-revert to, well, revert it to the latest version in the repository.

Now for argument’s sake, let’s say we find rl.c’s documentation for the “-u” command-line flag somewhat confusing:

Find (with C-s) both instances of the documentation for “-u” and replace the word “unit” with “fd”. Save your changes.

*vc-diff*

diff --git a/examples/rl.c b/examples/rl.c index 845a4b1..7bfb932 100644 --- a/examples/rl.c +++ b/examples/rl.c @@ -2,7 +2,7 @@ * rl - command-line interface to read a line from the standard input * (or another fd) using readline. * - * usage: rl [-p prompt] [-u unit] [-d default] [-n nchars] + * usage: rl [-p prompt] [-u fd] [-d default] [-n nchars] */ /* Copyright (C) 1987-2009 Free Software Foundation, Inc. @@ -72,7 +72,7 @@ set_deftext () static void usage() {
--:%*- *vc-diff* Top L1 (Diff from rl.c)-----------------------------------

You can run the command `vc-diff' with C-x v =

Ask Emacs to show you a diff of this file. (If you need a hint, it’s in the first sentence of this section.)

The diff will be shown in diff-mode, which is also used for viewing patch files. diff-mode has some useful tricks—read its documentation when you have a spare minute.

All the vc commands are bound to key sequences starting with C-x v. If you were paying attention when you invoked the diff command by its full name, you may have noticed that Emacs told you the corresponding keybinding.

Press C-x v C-h to see all keybindings starting with C-x v.

This also works with any other prefix. Try it with C-x 4—you might notice some parallels with keybindings you already know.

To commit the file, look into C-x v v (vc-next-action). Or enter vc-dir-mode with C-x v d and find out how to mark files, for performing vc- actions on multiple files at once.

vc has a (long!) section in the Emacs manual.

Personally, I prefer to use the gitk and git gui tools, or git’s command-line interface directly, for adding, staging, committing, reverting, merging, branching. But I do use the Emacs vc-diff and vc-print-log (and vc-annotate!) extensively.

Because vc is limited to the common denominator of the backend systems it supports, people have written custom modes for specific version control systems. Magit is one such mode for git; but as we haven’t yet learned how to install extensions, we’ll stick with vc. Anyway, vc can do a thing or two even magit doesn’t do—have I mentioned vc-annotate?

vc-annotate

A couple of sections ago, I asked you to grep the readline sources for “rl_insert_comment”.

Switch to the *grep* buffer if you still have it around, or do a new search.

Remember, when switching buffers with C-x b you have to enter the asterisks as part of the buffer name. (Incidentally, the asterisks are for buffers not associated with a file on disk. This is just a convention; you could always rename the *grep* buffer to something without asterisks —see rename-buffer— or save it to disk if you wanted to.)

The first hit should have been in emacs_keymap.c. Jump to that match.

Let’s find out which release of readline added the Meta-# keybinding:

*Annotate emacs_keymap.c (rev master)*

^06cd36c emacs_keymap.c /* The start of printing characters. */ f8d82ba2 emacs_keymap.c { ISFUNC, rl_set_mark }, /* Meta-SPACE */ f8d82ba2 emacs_keymap.c { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-! */ f8d82ba2 emacs_keymap.c { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-" */ f8d82ba2 emacs_keymap.c { ISFUNC, rl_insert_comment }, /* Meta-# */

M-x vc-annotate

Delete all Emacs windows other than the annotate window (you might also want to resize the frame so that it is large enough).

With point on the “Meta-#” line, press d to view the diff of the revision where this line was last changed.

Now we’re in diff-mode. It seems that this revision consisted mostly of whitespace changes. Find the exact change to “Meta-#”. You can press C-c C-w to hide whitespace-only changes in the hunk surrounding point, and n to jump to the next hunk.

Nope, this revision wasn’t it. Press q to exit the diff buffer, then a to run annotate again, starting from the revision before this line’s revision.

*vc-diff*

{ ISFUNC, (Function *)0x0 }, /* Meta-! */ { ISFUNC, (Function *)0x0 }, /* Meta-" */ - { ISFUNC, (Function *)0x0 }, /* Meta-# */ + { ISFUNC, rl_insert_comment },/* Meta-# */ { ISFUNC, (Function *)0x0 }, /* Meta-$ */ { ISFUNC, (Function *)0x0 }, /* Meta-% */

Now make sure your point is on the right line (if the new revision is different enough from the newer one, the line we’re interested in may have moved around). Then press d again, and in diff-mode n until you find the right hunk. Yes, this is the change we’re looking for!

Go back to the annotate buffer (q). Press l to view the log message for this revision. See, readline’s “Meta-#” binding dates back to version 2.1! If you want some context you can press D (that’s shift-d) to view the diff of all files changed in this revision.

Of course, annotate is more useful when the commits are more granular and the commit messages are more descriptive, with links to bug tracker entries and so on. But you get the idea.

Right now I don’t expect you to remember all these keybindings, but I do expect you to know how to find them when you need them.

ediff

ediff is a more powerful mode for viewing differences between files or revisions.

Switch to buffer rl.c if necessary.

M-x ediff-revision. Accept the default values of rl.c, its latest revision, and its current state.

This opens a new frame from which you control ediff; always make sure the ediff frame has focus when you’re giving it a command.

Press ? for help. Figure out how to step through each diff. Figure out how to show the files side-by-side. q when you’re done.

When invoking ediff-revision you can supply any two revisions, not just the latest revision and the current working copy. You can also diff any 2 buffers (ediff-buffers) or files (ediff-files).

I suggest you stay away from ediff-directories (if you want to know why, try using it).

etags

etags is a program that indexes source files and creates a TAGS file that Emacs can use to find definitions of variables, functions and types.

Run the shell command make TAGS in the readline directory (either from a shell buffer, or with M-x compile).

The Makefiles of most open-source projects include the TAGS target. For those that don’t, you can use a combination of find, xargs and etags from the shell to generate the TAGS file manually (read the man pages for those tools if you need to).

The etags you just ran was probably the one that shipped with Emacs. There’s an alternate implementation called “Exuberant ctags” that supports more languages. Install it with your package manager (e.g. port or yum install ctags) and call it with ctags -e.

Back in Emacs, invoke find-tag (M-.). Enter rl_insert_comment as the tag to find, and then the location of the TAGS file you just generated.

From the help for find-tag, figure out how to jump back to the location you were at before invoking the command, and how to find the next match if there is more than one. (You might find the documentation from C-h F find-tag clearer than that from C-h f.)

To use a different TAGS file visit-tags-table.

If you’re a C++ programmer, you’ll soon find that ctags/etags is not perfect when it comes to classes and namespaces. As a 90% solution, it’s good enough, most of the time. Hopefully someone will come up with a clang-based indexer sometime soon.

gdb

We’re going to run the rl program under the GNU debugger, gdb.

First run compile in readline and then in readline/examples.

The compilation should succeed,[5] as long as you haven’t introduced any errors in any of the source files. If you have, you know how to view and back out your changes.

M-x gdb. When prompted for the command-line to use, specify the program examples/rl as an argument to gdb: if you’re in the readline/examples directory, the command-line will look like gdb ‑‑annotate=3 ./rl. The default options for gdb may differ on your system so you may want to use them instead.

You are now running gdb inside Emacs, so the standard gdb commands apply. Let’s set a breakpoint in the readline function, start the rl program, and when we reach the breakpoint step through a few lines.

Type the following commands at the gdb prompt:

break readline
run
print rl_pending_input
next
step
backtrace
frame 1

Note how Emacs displays the corresponding source file and line in a separate window.

The above commands are all interpreted directly by the gdb program. gdb allows you to abbreviate them to r, p, n, s, bt, and f, respectively. Pressing return on an empty line repeats the previous command—useful for multiple next commands. help displays gdb’s built-in help.

For serious debugging, Emacs can open additional windows showing the current stack frames, breakpoints, local variables and registers. See the Emacs manual for details: C-h r opens the Emacs manual in the Info browser, then search for the chapter titled “GDB Graphical Interface”.

Homework

You may be feeling somewhat overwhelmed at this point. Spend a few days using Emacs as your main editor, painful though it may be, before moving on to the next chapter of this guide. If you’ve forgotten a command I’ve taught you, try to figure it out yourself (use C-h m, C-h a, C-h f, C-h k and C-h F) before looking it up here.

As part of your commitment to learning Emacs, try to run your shell within Emacs as much as possible. (If you need help configuring your shell to work well within Emacs, or configuring Emacs to work well with your shell, we will revisit shell-mode in the “General customization” chapter of this guide.)

[1]: You will need git, a source control system; the Git Book has installation instructions.

[2]: On Windows you will need a shell provided by Cygwin or similar.

[3]: These keybindings aren’t arbitrary. C-c C-s mirrors C-x C-s, which you already know for saving the entire buffer to a file (“global” keybindings tend to start with C-x, whereas C-c is a prefix for mode-specific bindings). And C-M-l performs a similar function in other editing modes—in c-mode it tries to bring into view the whole function surrounding the point. If you’re feeling overwhelmed by the number of keybindings to memorize, don’t worry; you can always find them again with C-h m.

[4]: On Windows you will need find and grep commands provided by Cygwin or similar.

[5]: I haven’t tested this on Windows, but I’m assuming that Cygwin installs the necessary compiler, headers and libraries.