18

I want to customize cc-mode to execute a function before saving. One solution would be to modify cc-mode keymap to bind C-x C-s to a function which performs the work I need and then saves it.

My question is whether there is a hook I could customize for this? The CC Hooks docs don't mention a before-save-hook specifically for cc-mode. How should this be done through a hook?

Alternatively, how do I do this through defadvice? From reading the manual, the only way I could see was to enable the advice before saving and then disable after the work is done. This sounds cumbersome. What would be the idiomatic way of using advices?

Pradhan
  • 2,330
  • 14
  • 28
  • 4
    The function you add to `before-save-hook` can check the current major mode (e.g. `(eq major-mode ...)`) and *do nothing* if it does not match the mode you are customizing. – Constantine Dec 16 '14 at 21:28
  • @Constantine Agreed. I wanted to check through if there is something more "built-in" for this kind of thing. IIRC `haskell-mode` has at least one of `after/before-save` hooks and I assumed this was standard practice for prog-modes. – Pradhan Dec 16 '14 at 21:31
  • @Constantine: could you convert your comment to an answer (expanding a little, of course)? – Dan Dec 17 '14 at 17:02
  • 2
    See [this thread](http://emacs.stackexchange.com/questions/4108/execute-external-script-upon-save-when-in-a-certain-mode/4115#4115) for an example use of *`after-save-hook`*; you can use the same sort of procedure but substitute `before-save-hook`. – Dan Dec 19 '14 at 12:45

3 Answers3

27

Alternatively, use a local hook:

(add-hook 'c++-mode-hook
          (lambda () (add-hook 'before-save-hook MY-HOOK-FUNC nil 'local)))

This adds MY-HOOK-FUNC to the buffer-local before-save-hook of each C++ Mode buffer, or any buffer in a mode derived of C++ Mode.

I find this more elegant that explicitly checking major-mode, and it has the advantage that you can disable the before-save-hook locally for each buffer with M-: (remove-hook 'before-save-hook MY-HOOK-FUNC 'local) without affecting any other buffers.

14

One fairly common way of restricting the action of a hook to a particular major mode is to check the value of major-mode.

For example, this hook prints a message before saving buffers using c++-mode:

(defun my-c++-mode-before-save-hook ()
  (when (eq major-mode 'c++-mode)
    (message "It's never too early to start saving (C++ code)!")))

(add-hook 'before-save-hook #'my-c++-mode-before-save-hook)

As a side note: sometimes it can be useful to check if a major mode is derived from CC Mode; we can do this by checking if c-buffer-is-cc-mode is not nil:

(defun my-cc-mode-before-save-hook ()
  (when c-buffer-is-cc-mode
    (message "Saving a buffer with a major-mode derived from CC Mode.")))
Constantine
  • 9,072
  • 1
  • 34
  • 49
-1

I once needed something like that for autocompiling my elisp files when saved, I used a approach like this (converted the approach to cc-mode):

(add-hook 'c-common-hook #'(lambda ()
                              (add-hook 'before-save-hook #'(lambda ()
                                                               (funcall #'YOUR-FUNC-HOOK)))))
  • 1
    First, did you mean `c-mode-common-hook`? Second, it looks like it will add the function to `before-save-hook` the first time you enter a `C`-related language, but then that function will be called just before every save on every buffer. What OP needs to do is run the function conditional on the buffer being in a specific mode (see @Constantine's comment for how). – Dan Dec 17 '14 at 17:01