commit | author | age
|
5cb5f7
|
1 |
;;; company-cmake.el --- company-mode completion backend for CMake |
C |
2 |
|
|
3 |
;; Copyright (C) 2013-2014, 2017-2018 Free Software Foundation, Inc. |
|
4 |
|
|
5 |
;; Author: Chen Bin <chenbin DOT sh AT gmail> |
|
6 |
;; Version: 0.2 |
|
7 |
|
|
8 |
;; This program is free software: you can redistribute it and/or modify |
|
9 |
;; it under the terms of the GNU General Public License as published by |
|
10 |
;; the Free Software Foundation, either version 3 of the License, or |
|
11 |
;; (at your option) any later version. |
|
12 |
|
|
13 |
;; This program is distributed in the hope that it will be useful, |
|
14 |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 |
;; GNU General Public License for more details. |
|
17 |
|
|
18 |
;; You should have received a copy of the GNU General Public License |
|
19 |
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
20 |
|
|
21 |
;;; Commentary: |
|
22 |
;; |
|
23 |
;; company-cmake offers completions for module names, variable names and |
|
24 |
;; commands used by CMake. And their descriptions. |
|
25 |
|
|
26 |
;;; Code: |
|
27 |
|
|
28 |
(require 'company) |
|
29 |
(require 'cl-lib) |
|
30 |
|
|
31 |
(defgroup company-cmake nil |
|
32 |
"Completion backend for CMake." |
|
33 |
:group 'company) |
|
34 |
|
|
35 |
(defcustom company-cmake-executable |
|
36 |
(executable-find "cmake") |
|
37 |
"Location of cmake executable." |
|
38 |
:type 'file) |
|
39 |
|
|
40 |
(defvar company-cmake-executable-arguments |
|
41 |
'("--help-command-list" |
|
42 |
"--help-module-list" |
|
43 |
"--help-variable-list") |
|
44 |
"The arguments we pass to cmake, separately. |
|
45 |
They affect which types of symbols we get completion candidates for.") |
|
46 |
|
|
47 |
(defvar company-cmake--completion-pattern |
|
48 |
"^\\(%s[a-zA-Z0-9_<>]%s\\)$" |
|
49 |
"Regexp to match the candidates.") |
|
50 |
|
|
51 |
(defvar company-cmake-modes '(cmake-mode) |
|
52 |
"Major modes in which cmake may complete.") |
|
53 |
|
|
54 |
(defvar company-cmake--candidates-cache nil |
|
55 |
"Cache for the raw candidates.") |
|
56 |
|
|
57 |
(defvar company-cmake--meta-command-cache nil |
|
58 |
"Cache for command arguments to retrieve descriptions for the candidates.") |
|
59 |
|
|
60 |
(defun company-cmake--replace-tags (rlt) |
|
61 |
(setq rlt (replace-regexp-in-string |
|
62 |
"\\(.*?\\(IS_GNU\\)?\\)<LANG>\\(.*\\)" |
|
63 |
(lambda (_match) |
|
64 |
(mapconcat 'identity |
|
65 |
(if (match-beginning 2) |
|
66 |
'("\\1CXX\\3" "\\1C\\3" "\\1G77\\3") |
|
67 |
'("\\1CXX\\3" "\\1C\\3" "\\1Fortran\\3")) |
|
68 |
"\n")) |
|
69 |
rlt t)) |
|
70 |
(setq rlt (replace-regexp-in-string |
|
71 |
"\\(.*\\)<CONFIG>\\(.*\\)" |
|
72 |
(mapconcat 'identity '("\\1DEBUG\\2" "\\1RELEASE\\2" |
|
73 |
"\\1RELWITHDEBINFO\\2" "\\1MINSIZEREL\\2") |
|
74 |
"\n") |
|
75 |
rlt)) |
|
76 |
rlt) |
|
77 |
|
|
78 |
(defun company-cmake--fill-candidates-cache (arg) |
|
79 |
"Fill candidates cache if needed." |
|
80 |
(let (rlt) |
|
81 |
(unless company-cmake--candidates-cache |
|
82 |
(setq company-cmake--candidates-cache (make-hash-table :test 'equal))) |
|
83 |
|
|
84 |
;; If hash is empty, fill it. |
|
85 |
(unless (gethash arg company-cmake--candidates-cache) |
|
86 |
(with-temp-buffer |
|
87 |
(let ((res (call-process company-cmake-executable nil t nil arg))) |
|
88 |
(unless (zerop res) |
|
89 |
(message "cmake executable exited with error=%d" res))) |
|
90 |
(setq rlt (buffer-string))) |
|
91 |
(setq rlt (company-cmake--replace-tags rlt)) |
|
92 |
(puthash arg rlt company-cmake--candidates-cache)) |
|
93 |
)) |
|
94 |
|
|
95 |
(defun company-cmake--parse (prefix content cmd) |
|
96 |
(let ((start 0) |
|
97 |
(pattern (format company-cmake--completion-pattern |
|
98 |
(regexp-quote prefix) |
|
99 |
(if (zerop (length prefix)) "+" "*"))) |
|
100 |
(lines (split-string content "\n")) |
|
101 |
match |
|
102 |
rlt) |
|
103 |
(dolist (line lines) |
|
104 |
(when (string-match pattern line) |
|
105 |
(let ((match (match-string 1 line))) |
|
106 |
(when match |
|
107 |
(puthash match cmd company-cmake--meta-command-cache) |
|
108 |
(push match rlt))))) |
|
109 |
rlt)) |
|
110 |
|
|
111 |
(defun company-cmake--candidates (prefix) |
|
112 |
(let (results |
|
113 |
cmd-opts |
|
114 |
str) |
|
115 |
|
|
116 |
(unless company-cmake--meta-command-cache |
|
117 |
(setq company-cmake--meta-command-cache (make-hash-table :test 'equal))) |
|
118 |
|
|
119 |
(dolist (arg company-cmake-executable-arguments) |
|
120 |
(company-cmake--fill-candidates-cache arg) |
|
121 |
(setq cmd-opts (replace-regexp-in-string "-list$" "" arg) ) |
|
122 |
|
|
123 |
(setq str (gethash arg company-cmake--candidates-cache)) |
|
124 |
(when str |
|
125 |
(setq results (nconc results |
|
126 |
(company-cmake--parse prefix str cmd-opts))))) |
|
127 |
results)) |
|
128 |
|
|
129 |
(defun company-cmake--unexpand-candidate (candidate) |
|
130 |
(cond |
|
131 |
((string-match "^CMAKE_\\(C\\|CXX\\|Fortran\\)\\(_.*\\)$" candidate) |
|
132 |
(setq candidate (concat "CMAKE_<LANG>" (match-string 2 candidate)))) |
|
133 |
|
|
134 |
;; C flags |
|
135 |
((string-match "^\\(.*_\\)IS_GNU\\(C\\|CXX\\|G77\\)$" candidate) |
|
136 |
(setq candidate (concat (match-string 1 candidate) "IS_GNU<LANG>"))) |
|
137 |
|
|
138 |
;; C flags |
|
139 |
((string-match "^\\(.*_\\)OVERRIDE_\\(C\\|CXX\\|Fortran\\)$" candidate) |
|
140 |
(setq candidate (concat (match-string 1 candidate) "OVERRIDE_<LANG>"))) |
|
141 |
|
|
142 |
((string-match "^\\(.*\\)\\(_DEBUG\\|_RELEASE\\|_RELWITHDEBINFO\\|_MINSIZEREL\\)\\(.*\\)$" candidate) |
|
143 |
(setq candidate (concat (match-string 1 candidate) |
|
144 |
"_<CONFIG>" |
|
145 |
(match-string 3 candidate))))) |
|
146 |
candidate) |
|
147 |
|
|
148 |
(defun company-cmake--meta (candidate) |
|
149 |
(let ((cmd-opts (gethash candidate company-cmake--meta-command-cache)) |
|
150 |
result) |
|
151 |
(setq candidate (company-cmake--unexpand-candidate candidate)) |
|
152 |
|
|
153 |
;; Don't cache the documentation of every candidate (command) |
|
154 |
;; Cache in this case will cost too much memory. |
|
155 |
(with-temp-buffer |
|
156 |
(call-process company-cmake-executable nil t nil cmd-opts candidate) |
|
157 |
;; Go to the third line, trim it and return the result. |
|
158 |
;; Tested with cmake 2.8.9. |
|
159 |
(goto-char (point-min)) |
|
160 |
(forward-line 2) |
|
161 |
(setq result (buffer-substring-no-properties (line-beginning-position) |
|
162 |
(line-end-position))) |
|
163 |
(setq result (replace-regexp-in-string "^[ \t\n\r]+" "" result)) |
|
164 |
result))) |
|
165 |
|
|
166 |
(defun company-cmake--doc-buffer (candidate) |
|
167 |
(let ((cmd-opts (gethash candidate company-cmake--meta-command-cache))) |
|
168 |
|
|
169 |
(setq candidate (company-cmake--unexpand-candidate candidate)) |
|
170 |
(with-temp-buffer |
|
171 |
(call-process company-cmake-executable nil t nil cmd-opts candidate) |
|
172 |
;; Go to the third line, trim it and return the doc buffer. |
|
173 |
;; Tested with cmake 2.8.9. |
|
174 |
(goto-char (point-min)) |
|
175 |
(forward-line 2) |
|
176 |
(company-doc-buffer |
|
177 |
(buffer-substring-no-properties (line-beginning-position) |
|
178 |
(point-max)))))) |
|
179 |
|
|
180 |
(defun company-cmake-prefix-dollar-brace-p () |
|
181 |
"Test if the current symbol follows ${." |
|
182 |
(save-excursion |
|
183 |
(skip-syntax-backward "w_") |
|
184 |
(and (eq (char-before (point)) ?\{) |
|
185 |
(eq (char-before (1- (point))) ?$)))) |
|
186 |
|
|
187 |
(defun company-cmake (command &optional arg &rest ignored) |
|
188 |
"`company-mode' completion backend for CMake. |
|
189 |
CMake is a cross-platform, open-source make system." |
|
190 |
(interactive (list 'interactive)) |
|
191 |
(cl-case command |
|
192 |
(interactive (company-begin-backend 'company-cmake)) |
|
193 |
(init (when (memq major-mode company-cmake-modes) |
|
194 |
(unless company-cmake-executable |
|
195 |
(error "Company found no cmake executable")))) |
|
196 |
(prefix (and (memq major-mode company-cmake-modes) |
|
197 |
(or (not (company-in-string-or-comment)) |
|
198 |
(company-cmake-prefix-dollar-brace-p)) |
|
199 |
(company-grab-symbol))) |
|
200 |
(candidates (company-cmake--candidates arg)) |
|
201 |
(meta (company-cmake--meta arg)) |
|
202 |
(doc-buffer (company-cmake--doc-buffer arg)) |
|
203 |
)) |
|
204 |
|
|
205 |
(provide 'company-cmake) |
|
206 |
;;; company-cmake.el ends here |