forked from mooz/auto-complete-c-headers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
auto-complete-c-headers.el
155 lines (126 loc) · 6.19 KB
/
auto-complete-c-headers.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
;;; auto-complete-c-headers.el --- An auto-complete source for C/C++ header files
;; Copyright (C) 2013 Masafumi Oyamada
;; Author: Masafumi Oyamada <stillpedant@gmail.com>
;; Package-Requires: ((auto-complete "1.4"))
;; Keywords: c
;; 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/>.
;;; Commentary:
;; (require 'auto-complete-c-headers)
;; (add-to-list 'ac-sources 'ac-source-c-headers)
;;; Code:
;; For `remove-duplicates'
(require 'cl-lib)
(require 'auto-complete)
(require 'tramp)
(defvar achead:include-patterns (list
"\\.\\(h\\|hpp\\|hh\\)$" ; Standard header files
"/[a-zA-Z-_]+$" ; C++'s suffix-free include files (iostream, vector, unordered_map, ...)
)
"Regexp pattern list that limits the candidates. If a header
file path matches a pattern in `achead:include-patterns', the
candidates will be displayed.")
(defvar achead:include-directories (list "." "/usr/include" "/usr/local/include")
"Standard include directories. This variable should be
customized to your environment via commands like,
`gcc -xc -E -v -`
or
`gcc -xc++ -E -v -`
If you need to do more complicated things (like `pkg-config`),
please consider to make your own function and set it to
`achead:get-include-directories-function'.")
(defvar achead:get-include-directories-function 'achead:get-include-directories
"Function that collects include directories.")
(defun achead:get-include-directories ()
"Default function for `achead:get-include-directories-function',
which simply returns the contents of
`achead:include-directories'. "
achead:include-directories)
(defvar achead:ac-prefix "#\\(?:include\\|import\\)[ \t]*[<\"][ \t]*\\([^\"<>' \t\r\n]+\\)"
"`prefix' value for `auto-complete'")
(defvar achead:inspect-remote-directories t
"If t, remote directories will be searched.")
(defun achead:get-include-directories-from-options (cmd-line-options)
"Extract include directory names from command line options
like (\"-I~/.local/include/\" \"-I~/src/include/\")."
(cl-loop for option in cmd-line-options
when (let (case-fold-search)
(string-match "^-I\\(.*\\)" option))
collect (match-string 1 option)))
(defvar achead:include-cache nil
"Cache file list of include directories.")
(defun achead:file-list-for-directory (dir)
"Get file list of the directory `dir'."
(ignore-errors
(or (assoc-default dir achead:include-cache)
(let ((files (directory-files dir nil "^[^.]")))
(push (cons dir files) achead:include-cache)
files))))
(defun achead:path-should-be-displayed (path)
"Decide `path' should be displayed as a candidate."
(cl-loop for include-pattern in achead:include-patterns
when (string-match-p include-pattern path)
return t))
(defun achead:get-include-file-candidates (&optional basedir)
"Get all header files under `basedir' as if -I option is
enabled for directories returned by
`achead:get-include-directories-function'."
(let ((remote (and achead:inspect-remote-directories
(file-remote-p default-directory))))
(cl-loop with dir-suffix = (or basedir "")
with include-base-dirs = (cl-delete-duplicates (funcall achead:get-include-directories-function)
:test 'string=)
for include-base in include-base-dirs
append (cl-loop with dir = (file-name-directory (concat (file-name-as-directory include-base)
dir-suffix))
with files = (achead:file-list-for-directory (concat remote dir))
for file in files
;; FIXME: Are there a good way to bind variable inside a loop (`with' cannot capture `file')?
;; (concat dir file) should be bounded to a variable like `real-path'
when (or (file-directory-p (concat dir file))
(and achead:include-patterns (achead:path-should-be-displayed (concat dir file))))
collect (cons (if (file-directory-p (concat dir file))
(concat dir-suffix (concat file "/"))
(concat dir-suffix file))
(concat dir file)))))
)
(defvar achead:ac-latest-results-alist nil
"Keeps latest results, which is a list of (candidate . header-path).")
(defun achead:documentation-for-candidate (candidate)
"Generate documentation for a candidate `candidate'. For now,
just returns the path and content of the header file which
`candidate' specifies."
(let ((path
(assoc-default candidate achead:ac-latest-results-alist 'string=)))
(ignore-errors
(with-temp-buffer
(insert path)
(unless (file-directory-p path)
(insert "\n--------------------------\n")
(insert-file-contents path nil))
(buffer-string)))))
(defun achead:ac-candidates ()
"Candidate-collecting function for `auto-complete'."
(ignore-errors
(setq achead:ac-latest-results-alist (achead:get-include-file-candidates (file-name-directory ac-prefix)))
(cl-loop for (candidate . path) in achead:ac-latest-results-alist
collect candidate)))
(ac-define-source c-headers
`((init . (setq achead:include-cache nil))
(candidates . achead:ac-candidates)
(prefix . ,achead:ac-prefix)
(document . achead:documentation-for-candidate)
(requires . 0)
(symbol . "I")
(action . ac-start)
(limit . nil)))
(provide 'auto-complete-c-headers)
;;; auto-complete-c-headers.el ends here