5

Whats the best way to clang-format a C/C++/GLSL a buffer on save, that does nothing in the case there is no clang-format file found for a project?

2 Answers 2

8

Install the clang-format package and add the following hooks to your emacs init:


(defun clang-format-save-hook-for-this-buffer ()
  "Create a buffer local save hook."
  (add-hook 'before-save-hook
            (lambda ()
              (when (locate-dominating-file "." ".clang-format")
                (clang-format-buffer))
              ;; Continue to save.
              nil)
            nil
            ;; Buffer local hook.
            t))

;; Run this for each mode you want to use the hook.
(add-hook 'c-mode-hook (lambda () (clang-format-save-hook-for-this-buffer)))
(add-hook 'c++-mode-hook (lambda () (clang-format-save-hook-for-this-buffer)))
(add-hook 'glsl-mode-hook (lambda () (clang-format-save-hook-for-this-buffer)))

Created clang-format-on-save package to make this into a minor mode.

5
  • For some reason this cases my file to be impossible to save even though it gets formatted.
    – Martin
    May 21, 2019 at 4:15
  • Fixed, the function needed to evaluate to nil, also only run when .clang-format file is found.
    – ideasman42
    Jun 24, 2019 at 2:36
  • Thanks for showing us locate-dominating-file. Would be helpful with flycheck, lsp-mode, etc. where the notion of a project is needed.
    – legends2k
    Dec 12, 2019 at 11:01
  • this answer is excellent, but is missing ')' on each of the last three lines. Jul 28, 2021 at 18:19
  • 1
    @optimus_prime corrected (feel free to delete these comments to remove noise).
    – ideasman42
    Apr 5, 2022 at 5:59
1

Building on ideasman42's answer, I wanted to be able to turn this feature on an off, per buffer or globally. Minor modes to the rescue :

(use-package clang-format)
(defun clang-format-save-hook()
  "Create a buffer local save hook to apply `clang-format-buffer'"
  ;; Only format if .clang-format is found
  (when (locate-dominating-file "." ".clang-format")
    (clang-format-buffer))
  ;; Continue to save
  nil)

(define-minor-mode clang-format-on-save-mode
  "Buffer-local mode to enable/disable automated clang format on save"
  :lighter " ClangFormat"
  (if clang-format-on-save-mode
      (add-hook 'before-save-hook 'clang-format-save-hook nil t)
    (remove-hook 'before-save-hook 'clang-format-save-hook t)))

;; Create a globalized minor mode to
;;   - Auto enable the above mode only for C/C++, or glsl in your case
;;   - Be able to turn it off globally if needed
(define-globalized-minor-mode clang-format-auto-enable-mode clang-format-on-save-mode
  (lambda()(clang-format-on-save-mode t))
  :predicate '(c-mode c++-mode c-or-c++-mode))
(clang-format-auto-enable-mode t)
1
  • Thanks, in this case it may as well be a package, updated my answer to link to a package that implements the minor mode.
    – ideasman42
    Sep 29, 2023 at 0:56

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.