8

I need to copy the contents of the current buffer to a temp buffer, set that buffer to a particular major mode to take advantage of its benefits and get the information I need back to the main logic.

Is this complete madness? And if not, what's the structure for this?

4 Answers 4

12

If you want to copy some information to another buffer, and from then on let the buffers evolve independently, you can do just that.

But if you want the other buffer to reflect the original content in real time, then Emacs provides this with indirect buffers. An indirect buffer is another buffer that has the same content as the original (modifications in one buffer are reflected in the other buffer), but different settings: a different major mode, different minor modes, different local variables, a different point, different marks, a different narrowing, etc.

So you can get a view of a part of a buffer in a different major mode, while keeping track of modifications in the original buffer and reflecting modifications back to the original buffer. First make an indirect buffer with M-x clone-indirect buffer; there's also clone-indirect-buffer-other-window which is bound to C-x 4 c (C-x 4 window prefix, and c for clone). In the cloned buffer, narrow to the region you want: select the interesting part and run C-x n n (narrow-to-region). Change the major mode as desired.

You can automate that with a command like this for interactive use:

(defun edit-region-in-foo-mode (beg end)
  (interactive "@r")
  (let ((new-buffer (clone-indirect-buffer nil t)))
    (narrow-to-region beg end)
    (foo-mode)))

For programming use:

(defmacro with-indirect-buffer-in-foo-mode (beg end &rest body)
  `(with-current-buffer (clone-indirect-buffer nil nil)
     (narrow-to-region beg end)
     (foo-mode)
     (unwind-protect
         ,body
       (kill-buffer (current-buffer)))))
9

Something like this:

(let ((old-buffer (current-buffer)))
  (with-temp-buffer
    (insert-buffer-substring old-buffer)
    (my-favourite-major-mode 1)
    (extract-needed-information)))
3
  • 2
    Was writing up almost exactly that. Just wrap that in a defun if you need to be able to call it arbitrarily Commented Oct 15, 2014 at 13:55
  • That looks pretty good. I'm going to wait a bit, just in case there exists something better to mark as accepted, but I think this is it :)
    – Trevoke
    Commented Oct 15, 2014 at 14:14
  • I was actually suggesting M-x copy-to-buffer, then I red the @legoscia answer, which is probably what you want. if the extraction process & the major mode are the same, a function will be better
    – Nsukami _
    Commented Oct 15, 2014 at 14:21
2

I liked what @Gilles wrote. I modifed what @Gilles wrote to ask the user what mode they would like to use. You can edit what I wrote to provide whatever modes you prefer or even alter the call to completing read so that it will allow you to provide a mode not provided in the default list.

(defun edit-region-in-mode (beg end)
  "Create an indirect buffer cloned from the current buffer and
  narrowed to the highlighted region. The cloned indirect buffer
  will have org-mode active. Changes to the indirect buffer will
  be updated in real time in the originating buffer. This is
  useful, for instance, when you are in a non-org-mode mode and
  want to edit table data or in a non-emacs-lisp mode and want to
  write some elisp utilizing code formatting and highlighting."
  (interactive "@r")
  (let ((new-buffer (clone-indirect-buffer nil t)))
    (narrow-to-region beg end)
    (funcall
     (intern
      (completing-read
       "Choose the mode you want to use when editing the highlighted region: "
       '(org-mode emacs-lisp-mode lisp-mode haskell-mode julia-mode
          python-mode mathematica-mode matlab-mode c++-mode))))))
1

For a similar use case, I had written an elisp function modi/switch-to-scratch-and-back that allows you to switch quickly between a buffer FILE and a *scratch* buffer having the same major-mode as the FILE buffer. The above hyperlinked function will lead you to an existing emacs SE question.

Here is how you can use that function:

  • Create a wrapper function to copy your existing buffer, create a *scratch* buffer with the same major-mode and paste the copied content.

Here is an example wrapper function

(defun copy-current-buffer-to-scratch ()
 "Copied the current buffer, open scratch, paste it there."
  (interactive)
  (kill-ring-save (point-min) (point-max))
  (modi/switch-to-scratch-and-back)
  (yank))
  • You can now bind this copy-current-buffer-to-scratch to a key if you wish and executing it will give you a *scratch* buffer with contents from your working buffer.
  • Once you are happy with the edits in the scratch buffer, you will need to manually copy the required section back to the original buffer.

This is just another way of doing what you want; you might though want to use indirect buffers that @Gilles' solution talks about. This approach is useful if you need to make some heavy edits in a temporary buffer without risking accidental saves in the original buffer till you have reached a stable solution.

An example use case is trying out experimental elisp functions before saving them to your emacs init.

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.