23

At times while working on a code, it's useful to quickly open a *scratch* buffer to paste a snippet from that code file.

If I am working on a Perl script, I would like to quickly open a *scratch* buffer with in cperl-mode. It would also be nice to quickly jump back to the code buffer I was originally working in.

Malabarba
  • 22,878
  • 6
  • 78
  • 163
Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179

1 Answers1

25

It will be convenient to bind the below function to a key binding of your choice. If you are currently working on a FILE buffer, calling the below function will toggle between FILE's major-mode specific *scratch* buffer called *scratch-MAJOR-MODE* and the FILE buffer.

Given the example in question, if I am working on a Perl script called myperl.pl, calling this function will toggle between myperl.pl and *scratch-cperl-mode*.

(defun modi/switch-to-scratch-and-back (&optional arg)
  "Toggle between *scratch-MODE* buffer and the current buffer.
If a scratch buffer does not exist, create it with the major mode set to that
of the buffer from where this function is called.

        COMMAND -> Open/switch to a scratch buffer in the current buffer's major mode
    C-0 COMMAND -> Open/switch to a scratch buffer in `fundamental-mode'
    C-u COMMAND -> Open/switch to a scratch buffer in `org-mode'
C-u C-u COMMAND -> Open/switch to a scratch buffer in `emacs-elisp-mode'

Even if the current major mode is a read-only mode (derived from `special-mode'
or `dired-mode'), we would want to be able to write in the scratch buffer. So
the scratch major mode is set to `org-mode' for such cases.

Return the scratch buffer opened."
  (interactive "p")
  (if (and (or (null arg)               ; no prefix
               (= arg 1))
           (string-match-p "\\*scratch" (buffer-name)))
      (switch-to-buffer (other-buffer))
    (let* ((mode-str (cl-case arg
                       (0  "fundamental-mode") ; C-0
                       (4  "org-mode") ; C-u
                       (16 "emacs-lisp-mode") ; C-u C-u
                       ;; If the major mode turns out to be a `special-mode'
                       ;; derived mode, a read-only mode like `help-mode', open
                       ;; an `org-mode' scratch buffer instead.
                       (t (if (or (derived-mode-p 'special-mode) ; no prefix
                                  (derived-mode-p 'dired-mode))
                              "org-mode"
                            (format "%s" major-mode)))))
           (buf (get-buffer-create (concat "*scratch-" mode-str "*"))))
      (switch-to-buffer buf)
      (funcall (intern mode-str))   ; http://stackoverflow.com/a/7539787/1219634
      buf)))
Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
  • How could I exclude dired mode, term mode and other non editable mode for this function? – godblessfq Aug 31 '16 at 07:31
  • @godblessfq I had fixed this just recently in [my config](https://github.com/kaushalmodi/.emacs.d/blob/aff540bf918b6e94d10f2c812fdaaa06d70623e6/setup-files/setup-windows-buffers.el#L264). For now you can get that version from there. I'll update this answer when I get to a computer. – Kaushal Modi Aug 31 '16 at 23:24
  • @godblessfq I have updated the answer. Try it out and see if it works for you. – Kaushal Modi Sep 01 '16 at 15:26
  • works like a charm! – godblessfq Sep 03 '16 at 03:59