Emacs Tips n Tricks for Everybody

This web-page is not yet complete. Several pieces of LISP-code require explanations — I'll add them as I get time.

To try out a code snippet, just add it to your .emacs, re-start emacs and see if any error messages appear (visit the *messages* window in emacs. Alternately, if you're familiar with the basic syntax of LISP, you could position your cursor after a closing parenthesis (the end of a LISP expression) and press C-x C-e (ctrl-x followed by ctrl-e). This would "evaluate" the expression, thereby "executing" the command. Of course, to execute the command automatically every time you start emacs, you would have to add it to your .emacs.

Removing Annoyances

(setq inhibit-startup-message t) will inhibit startup messages.

(setq require-final-newline t) will make the last line end in a carriage return.

(fset 'yes-or-no-p 'y-or-n-p) will allow you to type just "y" instead of "yes" when you exit.

(setq next-line-add-newlines nil) will disallow creation of new lines when you press the "arrow-down key" at end of the buffer.

General Embellishments

(setq modifier-keys-are-sticky t) will make ctrl, shift, alt "sticky" in xemacs. (Does anybody know how to do this in emacs?) With sticky-keys, you dont have to hold down the ctrl/shift/alt key and another key simultaneosly. For example, to type ctrl-a, you'd have to tap on the 'ctrl'-key, followed by a tap on the 'a'-key. This feature is useful for folks with sore wrists/hands.

(setq message-log-max 512) will reduce the number of messages that appear in the "*Messages*" window to 512.

(setq display-time-day-and-date t) (display-time) will make the display of date and time persistent.

(require 'paren) (show-paren-mode t) will highlight matching parentheses next to cursor.

(setq-default indent-tabs-mode nil) will introduce spaces instead of tabs by default.

(setq-default truncate-lines t) will trucate lines if they are too long.

(setq-default truncate-partial-width-windows nil) will trucate even when screen is split into multiple windows.

(require 'auto-show) (auto-show-mode 1) (setq-default auto-show-mode t) load auto-show (shows lines when cursor moves to right of long line).

(auto-show-make-point-visible) will position the cursor to end of output in shell mode.

(auto-show-make-point-visible) will position cursor to end of output in shell mode automatically.

(transient-mark-mode t) will highlight region between point and mark.

(setq query-replace-highlight t) will highlight during query.

(setq search-highlight t) highlight incremental search

(setq default-major-mode 'text-mode) will make text-mode default.

(global-font-lock-mode t t) means that we want fontification in all modes.

(setq font-lock-maximum-decoration t) denotes our interest in maximum possible fontification.

(type-break-mode) get intermittent messages to stop typing

(setq enable-recursive-minibuffers t) ;; allow recursive editing in minibuffer
(resize-minibuffer-mode 1)            ;; minibuffer gets resized if it becomes too big
(follow-mode t)                       ;; follow-mode allows easier editing of long files 

(require 'uniquify)
(setq uniquify-buffer-name-style 'reverse)

; Moving cursor down at bottom scrolls only a single line, not half page
(setq scroll-step 1)
(setq scroll-conservatively 5)
(global-set-key [delete] 'delete-char)

(set-background-color "dark slate gray")
(set-foreground-color "blanched almond")

C-mode with Fewer Key-strokes

(setq kill-whole-line t) will make "Ctrl-k" kills an entire line if the cursor is at the beginning of line -- very useful.

(setq c-hungry-delete-key t) will delete "hungrily" in C mode! Use it to see what it does -- very useful.

(setq c-auto-newline 1) will let emacs put in a "carriage-return" for you automatically after left curly braces, right curly braces, and semi-colons in "C mode" -- very useful.

(add-hook 'c-mode-common-hook
          '(lambda ()
             (setq fill-column 80)
             (setq comment-column 60)
             (modify-syntax-entry ?_ "w")       ; now '_' is not considered a word-delimiter
             (c-set-style "ellemtel")           ; set indentation style
             (local-set-key [(control tab)]     ; move to next tempo mark

(setq auto-mode-alist
      (append '(("\\.h$" . c++-mode)) auto-mode-alist))

(global-set-key [f12]         'dabbrev-expand)
(define-key esc-map [f12]     'dabbrev-completion)
With the above global key-bindings, it is possible to press 'f12' (you could change this to any other key you want) and automagically, a partial string gets expanded. For example, if you have typed "mylon" and press 'F12', "mylon" will get replaced by "MyLongIdentifierName" if that string exists somewhere in your set of buffers.

;; "funky stuff" ;; proceed with caution

(setq my-key-pairs
      '((?! ?1) (?@ ?2) (?# ?3) (?$ ?4) (?% ?5)
        (?^ ?6) (?& ?7) (?* ?8) (?( ?9) (?) ?0)
        (?- ?_) (?\" ?') (?{ ?[) (?} ?])         ; (?| ?\\)
(defun my-key-swap (key-pairs)
  (if (eq key-pairs nil)
      (message "Keyboard zapped!! Shift-F10 to restore!")
        (keyboard-translate (caar key-pairs)  (cadar key-pairs)) 
        (keyboard-translate (cadar key-pairs) (caar key-pairs))
        (my-key-swap (cdr key-pairs))

(defun my-key-restore (key-pairs)
  (if (eq key-pairs nil)
      (message "Keyboard restored!! F10 to Zap!")
        (keyboard-translate (caar key-pairs)  (caar key-pairs))
        (keyboard-translate (cadar key-pairs) (cadar key-pairs))
        (my-key-restore (cdr key-pairs))
The above function "swaps" the numeric keys with the respective characters (e.g., '*' with '8' and '(' with '9'). Why? It appears to me that the upper row of characters is used more often in C/C++. So we need fewer key-strokes (the 'Shift' is avoided) with the swappings in place. 'F10' and 'Shift-F10' allow u to toggle between these key-swaps.

;; "funky stuff" ;; proceed with caution

(defun my-editing-function (first last len)
  (if (and (boundp 'major-mode)
           (member major-mode (list 'c-mode 'c++-mode 'gud-mode 'fundamental-mode 'ruby-mode))
           (= len 0)
           (> (point) 4)
           (= first (- (point) 1)))      
       ((and (string-equal (buffer-substring (point) (- (point) 2)) "__")
             (not (string-equal (buffer-substring (point) (- (point) 3)) "___")))
        (progn (delete-backward-char 2) (insert-char ?- 1) (insert-char ?> 1)))

       ((string-equal (buffer-substring (point) (- (point) 3)) "->_")
        (progn (delete-backward-char 3) (insert-char ?_ 3)))
       ((and (string-equal (buffer-substring (point) (- (point) 2)) "..")
             (not (string-equal (buffer-substring (point) (- (point) 3)) "...")))
        (progn (delete-backward-char 2) (insert-char ?[ 1) (insert-char ?] 1) (backward-char 1))) 

       ((and (> (point-max) (point))
             (string-equal (buffer-substring (+ (point) 1) (- (point) 2)) "[.]"))
        (progn (forward-char 1) (delete-backward-char 3) (insert-char ?. 1) (insert-char ?. 1) ))
(add-hook 'after-change-functions 'my-editing-function)
The function above is funky but useful. Having swapped the pairs ('[', '{'), ('-', '_') and (']', '}'), in order to type "->", we need to type four characters ('Shift' followed by '-' followed by 'Shift' followed by '>'). With the above code, all you need to type is two underscores: '__'). Automagically, they are converted into '->'). Similarly, two successive dots '..' are translated into '[]' (for array indexing). I find that these combinations improve my code-typing speed significantly.

shell-mode Improvements

(setq comint-buffer-maximum-size 10240) set maximum-buffer size for shell-mode (useful if some program that you're debugging spews out large amounts of output).

(add-hook 'comint-output-filter-functions 'comint-truncate-buffer) will truncate shell buffer to comint-buffer-maximum-size.

(add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt) will disalllow passwords to be shown in clear text (this is useful, for example, if you use the shell and then, login/telnet/ftp/scp etc. to other machines).

(add-hook 'comint-output-filter-functions 'comint-strip-ctrl-m) will remove ctrl-m from shell output.

(add-hook 'shell-mode-hook
	  '(lambda ()
             (local-set-key [home]        ; move to beginning of line, after prompt  
	     (local-set-key [up]          ; cycle backward through command history
                            '(lambda () (interactive)
                               (if (comint-after-pmark-p)
                                   (comint-previous-input 1)
                                 (previous-line 1))))
	     (local-set-key [down]        ; cycle forward through command history
                            '(lambda () (interactive)
                               (if (comint-after-pmark-p)
                                   (comint-next-input 1)
                                 (forward-line 1))))

;; shell-toggle.el stuff

(autoload 'shell-toggle "shell-toggle" 
  "Toggles between the *shell* buffer and whatever buffer you are editing." t) 
(autoload 'shell-toggle-cd "shell-toggle" 
  "Pops up a shell-buffer and insert a \"cd \" command." t)
(global-set-key [f4] 'shell-toggle)
(global-set-key [C-f4] 'shell-toggle-cd)

;; protbuf.el
(load "protbuf")
(protect-process-buffer-from-kill-mode 1 "shell-first")
;; ssh.el

(load "ssh") will load ssh.el

gud-mode (debugging with gdb)

(add-hook 'gud-mode-hook
	  '(lambda ()
             (local-set-key [home]        ; move to beginning of line, after prompt
	     (local-set-key [up]          ; cycle backward through command history
                            '(lambda () (interactive)
                               (if (comint-after-pmark-p)
                                   (comint-previous-input 1)
                                 (previous-line 1))))
	     (local-set-key [down]        ; cycle forward through command history
                            '(lambda () (interactive)
                               (if (comint-after-pmark-p)
                                   (comint-next-input 1)
                                 (forward-line 1))))

Global key-bindings (Hot-keys)

;; global key bindings
(global-set-key [C-delete]    'kill-word)
(global-set-key [C-backspace] 'backward-kill-word)
(global-set-key [home]        'beginning-of-line)
(global-set-key [end]         'end-of-line)
(global-set-key [C-home]      'beginning-of-buffer)
(global-set-key [C-end]       'end-of-buffer)
(global-set-key [f1]          'find-file)
(global-set-key [f2]          '(lambda () (interactive) (progn (fill-paragraph 1) (save-buffer))))
(global-set-key [f3]          'manual-entry)
(global-set-key [f4]          'shell)
(global-set-key [f5]          '(lambda () (interactive) (kill-buffer (current-buffer))))
(global-set-key [S-f7]        'compile)
(global-set-key [f7]          'next-error)
(global-set-key [C-f7]        'kill-compilation)
(global-set-key [f8]          'other-window)
(global-set-key [S-right]     'other-window)
(global-set-key [S-left]      'other-window)
(global-set-key [f9]          'save-buffer)
(global-set-key [f10]         '(lambda () (interactive) (my-key-swap    my-key-pairs)))
(global-set-key [S-f10]       '(lambda () (interactive) (my-key-restore my-key-pairs)))
(global-set-key [f12]         'dabbrev-expand)
(define-key esc-map [f12]     'dabbrev-completion)
; for my pc @ home
(global-set-key [M-backspace] 'dabbrev-expand)
;; (global-set-key [S-f12]       'my-vm-without-new-frame)
(global-set-key [C-f12]       'save-buffers-kill-emacs)
;; some machines have SunF37 instead of f12
(global-set-key [SunF37]      'dabbrev-expand)
(define-key esc-map [SunF37]  'dabbrev-completion)
;; (global-set-key [S-SunF37]    'my-vm-without-new-frame)
(global-set-key [C-SunF37]    'save-buffers-kill-emacs)
(global-set-key "\C-x\C-b"    'electric-buffer-list)
; Make Emacs use "newline-and-indent" when you hit the Enter key so
; that you don't need to keep using TAB to align yourself when coding.
(global-set-key "\C-m"        'newline-and-indent)
; capitalize current word (for example, C constants)
(global-set-key "\M-u"        '(lambda () (interactive) (backward-word 1) (upcase-word 1)))

;; pager.el stuff
(require 'pager)
(global-set-key "\C-v"     'pager-page-down)
(global-set-key [next]     'pager-page-down)
(global-set-key "\ev"      'pager-page-up)
(global-set-key [prior]    'pager-page-up)
(global-set-key '[M-up]    'pager-row-up)
(global-set-key '[M-kp-8]  'pager-row-up)
(global-set-key '[M-down]  'pager-row-down)
(global-set-key '[M-kp-2]  'pager-row-down)

Using Abbreviations and Auto-Capitalization

;; Abbreviations

;; M-x edit-abbrevs        allows editing of abbrevs
;; M-x write-abbrev-file   will save abbrevs to file
;; C-x a i l               allows us to define a local abbrev
;; M-x abbrev-mode         turns abbrev-mode on/off

;; set name of abbrev file with .el extension
(setq abbrev-file-name "~/.abbrevs.el")

(setq-default abbrev-mode t)
(setq save-abbrevs t)
;; we want abbrev mode in all modes (does not seem to work)
;; (abbrev-mode 1)
;; quietly read the abbrev file
;; (quietly-read-abbrev-file)
(if (file-exists-p  abbrev-file-name) (quietly-read-abbrev-file abbrev-file-name))

; auto-capitalize stuff
(autoload 'auto-capitalize-mode "auto-capitalize"
  "Toggle `auto-capitalize' minor mode in this buffer." t)
(autoload 'turn-on-auto-capitalize-mode "auto-capitalize"
  "Turn on `auto-capitalize' minor mode in this buffer." t)
(autoload 'enable-auto-capitalize-mode "auto-capitalize"
  "Enable `auto-capitalize' minor mode in this buffer." t)
(add-hook 'text-mode-hook 'turn-on-auto-capitalize-mode)
(setq auto-capitalize-words '("I" "Rajeev" "Nautiyal" "Sanjeev" "Uma"))

Latex Improvements

(setq auto-mode-alist (cons '("\\.tex$" . latex-mode) auto-mode-alist)) means that .tex files should be handled by latex-mode.

(setq tex-mode-hook
   '(lambda ()
      (auto-fill-mode 1)

(setq latex-mode-hook
   '(lambda ()
      (auto-fill-mode 1)

(autoload 'reftex-mode    "reftex" "RefTeX Minor Mode" t)
(autoload 'turn-on-reftex "reftex" "RefTeX Minor Mode" t)

(add-hook 'LaTeX-mode-hook 'turn-on-reftex) ; with AUCTeX LaTeX mode
;  (add-hook 'latex-mode-hook 'turn-on-reftex)) ; with Emacs latex mode

(setq reftex-enable-partial-scans t)
(setq reftex-save-parse-info t)
(setq reftex-use-multiple-selection-buffers t)

;; To integrate with AUCTeX, use 
(setq reftex-plug-into-AUCTeX t)

text-mode Improvements

(add-hook 'text-mode-hook
          '(lambda ()
             (auto-fill-mode 1)

ruby-mode Improvements

    (autoload 'ruby-mode "ruby-mode"
      "Mode for editing ruby source files")
    (setq auto-mode-alist
          (append '(("\\.rb$" . ruby-mode)) auto-mode-alist))
    (setq interpreter-mode-alist (append '(("ruby" . ruby-mode))
    (autoload 'run-ruby "inf-ruby"
      "Run an inferior Ruby process")
    (autoload 'inf-ruby-keys "inf-ruby"
      "Set local key defs for inf-ruby in ruby-mode")
    (add-hook 'ruby-mode-hook
          '(lambda ()

(autoload 'rubydb "rubydb3x" "Ruby debugger" t)

VM-mode Improvements

; ----- VM --------
(autoload 'vm "~/emacs/vm" "Start VM on your primary inbox." t)
(autoload 'vm-visit-folder "~/emacs/vm" "Start VM on an arbitrary folder." t)
(autoload 'vm-mail "~/emacs/vm" "Send a mail message using VM." t)
(autoload 'vm-submit-bug-report "~/emacs/vm" "Send a bug report about VM." t)
(setq vm-preview-lines nil)
(setq vm-highlighted-header-regexp '"^From\\|^Subject")
(setq vm-preview-read-messages t)

Emacs-lisp-mode Improvements

(add-hook 'emacs-lisp-mode-hook
          '(lambda ()
             (modify-syntax-entry ?- "w")       ; now '-' is not considered a word-delimiter

tempo-mode for Faster Coding in C/C++

;; This is a way to hook tempo into cc-mode
(defvar c-tempo-tags nil
  "Tempo tags for C mode")
(defvar c++-tempo-tags nil
  "Tempo tags for C++ mode")

;;; C-Mode Templates and C++-Mode Templates (uses C-Mode Templates also)
(require 'tempo)
(setq tempo-interactive t)

(add-hook 'c-mode-hook
          '(lambda ()
             (local-set-key [f11] 'tempo-complete-tag)
             (tempo-use-tag-list 'c-tempo-tags)
(add-hook 'c++-mode-hook
          '(lambda ()
             (local-set-key [f11] 'tempo-complete-tag)
             (tempo-use-tag-list 'c-tempo-tags)
             (tempo-use-tag-list 'c++-tempo-tags)

;;; Preprocessor Templates (appended to c-tempo-tags)

(tempo-define-template "c-include"
		       '("include <" r ".h>" > n
		       "Insert a #include <> statement"

(tempo-define-template "c-ifdef"
		       '("ifdef " (p "ifdef-clause: " clause) > n> p n
			 "#else /* !(" (s clause) ") */" n> p n
			 "#endif /* " (s clause)" */" n>
		       "Insert a #ifdef #else #endif statement"

(tempo-define-template "c-ifndef"
		       '("ifndef " (p "ifndef-clause: " clause) > n
			 "#define " (s clause) n> p n
			 "#endif /* " (s clause)" */" n>
		       "Insert a #ifndef #define #endif statement"
;;; C-Mode Templates

(tempo-define-template "c-if"
		       '(> "if (" (p "if-clause: " clause) ")" n>
                           "{" > n>
                           > r n
                           "}" > n>
		       "Insert a C if statement"

(tempo-define-template "c-else"
		       '(> "else" n>
                           "{" > n>
                           > r n
                           "}" > n>
		       "Insert a C else statement"

(tempo-define-template "c-if-else"
		       '(> "if (" (p "if-clause: " clause) ")"  n>
                           "{" > n
                           > r n
                           "}" > n
                           "else" > n
                           "{" > n>
                           > r n
                           "}" > n>
		       "Insert a C if else statement"

(tempo-define-template "c-while"
		       '(> "while (" (p "while-clause: " clause) ")" >  n>
                           "{" > n
                           > r n
                           "}" > n>
		       "Insert a C while statement"

(tempo-define-template "c-for"
		       '(> "for (" (p "for-clause: " clause) ")" >  n>
                           "{" > n
                           > r n
                           "}" > n>
		       "Insert a C for statement"

(tempo-define-template "c-for-i"
		       '(> "for (" (p "variable: " var) " = 0; " (s var)
                           " < "(p "upper bound: " ub)"; " (s var) "++)" >  n>
                           "{" > n
                           > r n
                           "}" > n>
		       "Insert a C for loop: for(x = 0; x < ..; x++)"

(tempo-define-template "c-main"
		       '(> "int main(int argc, char *argv[])" >  n>
                           "{" > n>
                           > r n
                           > "return 0 ;" n>
                           > "}" > n>
		       "Insert a C main statement"

(tempo-define-template "c-if-malloc"
		       '(> (p "variable: " var) " = ("
                           (p "type: " type) " *) malloc (sizeof(" (s type)
                           ") * " (p "nitems: " nitems) ") ;" n>
                           > "if (" (s var) " == NULL)" n>
                           > "error_exit (\"" (buffer-name) ": " r ": Failed to malloc() " (s var) " \") ;" n>
		       "Insert a C if (malloc...) statement"

(tempo-define-template "c-if-calloc"
		       '(> (p "variable: " var) " = ("
                           (p "type: " type) " *) calloc (sizeof(" (s type)
                           "), " (p "nitems: " nitems) ") ;" n>
                           > "if (" (s var) " == NULL)" n>
                           > "error_exit (\"" (buffer-name) ": " r ": Failed to calloc() " (s var) " \") ;" n>
		       "Insert a C if (calloc...) statement"

(tempo-define-template "c-switch"
		       '(> "switch (" (p "switch-condition: " clause) ")" n>
                           "{" >  n>
                           "case " (p "first value: ") ":" > n> p n
                           "break;" > n> p n
                           "default:" > n> p n
                           "break;" > n
                           "}" > n>
		       "Insert a C switch statement"

(tempo-define-template "c-case"
		       '(n "case " (p "value: ") ":" > n> p n
			   "break;" > n> p
		       "Insert a C case statement"

(tempo-define-template "c++-class"
		       '("class " (p "classname: " class) p > n>
                         " {" > n
                         "public:" > n
                         "" > n
			 "protected:" > n
                         "" > n
			 "private:" > n
                         "" > n
			 "};" > n
		       "Insert a class skeleton"


(split-window-horizontally)   ;; want two windows at startup 
(other-window 1)              ;; move to other window
(shell)                       ;; start a shell
(rename-buffer "shell-first") ;; rename it
(other-window 1)              ;; move back to first window 
(my-key-swap my-key-pairs)    ;; zap keyboard
The above code will split the Emacs window into two, and start the shell in one of them. The last line invokes (my-key-swap my-key-pairs) which toggles some keys (search for "my-key-swap" on this page to locate its definition).

Last update: 11 Mar 2004 by Gurmeet Singh Manku