Emacs: Friend or Foe?

Frustrated with Emacs? Here's how to wrestle it into submission.
Using hooks

One problem with the above configuration is that font-lock-mode is not automatically enabled for each major mode. Including the font-lock-mode command in your startup.el file will enable this mode when Emacs first begins, but not for each new buffer that you create. In general, this is true for any Emacs minor mode; you must turn on the minor modes whenever you enter a new major mode.

What we want to do is have the font-lock-mode command be executed whenever we enter certain modes, such as C mode or Emacs LISP mode. Happily, Emacs provides “hooks” which allow you to execute functions when certain events occur.

Let's turn on several minor modes whenever we enter C mode, Emacs LISP mode, or Text mode:

(defun my-enable-minor-modes ()
   "Enables several minor modes."
   (interactive "")
   (transient-mark-mode 1)
   (font-lock-mode 1))
(add-hook 'c-mode-hook 'my-enable-minor-modes)
(add-hook 'emacs-lisp-mode-hook 'my-enable-minor-modes)
(add-hook 'text-mode-hook 'my-enable-minor-modes)

Now you should find that upon entering any of these major modes, the corresponding minor modes are enabled as well. In general, each major mode has an entry hook, named modename-hook.

Local key bindings

Instead of using global-set-key to define key bindings for all major modes, we can use define-key to set bindings for particular modes. In this way we can specify the behavior of certain keys based on the major mode that you happen to be in.

For example, I prefer that the return key indent the next line of text relative to the one above it (if the previous line is indented five spaces, the next line should be as well). To enable this feature in C mode, Emacs LISP mode, and Indented Text Mode, use the commands:

(define-key indented-text-mode-map "\C-m" 'newline-and-indent)
(define-key emacs-lisp-mode-map "\C-m" 'newline-and-indent)
(define-key c-mode-map "\C-m" 'newline-and-indent)

Each mode has a modename-map associated with it, which specifies the key bindings for that mode. As you may have guessed, newline-and-indent is the Emacs function which does a newline followed by a relative indent.

When editing files, Emacs usually determines the mode to use from the filename extension. If I were to edit a new file called clunker.c, C mode would be used as the default. However, when unable to make a decision, Emacs uses Fundamental mode. I prefer to use Indented Text mode instead, which is enabled with the command:

(setq default-major-mode 'indented-text-mode)

Local key bindings can be used for more interesting tasks than those demonstrated above. For example, the command M-x compile will issue the command make -k (by default) in the current directory, thereby compiling whatever code you may have been working on. Output and error messages from the make command are displayed in a separate window. You can select error messages from the compilation buffer, in which case Emacs will automatically open up the corresponding source file and jump to the line containing the error. In all, this makes editing, compiling, and debugging programs much more efficient; you can do literally everything within Emacs.

In order to automate the process of saving the current source file and issuing make, we can bind the key sequence C-c C-c to a new function; let's call it my-save-and-compile. The code looks like this:

(defun my-save-and-compile ()
   "Save current buffer and issue compile."
   (interactive "")
   (save-buffer 0)
   (compile "make -k"))
(define-key c-mode-map "\C-c\C-c" 'my-save-and-compile)

The save-buffer command is used to save the current source file, and compile is issued with the command make -k. Now, with two simple keystokes you can fire your source file off to the compiler, and wait for the error messages to roll in. Without the my-save-and-compile function, you have to save the source file (using C-x C-s) and issue M-x compile by hand.

Of course, to use this feature you'll have to create a Makefile in the directory where your source files live. (The make command is issued in the directory containing the source file in question.) Creating Makefiles is another issue altogether. A future issue of Linux Journal will discuss this subject, but in the meantime there are several sources of information about make. The book Managing Projects with make from O'Reilly and Associates is a good place to start, as is the GNU make Manual, which covers the version of make available on Linux systems.

Also note that compile will first prompt you to save any modified buffers. If you modify only one buffer at a time, my-save-and-compile saves it for you. We could have my-save-and-compile save all modified buffers, but you may not want that to happen automatically behind your back.

As we mentioned, the compile function will open a new window containing messages from the make command. From this buffer, you can select error messages for Emacs to automatically jump to, allowing you to fix the problem and move on. If you are running Emacs under X, clicking on an error message with the second mouse button will take you to the line containing the error. Otherwise, you can move point to the error message (in the compilation buffer), and use C-c C-c (don't be confused by the multiple meanings of this key sequence). Alternately, you can use the function next-error to visit the next error message. In my startup.el I have this function bound to M-n in C mode (which, by now, you should know how to do).



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Thanks - nice article for an

eyolf's picture

Thanks - nice article for an new emacs convert (from vi...)
A couple of typos in the code for multiple key sequences:

; Various keys for nuking text (global-unset-key "\C-d")
(global-set-key "\C-d g" 'my-nuke-to-end)
(global-set-key "\C-d\C-d" 'my-nuke-line)

which I believe should be:

; Various keys for nuking text
(global-unset-key "\C-d")
(global-set-key "\C-dg" 'my-nuke-to-end)
(global-set-key "\C-d\C-d" 'my-nuke-line)

At least that worked for me.

Compare with this..

ILoveEmacs's picture

Ever tried viper mode?