-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauto-complete-clang.el
156 lines (133 loc) · 5.67 KB
/
auto-complete-clang.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
156
(eval-when-compile (require 'cl))
(defvar clang-executable "clang")
(defvar clang-completion-doc-table (make-hash-table :test 'equal))
(defvar clang-make-executable (executable-find "make"))
;; faces
(defface clang-completion-plain-face
'((t (:inherit default :family "Verdana")))
"clang completion hint base font" :group 'clang-completion-faces)
(defface clang-completion-type-face
'((t (:inherit 'clang-completion-plain-face :foreground "#729FCF" :weight bold :family "Verdana")))
"clang completion hint font for types" :group 'clang-completion-faces)
(defface clang-completion-variable-face
'((t (:inherit 'clang-completion-plain-face :foreground "#73D216" :family "Verdana")))
"clang completion hint font for variables" :group 'clang-completion-faces)
;; extra flags
(defvar clang-completion-pch nil)
(defvar clang-completion-flags nil)
(defun clang-process-exec (command)
(with-output-to-string
(with-current-buffer standard-output
(unless (eq (apply 'call-process (car command) nil '(t ".clang-completion-error") nil (cdr command)) 0)
(let ((last-command compile-command))
;(compile "cat .clang-completion-error")
(setq compile-command last-command))))))
(defun clang-parse-completion-line (line)
(cond ((string-match "^COMPLETION: Pattern" line) nil) ;; exclude patterns
((string-match "^COMPLETION: \\([^ ]*\\)\\(?: : \\([^\"]*\\)\\)$" line)
(list (match-string 1 line) (match-string 2 line)))
((string-match "^OVERRIDE: \\([^ ]*\\)\\(?: : \\([^\"]*\\)\\)$" line)
(list (match-string 1 line) (match-string 2 line)))
(t nil))
)
(defun clang-choose-command (filename row col)
(if (file-exists-p "Makefile")
(list clang-make-executable "check-completions"
(format "COMPLETE_POINT=%s:%s:%s" filename row col)
(format "COMPLETE_SOURCES=%s" filename))
(list clang-executable "-cc1"
filename "-fsyntax-only" "-code-completion-at"
(format "%s:%s:%s" filename row col))))
(defun clang-process (buffer point)
(unless (buffer-file-name buffer)
(return ""))
(let* ((filename (buffer-file-name buffer))
(col (1+ (- point (point-at-bol))))
(row (count-lines point (point-min)))
(cmd (clang-choose-command filename row col)))
;; eval the config file under buffer locations
(let* ((filedir (file-name-directory filename))
(config-filename (concat filedir ".clang-completion-config.el")))
(when (file-readable-p config-filename)
(with-temp-buffer
(insert-file-contents config-filename)
(eval-buffer))))
(when (listp clang-completion-flags)
(setq cmd (append cmd clang-completion-flags)))
(when (stringp clang-completion-pch)
(setq cmd (append cmd (list "-include-pch" clang-completion-pch))))
(clang-process-exec cmd)))
(defun clang-get-process-result (string)
(let* ((completion-lines (split-string string "\n")))
(delq nil (mapcar 'clang-parse-completion-line completion-lines))))
(defun clang-get-process-completion-result (string)
(mapcar 'car (clang-get-process-result string)))
(defun clang-get-process-prototype-table (string)
(let* ((lines (clang-get-process-result string))
(result-table (make-hash-table :test 'equal)))
(dolist (line lines)
(let* ((key (first line))
(value (gethash key result-table)))
(setq value (append value (list (second line))))
(puthash key value result-table))
)
(setq clang-completion-doc-table result-table)))
(defun clang-get-completions (&optional buffer point)
;; save all modified buffers
(or buffer (setq buffer (current-buffer)))
(or point (setq point (point)))
(save-some-buffers t)
(let* ((output (clang-process buffer point)))
(clang-get-process-prototype-table output)
(clang-get-process-completion-result output)))
(defun filter-doc-buffer ()
(while (re-search-backward "\\[#.*?::#\\]" nil t)
(replace-match ""))
(goto-char (point-max))
(while (re-search-backward "\\[#\\|#\\]" nil t)
(replace-match " "))
(goto-char (point-max))
(while (re-search-backward "{#\\|#}\\|<#\\|#>" nil t)
(replace-match ""))
)
(defun clang-get-doc (symbol)
;;(setq symbol (symbol-name (intern-soft symbol)))
(let ((reslist (gethash symbol clang-completion-doc-table)))
(with-temp-buffer
(font-lock-add-keywords nil '(("\\[#\\(.*?\\)#\\]" 1
'clang-completion-type-face t)))
(font-lock-add-keywords nil '(("<#\\(.*?\\)#>" 1
'clang-completion-variable-face t)))
(font-lock-add-keywords nil '(("\\(.*\\)" 1
'clang-completion-plain-face t)))
(font-lock-mode t)
(insert (reduce '(lambda (x y) (concat x "\n" y)) reslist))
(font-lock-fontify-buffer)
(filter-doc-buffer)
(message (buffer-string))))
;;(with-temp-buffer
;; (dolist (proto reslist)
;; (insert proto)
;; (insert "\n\n"))
;; (filter-doc-buffer)
;; (buffer-string))
;; display nothing
(return nil))
(defvar ac-source-clang-complete
'((candidates . (clang-get-completions nil ac-point))
(prefix "[^a-zA-Z0-9_]\\(\\(?:[a-zA-Z_][a-zA-Z0-9_]*\\)?\\)" nil 1)
(document . clang-get-doc)
(requires . 0)
(symbol . "C")
(cache)))
;;(defvar ac-source-clang-static-complete
;; '((candidates . (clang-get-completions nil ac-point))
;; (prefix "::\\(\\(?:[a-zA-Z_][a-zA-Z0-9_]*\\)?\\)" nil 1)
;; ;;(document . 'clang-get-doc)
;; (requires . 0)
;; (symbol . "M")
;; (cache)))
(defun ac-complete-clang ()
(interactive)
(auto-complete '(ac-source-clang-complete)))
(provide 'auto-complete-clang)