178 lines
5.7 KiB
EmacsLisp
178 lines
5.7 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) ;;;
|
|
|
|
(use-package gdb-mi
|
|
:quelpa (gdb-mi :fetcher git
|
|
:url "https://github.com/weirdNox/emacs-gdb.git"
|
|
:files ("*.el" "*.c" "*.h" "Makefile"))
|
|
:init
|
|
(fmakunbound 'gdb)
|
|
(fmakunbound 'gdb-enable-debug))
|
|
|
|
;; 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
|