402 lines
13 KiB
EmacsLisp
402 lines
13 KiB
EmacsLisp
;;; funcs.el --- C/C++ Layer functions File for Spacemacs
|
||
;;
|
||
;; Copyright (c) 2012-2021 Sylvain Benner & Contributors
|
||
;;
|
||
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
|
||
;; URL: https://github.com/syl20bnr/spacemacs
|
||
;;
|
||
;; This file is not part of GNU Emacs.
|
||
;;
|
||
;; This program is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation, either version 3 of the License, or
|
||
;; (at your option) any later version.
|
||
;;
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
;;
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
|
||
(require 'cl-lib)
|
||
(require 'subr-x)
|
||
|
||
(defun spacemacs//c-c++-setup-backend ()
|
||
"Conditionally setup c-c++ backend."
|
||
(pcase c-c++-backend
|
||
('lsp-clangd (spacemacs//c-c++-setup-lsp-clangd))
|
||
('lsp-ccls (spacemacs//c-c++-setup-lsp-ccls))
|
||
('rtags (spacemacs//c-c++-setup-rtags))
|
||
('ycmd (spacemacs//c-c++-setup-ycmd))))
|
||
|
||
(defun spacemacs//c-c++-setup-company ()
|
||
"Conditionally setup C/C++ company integration based on backend."
|
||
(pcase c-c++-backend
|
||
('rtags (spacemacs//c-c++-setup-rtags-company))
|
||
('ycmd (spacemacs//c-c++-setup-ycmd-company))))
|
||
|
||
(defun spacemacs//c-c++-setup-dap ()
|
||
"Conditionally setup C/C++ DAP integration based on backend."
|
||
;; currently DAP is only available using LSP
|
||
(pcase c-c++-backend
|
||
('lsp-clangd (spacemacs//c-c++-setup-lsp-dap))
|
||
('lsp-ccls (spacemacs//c-c++-setup-lsp-dap))))
|
||
|
||
(defun spacemacs//c-c++-setup-eldoc ()
|
||
"Conditionally setup C/C++ eldoc integration based on backend."
|
||
;; lsp setup eldoc on its own
|
||
(when (eq c-c++-backend 'ycmd)
|
||
(spacemacs//c-c++-setup-ycmd-eldoc)))
|
||
|
||
(defun spacemacs//c-c++-setup-flycheck ()
|
||
"Conditionally setup C/C++ flycheck integration based on backend."
|
||
(pcase c-c++-backend
|
||
('rtags (spacemacs//c-c++-setup-rtags-flycheck))
|
||
('ycmd (spacemacs//c-c++-setup-ycmd-flycheck))))
|
||
|
||
(defun spacemacs//c-c++-setup-format ()
|
||
"Conditionally setup format based on backend."
|
||
(pcase c-c++-backend
|
||
('lsp-clangd (spacemacs//c-c++-setup-clang-format))
|
||
('lsp-ccls (spacemacs//c-c++-setup-clang-format))))
|
||
|
||
(defun spacemacs//c-c++-setup-semantic ()
|
||
"Conditionally setup semantic based on backend."
|
||
(pcase c-c++-backend
|
||
('rtags (spacemacs//c-c++-setup-rtags-semantic))
|
||
('ycmd (spacemacs//c-c++-setup-ycmd-semantic))))
|
||
|
||
|
||
;; lsp
|
||
|
||
;; clang
|
||
|
||
(defun spacemacs//c-c++-setup-lsp-clangd ()
|
||
"Setup LSP clangd."
|
||
;; extensions
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-clangd"
|
||
'clangd-other-file "textDocument/switchSourceHeader" 'buffer-file-name)
|
||
(setq-local lsp-disabled-clients '(ccls))
|
||
(lsp))
|
||
|
||
;; ccls
|
||
|
||
(defun spacemacs//c-c++-setup-lsp-ccls ()
|
||
"Setup LSP ccls."
|
||
(require 'ccls)
|
||
|
||
;; semantic highlight
|
||
(when c-c++-lsp-enable-semantic-highlight
|
||
(setq ccls-sem-highlight-method c-c++-lsp-semantic-highlight-method)
|
||
(when (eq 'rainbow c-c++-lsp-enable-semantic-highlight)
|
||
(ccls-use-default-rainbow-sem-highlight)))
|
||
|
||
;; extensions
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'refs-address "textDocument/references" '(:role 128))
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'refs-read "textDocument/references" '(:role 8))
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'refs-write "textDocument/references" '(:role 16))
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'callers "$ccls/call")
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'callees "$ccls/call" '(:callee t))
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'base "$ccls/inheritance")
|
||
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'derived "$ccls/inheritance" '(:derived t))
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'member-types "$ccls/member" `(:kind 2))
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'member-functions "$ccls/member" `(:kind 3))
|
||
(spacemacs/lsp-define-extensions
|
||
"c-c++" "lsp-ccls"
|
||
'member-vars "$ccls/member" `(:kind 0))
|
||
|
||
;; key bindings
|
||
(dolist (mode c-c++-modes)
|
||
(spacemacs/set-leader-keys-for-major-mode mode
|
||
;; backend
|
||
"bf" 'ccls-reload
|
||
"bp" 'ccls-preprocess-file
|
||
;; goto
|
||
"gf" 'find-file-at-point
|
||
"gF" 'ffap-other-window
|
||
;; hierarchy
|
||
"ghc" 'ccls-call-hierarchy
|
||
"ghC" 'spacemacs/c-c++-lsp-ccls-call-hierarchy-inv
|
||
"ghi" 'ccls-inheritance-hierarchy
|
||
"ghI" 'spacemacs/c-c++-lsp-ccls-inheritance-hierarchy-inv
|
||
;; members
|
||
"gmh" 'ccls-member-hierarchy)
|
||
|
||
(spacemacs/lsp-bind-extensions-for-mode
|
||
mode "c-c++" "lsp-ccls"
|
||
"&" 'refs-address
|
||
"R" 'refs-read
|
||
"W" 'refs-write
|
||
"c" 'callers
|
||
"C" 'callees
|
||
"v" 'vars
|
||
"hb" 'base)
|
||
|
||
(spacemacs/lsp-bind-extensions-for-mode
|
||
mode "c-c++" "lsp-ccls"
|
||
"hd" 'derived
|
||
"mt" 'member-types
|
||
"mf" 'member-functions
|
||
"mv" 'member-vars))
|
||
|
||
;;(evil-set-initial-state 'ccls--tree-mode 'emacs)
|
||
;;(evil-make-overriding-map 'ccls-tree-mode-map)
|
||
(setq-local lsp-disabled-clients '(clangd))
|
||
(lsp))
|
||
|
||
(defun spacemacs//c-c++-setup-lsp-dap ()
|
||
"Setup DAP integration."
|
||
(mapc #'require c-c++-dap-adapters))
|
||
|
||
|
||
;; rtags
|
||
|
||
(defun spacemacs//c-c++-setup-rtags ()
|
||
"Setup rtags backend."
|
||
(setq rtags-autostart-diagnostics t)
|
||
(add-hook 'rtags-jump-hook 'evil-set-jump)
|
||
(rtags-diagnostics)
|
||
;; key bindings
|
||
(evil-define-key 'normal rtags-mode-map
|
||
(kbd "RET") 'rtags-select-other-window
|
||
(kbd "M-RET") 'rtags-select
|
||
(kbd "q") 'rtags-bury-or-delete)
|
||
;; TODO check for consistency with gtags key bindings
|
||
;; see https://github.com/syl20bnr/spacemacs/blob/develop/layers/+tags/gtags/funcs.el#L70
|
||
(dolist (mode c-c++-modes)
|
||
(spacemacs/set-leader-keys-for-major-mode mode
|
||
"g." 'spacemacs/c-c++-tags-find-symbol-at-point
|
||
"g," 'spacemacs/c-c++-tags-find-references-at-point
|
||
"g;" 'spacemacs/c-c++-tags-find-file
|
||
"g/" 'rtags-find-all-references-at-point
|
||
"g[" 'rtags-location-stack-back
|
||
"g]" 'rtags-location-stack-forward
|
||
"g>" 'spacemacs/c-c++-tags-find-symbol
|
||
"g<" 'spacemacs/c-c++-tags-find-references
|
||
"gB" 'rtags-show-rtags-buffer
|
||
"gd" 'rtags-print-dependencies
|
||
"gD" 'rtags-diagnostics
|
||
"ge" 'rtags-reparse-file
|
||
"gE" 'rtags-preprocess-file
|
||
"gf" 'rtags-find-dead-functions
|
||
"gF" 'rtags-fixit
|
||
"gG" 'rtags-guess-function-at-point
|
||
"gh" 'rtags-print-class-hierarchy
|
||
"gI" 'spacemacs/c-c++-tags-imenu
|
||
"gL" 'rtags-copy-and-print-current-location
|
||
"gM" 'rtags-symbol-info
|
||
"gO" 'rtags-goto-offset
|
||
"gp" 'rtags-set-current-project
|
||
"gr" 'rtags-references-tree
|
||
"gR" 'rtags-rename-symbol
|
||
"gs" 'rtags-print-source-arguments
|
||
"gS" 'rtags-display-summary
|
||
"gt" 'rtags-symbol-type
|
||
"gT" 'rtags-taglist
|
||
"gu" 'rtags-dependency-tree
|
||
"gv" 'rtags-find-virtuals-at-point
|
||
"gV" 'rtags-print-enum-value-at-point
|
||
"gX" 'rtags-fix-fixit-at-point
|
||
"gY" 'rtags-cycle-through-diagnostics)))
|
||
|
||
(defun spacemacs//c-c++-setup-rtags-company ()
|
||
"Setup rtags auto-completion."
|
||
(when c-c++-enable-rtags-completion
|
||
(setq rtags-completions-enabled t)
|
||
(spacemacs|add-company-backends
|
||
:backends company-rtags
|
||
:modes c-mode-common
|
||
:append-hooks nil
|
||
:call-hooks t)))
|
||
|
||
(defun spacemacs//c-c++-setup-rtags-flycheck ()
|
||
"Setup rtags syntax checking."
|
||
(when (or (spacemacs/enable-flycheck 'c-mode)
|
||
(spacemacs/enable-flycheck 'c++-mode))
|
||
(require 'flycheck-rtags)
|
||
(flycheck-mode)))
|
||
|
||
(defun spacemacs//c-c++-setup-rtags-semantic ()
|
||
"Setup semantic for rtags."
|
||
(semantic-mode)
|
||
(spacemacs//disable-semantic-idle-summary-mode))
|
||
|
||
(defun spacemacs/c-c++-use-rtags (&optional useFileManager)
|
||
"Return non-nil if rtags function should be used."
|
||
;; this function is used to fallback on gtags function if rtags is not
|
||
;; supported. So if gtags layer is not used we disable the fallback by
|
||
;; returning always t.
|
||
(or (not (configuration-layer/layer-used-p 'gtags))
|
||
(and (rtags-executable-find "rc")
|
||
(cond ((not (gtags-get-rootpath)) t)
|
||
((and (not (eq major-mode 'c++-mode))
|
||
(not (eq major-mode 'c-mode))) (rtags-has-filemanager))
|
||
(useFileManager (rtags-has-filemanager))
|
||
(t (rtags-is-indexed))))))
|
||
|
||
(defun spacemacs/c-c++-tags-find-symbol-at-point (&optional prefix)
|
||
(interactive "P")
|
||
(if (and (not (rtags-find-symbol-at-point prefix))
|
||
rtags-last-request-not-indexed)
|
||
(gtags-find-tag)))
|
||
|
||
(defun spacemacs/c-c++-tags-find-references-at-point (&optional prefix)
|
||
(interactive "P")
|
||
(if (and (not (rtags-find-references-at-point prefix))
|
||
rtags-last-request-not-indexed)
|
||
(gtags-find-rtag)))
|
||
|
||
(defun spacemacs/c-c++-tags-find-symbol ()
|
||
(interactive)
|
||
(call-interactively (if (spacemacs/c-c++-use-rtags)
|
||
'rtags-find-symbol 'gtags-find-symbol)))
|
||
|
||
(defun spacemacs/c-c++-tags-find-references ()
|
||
(interactive)
|
||
(call-interactively (if (spacemacs/c-c++-use-rtags)
|
||
'rtags-find-references 'gtags-find-rtag)))
|
||
|
||
(defun spacemacs/c-c++-tags-find-file ()
|
||
(interactive)
|
||
(call-interactively (if (spacemacs/c-c++-use-rtags t)
|
||
'rtags-find-file 'gtags-find-file)))
|
||
|
||
(defun spacemacs/c-c++-tags-imenu ()
|
||
(interactive)
|
||
(call-interactively (if (spacemacs/c-c++-use-rtags t)
|
||
'rtags-imenu 'idomenu)))
|
||
|
||
|
||
;; ycmd
|
||
|
||
(defun spacemacs//c-c++-setup-ycmd ()
|
||
"Setup ycmd backend."
|
||
(add-to-list 'spacemacs-jump-handlers-c++-mode '(ycmd-goto :async t))
|
||
(add-to-list 'spacemacs-jump-handlers-c-mode '(ycmd-goto :async t))
|
||
(dolist (mode c-c++-modes)
|
||
(spacemacs/set-leader-keys-for-major-mode mode
|
||
"gG" 'ycmd-goto-imprecise))
|
||
(ycmd-mode))
|
||
|
||
(defun spacemacs//c-c++-setup-ycmd-company ()
|
||
"Setup ycmd auto-completion."
|
||
(spacemacs|add-company-backends
|
||
:backends company-ycmd
|
||
:modes c-mode-common
|
||
:append-hooks nil
|
||
:call-hooks t))
|
||
|
||
(defun spacemacs//c-c++-setup-ycmd-eldoc ()
|
||
"Setup ycmd eldoc integration."
|
||
(ycmd-eldoc-setup))
|
||
|
||
(defun spacemacs//c-c++-setup-ycmd-flycheck ()
|
||
"Setup ycmd syntax checking."
|
||
(when (or (spacemacs/enable-flycheck 'c-mode)
|
||
(spacemacs/enable-flycheck 'c++-mode))
|
||
(flycheck-ycmd-setup)
|
||
(flycheck-mode)))
|
||
|
||
(defun spacemacs//c-c++-setup-ycmd-semantic ()
|
||
"Setup semantic for ycmd."
|
||
(semantic-mode))
|
||
|
||
|
||
;; style
|
||
|
||
(defun spacemacs//c-toggle-auto-newline ()
|
||
"Toggle auto-newline."
|
||
(c-toggle-auto-newline 1))
|
||
|
||
|
||
;; clang
|
||
|
||
(defun spacemacs//c-c++-setup-clang-format ()
|
||
"Setup clang format."
|
||
(when c-c++-enable-clang-format-on-save
|
||
(spacemacs/add-to-hooks 'spacemacs/clang-format-on-save c-c++-mode-hooks))
|
||
(dolist (mode c-c++-modes)
|
||
(spacemacs/declare-prefix-for-mode mode "m=" "format")
|
||
(spacemacs/set-leader-keys-for-major-mode mode
|
||
"==" 'spacemacs/clang-format-region-or-buffer
|
||
"=f" 'spacemacs/clang-format-function)))
|
||
|
||
(defun spacemacs/clang-format-function (&optional style)
|
||
"Format the current function with clang-format according to STYLE."
|
||
(interactive)
|
||
(save-excursion
|
||
(c-mark-function)
|
||
(clang-format (region-beginning) (region-end) style)
|
||
(deactivate-mark) ; If the function is already formatted, then remove the mark
|
||
(message "Formatted function %s" (c-defun-name))))
|
||
|
||
(defun spacemacs/clang-format-region-or-buffer (&optional style)
|
||
"Format the current region or buffer with clang-format according to STYLE."
|
||
(interactive)
|
||
(save-excursion
|
||
(if (region-active-p)
|
||
(progn
|
||
(clang-format-region (region-beginning) (region-end) style)
|
||
(message "Formatted region"))
|
||
(clang-format-buffer style)
|
||
(message "Formatted buffer %s" (buffer-name)))))
|
||
|
||
(defun spacemacs//clang-format-on-save ()
|
||
"Format the current buffer with clang-format on save when
|
||
`c-c++-enable-clang-format-on-save' is non-nil."
|
||
(when c-c++-enable-clang-format-on-save
|
||
(spacemacs/clang-format-region-or-buffer)))
|
||
|
||
(defun spacemacs/clang-format-on-save ()
|
||
"Add before-save hook for clang-format."
|
||
(add-hook 'before-save-hook 'spacemacs//clang-format-on-save nil t))
|
||
|
||
|
||
;; ccls
|
||
|
||
(defun spacemacs/c-c++-lsp-ccls-call-hierarchy-inv ()
|
||
(interactive)
|
||
(ccls-call-hierarchy t))
|
||
|
||
(defun spacemacs/c-c++-lsp-ccls-inheritance-hierarchy-inv ()
|
||
(interactive)
|
||
(ccls-inheritance-hierarchy t))
|
||
|
||
|
||
;; cpp-auto-include
|
||
|
||
(defalias 'spacemacs/c-c++-organize-includes 'cpp-auto-include)
|
||
|
||
(defun spacemacs//c-c++-organize-includes-on-save ()
|
||
"Organize the includes on save when `c-c++-enable-organize-includes-on-save'
|
||
is non-nil."
|
||
(when c-c++-enable-organize-includes-on-save
|
||
(spacemacs/c-c++-organize-includes)))
|
||
|
||
(defun spacemacs/c-c++-organize-includes-on-save ()
|
||
"Add before-save hook for c-c++-organize-includes."
|
||
(add-hook 'before-save-hook
|
||
#'spacemacs//c-c++-organize-includes-on-save nil t))
|