Files
dotemacs/lisp/modes/c-c++.el

169 lines
5.5 KiB
EmacsLisp

;;; c-c++.el --- initializes C/C++ modes -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:
(require 'cl)
(require 'lsp)
(require 'cc-vars)
(require 'flycheck)
(defun user--c-format-before-save ()
"C/C++ cleanup and format before save buffer."
(delete-trailing-whitespace)
;; Format buffer.
(indent-region (point-min) (point-max) nil))
;; From https://www.emacswiki.org/emacs/CompileCommand
(defun* user--c-get-closest-pathname (&optional (file "Makefile"))
"Determine the pathname of the first instance of FILE starting from the current directory towards root.
This may not do the correct thing in presence of links. If it does not find FILE, then it shall return the name
of FILE in the current directory, suitable for creation"
(let ((root (expand-file-name "/"))) ; the win32 builds should translate this correctly
(expand-file-name file
(loop
for d = default-directory then (expand-file-name ".." d)
if (file-exists-p (expand-file-name file d))
return d
if (equal d root)
return nil))))
(defun user--c-lsp-set-priority (server priority)
(setf (lsp--client-priority (gethash server lsp-clients)) priority))
(defun user--c-mode-common-hook ()
"C-like languages mode hook."
(message "user--c-mode-common-hook BEG")
(add-many-to-list 'c-default-style '(c-mode . "bsd") '(c++-mode . "bsd"))
(setq-local tab-width 4)
(setq-local c-basic-offset 4)
;; Propertize "#if 0" regions as comments.
(font-lock-add-keywords
nil
'((user/c-mode-font-lock-if0 (0 font-lock-comment-face prepend)))
'add-to-end)
;; Change compile-command.
(set
(make-local-variable 'compile-command)
(format "make -C %s" (directory-file-name (file-name-directory (user--c-get-closest-pathname)))))
;; Avoid to hit enter after compile-command to build.
(setq compilation-read-command nil)
;; Separate camel-case into separate words.
(subword-mode t)
(when (feature-p 'mic-paren)
;; Match context to open parentheses.
(paren-toggle-open-paren-context t))
(setq flycheck-checker-error-threshold 1000)
(setq flycheck-local-checkers '((lsp . ((next-checkers . (flawfinder))))))
;; (flycheck-add-next-checker 'clang-analyzer 'flawfinder)
(user/smartparens-enable)
(message "user--c-mode-common-hook END")
)
(defun user/c-mode-font-lock-if0 (limit)
"Propertize '#if 0' regions, up to LIMIT in size, as comments."
(save-restriction
(widen)
(save-excursion
(goto-char (point-min))
(let ((depth 0) str start start-depth)
(while (re-search-forward "^\\s-*#\\s-*\\(if\\|else\\|endif\\)" limit 'move)
(setq str (match-string 1))
(if (string= str "if")
(progn
(setq depth (1+ depth))
(when (and (null start) (looking-at "\\s-+0"))
(setq start (match-end 0)
start-depth depth)))
(when (and start (= depth start-depth))
(c-put-font-lock-face start (match-beginning 0) 'font-lock-comment-face)
(setq start nil))
(when (string= str "endif")
(setq depth (1- depth)))))
(when (and start (> depth 0))
(c-put-font-lock-face start (point) 'font-lock-comment-face)))))
nil)
(defun user/c++-header-file-p ()
"Return non-nil if in a C++ header."
(and (string-match "\\.h$" (or (buffer-file-name) (buffer-name)))
(save-excursion (re-search-forward "\\_<class\\_>" nil t))))
;; https://www.gnu.org/software/emacs/manual/html_mono/ccmode.html
(use-package cc-mode
:defer
:hook
(c-mode-common-hook . user--c-mode-common-hook)
(c-mode-common-hook . hs-minor-mode)
(c-mode-common-hook . lsp-deferred)
(c-mode-common-hook . (lambda ()
(add-hook 'before-save-hook #'user--c-format-before-save nil t)))
:init
;; Detect if inside a C++ header file.
(add-magic-mode 'c++-mode 'user/c++-header-file-p)
:config
(add-many-to-list 'c-default-style '(c-mode . "bsd") '(c++-mode . "bsd")
)
;;; (Packages) ;;;
;; https://github.com/emacs-mirror/emacs/blob/master/lisp/progmodes/cc-vars.el
;; user customization variables for CC Mod
(use-package cc-vars
:ensure cc-mode
:config
(validate-setq
;; Support completion using tab.
c-tab-always-indent nil
c-insert-tab-function 'indent-for-tab-command)
)
;; https://github.com/randomphrase/company-c-headers
;; Auto-completion for C/C++ headers using Company
(use-package company-c-headers
:after (company))
;; https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-clangd.el
;; LSP clients for the C Languages Family
(use-package lsp-clangd
:after (company lsp)
;; :defer t
:config
;; set priority to ensure the use of clangd
(setq company-backends '(company-capf))
(user--c-lsp-set-priority 'clangd 1))
;; https://github.com/MaskRay/emacs-ccls
;; Emacs client for ccls, a C/C++ language server
(use-package ccls
:if (executable-find "ccls")
:after lsp
:config
(user--c-lsp-set-priority 'ccls -1)
(validate-setq
ccls-initialization-options
'(:index (:comments 1) :cacheFormat "msgpack")))
;; https://github.com/alexmurray/flycheck-flawfinder
;; Integrate flawfinder with flycheck to automatically check for possible security weaknesses
;; within your C/C++ code on the fly.
(use-package flycheck-flawfinder
:disabled
:ensure t
:if (executable-find "flawfinder")
:config
(flycheck-flawfinder-setup))
)
(provide 'modes/c-c++)
;;; c-c++.el ends here