'emacs only delete-trailing-whitespace while saving in programming mode

following line removes all training white space while saving.

(add-hook 'write-file-hooks 'delete-trailing-whitespace)

but I want to hook this feature only when i'm in programming mode, so i did

(defun nuke_traling ()
  (add-hook 'write-file-hooks 'delete-trailing-whitespace) 
)

(add-hook 'prog-mode-hook 'nuke_traling)

which doesn't is not stopping which are not in programming mode.



Solution 1:[1]

Making the hook variable buffer-local has been mentioned. Don't do that. Or rather, don't do it using make-local-variable.

The normal hook mechanisms have buffer-local support built in -- that's the purpose of the LOCAL argument to add-hook. When the hook is run, it runs both the global and the buffer-local values.

So taking the example code in the question, you could change it to use:

(add-hook 'write-file-hooks 'delete-trailing-whitespace nil t)

And then delete-trailing-whitespace would be called whenever write-file-hooks was run, but only in the buffers in which prog-mode-hook had run.

However there are better ways to achieve this.

I agree with Drew that you are better to test whether your mode is derived from prog-mode, and with juanleon that before-save-hook is a better hook to use. So you might do something like:

(add-hook 'before-save-hook 'my-prog-nuke-trailing-whitespace)

(defun my-prog-nuke-trailing-whitespace ()
  (when (derived-mode-p 'prog-mode)
    (delete-trailing-whitespace)))

But what I actually recommend is using either ws-trim or ws-butler to take care of this in a smarter way.

Blindly removing all trailing whitespace from a file is a great way to wind up committing loads of unrelated lines to a version-control repository. Both of the libraries mentioned will ensure that your own commits are free of trailing whitespace, without also introducing unwanted modifications elsewhere in the file.

Solution 2:[2]

write-file-hooks is obsolete since Emacs-22, replaced by write-file-functions. But this hook is a bit delicate to use (because it can also be used to perform the write), so I recommend you use before-save-hook instead. And to make it apply only to the current buffer, just pass a non-nil value for the local argument of add-hook, as in:

(defun nuke_traling ()
  (add-hook 'before-save-hook #'delete-trailing-whitespace nil t))
(add-hook 'prog-mode-hook #'nuke_traling)

Solution 3:[3]

Yes, because as soon as you enter a prog-mode mode, you add the function to write-file-hooks, where it remains. And that hook applies to writing any file, regardless of the mode of its buffer.

Instead of putting that simple function on the hook, you can add a function that tests the mode and only does the whitespace deletion when it is a mode where you want to do that.

Or else you would need to make write-file-hooks buffer-local (which I doubt you would want want to do --- the hook is used more generally).

Solution 4:[4]

Bad way:

(add-to-list 'write-file-functions 'delete-trailing-whitespace)

Better way is using ws-butler:

(straight-use-package 'ws-butler)
(add-hook 'prog-mode-hook #'ws-butler-mode)

ws-butler-mode remove spaces only on changed lines.

Solution 5:[5]

You would need to make the variable buffer local:

(defun nuke_traling ()
    (make-variable-buffer-local 'write-file-hooks)
    (add-hook 'write-file-hooks 'delete-trailing-whitespace))

But I would recommend using before-save-hook instead:

(defun nuke_traling ()
    (add-to-list 'before-save-hook 'delete-trailing-whitespace))

write-file-hooks may be risky if used as a file-local variable, and documentation recomends using before-save-hook instead for thing like you want to do.

Solution 6:[6]

In emacs 21 or later you can add this hook to a perticular mode like this:

(add-hook 'prog-mode-hook
                (lambda () (add-to-list 'write-file-functions 'delete-trailing-whitespace)))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nifle
Solution 2 Stefan
Solution 3 Drew
Solution 4 Dunaevsky Maxim
Solution 5 juanleon
Solution 6 3r1k