I am writing a simple package for myself to try and learn some elisp - and to begin extending Emacs for my own personal workflow. This function processes the current buffer contents with a command line utility and pipes the output into a temporary buffer. This is what I have so far, and it processes the buffer as desired

(defun doStuff ()
  (with-output-to-temp-buffer "*stuffed*"
     (..cli stuff here...)
     (pop-to-buffer "*stuffed*")

What I'm looking for is a way to replace the contents of the current buffer, in such a way that if I press "q" it will revert to the original buffer contents. Can anyone give me some pointers on how I might go about that?

  • 3
    Rather than revert the contents of a non-file-visiting-buffer (e.g. one big undo), it would probably be better to create a different buffer to hold the new information. Programmatically, "q" would be choosing one version over the other. You may also wish to look at cloning the original buffer if you need the data it contains.
    – lawlist
    Jul 31, 2015 at 0:05
  • 2
    Along the lines of what @lawlist said, you can set the mode of your *stuffed* buffer to (special-mode). Then when you hit q in that buffer, that buffer window will quit without killing the buffer (default binding in special-mode-map). Hitting C-u q will quit that window and kill that buffer. Jul 31, 2015 at 1:44
  • @kaushalmodi is (special-mode) a built in mode? would either of you care to elaborate on your comments to in the form of an answer?
    – sunwukung
    Jul 31, 2015 at 6:49
  • 1
    A note: please follow Emacs Lisp naming conventions, so doStuff should be do-stuff or rather my-package-do-stuff. This will save you time fixing it later if you want to put it into some package archive after all. Jul 31, 2015 at 7:50

1 Answer 1


Here is a variation of your implementation:

(defun my-do-stuff ()
  (let ((cmd "your cmd here")
        (temp-buf-name "*stuffed*"))
    ;; Create a buffer `temp-buf-name' and run the shell command in it
    (get-buffer-create temp-buf-name)
    (let ((message-log-max nil)) ; Don't clutter *Messages* buffer (optional)
      (shell-command cmd temp-buf-name))
    ;; Switch to the `temp-buf-name' buffer
    (switch-to-buffer-other-window temp-buf-name)
    ;; Set its major mode to `special-mode'
    (special-mode) ; a read-only major mode
    ;; As you are now in the `temp-buf-name' buffer, you can do the below:
    ;; - hit `q' to quit the current window *without* killing `temp-buf-name'
    ;; - hit `C-u q' to quit the current window *and* kill `temp-buf-name'

The special-mode-map default bindings are defined in simple.el:

(defvar special-mode-map
  (let ((map (make-sparse-keymap)))
    (suppress-keymap map)
    (define-key map "q" 'quit-window)
    (define-key map " " 'scroll-up-command)
    (define-key map [?\S-\ ] 'scroll-down-command)
    (define-key map "\C-?" 'scroll-down-command)
    (define-key map "?" 'describe-mode)
    (define-key map "h" 'describe-mode)
    (define-key map ">" 'end-of-buffer)
    (define-key map "<" 'beginning-of-buffer)
    (define-key map "g" 'revert-buffer)
  • thanks, that did the trick. i'm trying to figure out how to apply syntax highlighting to the output - i'm transpiling some JS - i guess i'd need to make a minor mode to handle it instead of special?
    – sunwukung
    Aug 1, 2015 at 10:37
  • If the syntax highlighting is for some known language, then you can enable that language's major mode, make the buffer read-only and then bind q as you want only in that buffer. Aug 1, 2015 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.