Search code examples
emacselisp

In emacs, how do I save without running save hooks?


I have various things set up in my 'before-save-hook. For example, I run 'delete-trailing-whitespace. This is what I want in almost all occasions.

But sometimes, I'm working on files that are shared with other people, and the file already has a bunch of trailing whitespace. If I save the file, I'll get a big diff that's pretty confusing, as my change is buried in dozens or hundreds of meaningless changes. Yes, everyone could just tell their diff tool to not show whitespace changes, but that's something that everyone has to do every time they look at the diff. I'd rather not even have the whitespace change.

Is there anything I can do to save the file without the whitespace changes, short of starting a new instance of Emacs with no init.el file, or with a modified init.el that doesn't have the hook?


Solution

  • Based on a comment discussion with @Stefan, here are two possible (untested) solutions:

    Use let:

    (defun save-buffer-without-dtw ()
      (interactive)
      (let ((b (current-buffer)))   ; memorize the buffer
        (with-temp-buffer ; new temp buffer to bind the global value of before-save-hook
          (let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook))) 
            (with-current-buffer b  ; go back to the current buffer, before-save-hook is now buffer-local
              (let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook)))
                (save-buffer)))))))
    

    Use unwind-protect:

    (defun save-buffer-without-dtw ()
      (interactive)
      (let ((restore-global
             (memq 'delete-trailing-whitespace (default-value before-save-hook)))
            (restore-local
             (and (local-variable-p 'before-save-hook)
                  (memq 'delete-trailing-whitespace before-save-hook))))
        (unwind-protect
             (progn
               (when restore-global
                 (remove-hook 'before-save-hook 'delete-trailing-whitespace))
               (when restore-local
                 (remove-hook 'before-save-hook 'delete-trailing-whitespace t))
               (save-buffer))
          (when restore-global
            (add-hook 'before-save-hook 'delete-trailing-whitespace))
          (when restore-local
            (add-hook 'before-save-hook 'delete-trailing-whitespace nil t)))))
    

    The problem with the second solution is that the order of functions in the before-save-hook may change.