blob: 6cf5cb574519f70dd1a848d15688ab3495ed257a [file] [log] [blame]
Douglas Gregora584fb32009-10-09 22:17:40 +00001;;; Clang Code-Completion minor mode, for use with C/Objective-C/C++.
2
3;;; Commentary:
4
5;; This minor mode uses Clang's command line interface for code
6;; completion to provide code completion results for C, Objective-C,
7;; and C++ source files. When enabled, Clang will provide
8;; code-completion results in a secondary buffer based on the code
9;; being typed. For example, after typing "struct " (triggered via the
10;; space), Clang will provide the names of all structs visible from
11;; the current scope. After typing "p->" (triggered via the ">"),
12;; Clang will provide the names of all of the members of whatever
13;; class/struct/union "p" points to. Note that this minor mode isn't
14;; meant for serious use: it is meant to help experiment with code
15;; completion based on Clang. It needs your help to make it better!
16;;
17;; To use the Clang code completion mode, first make sure that the
Douglas Gregord2407242009-12-11 23:47:56 +000018;; "clang" variable below refers to the "clang" executable,
Douglas Gregora584fb32009-10-09 22:17:40 +000019;; which is typically installed in libexec/. Then, place
20;; clang-completion-mode.el somewhere in your Emacs load path. You can
21;; add a new load path to Emacs by adding some like the following to
22;; your .emacs:
23;;
24;; (setq load-path (cons "~/.emacs.d" load-path))
25;;
26;; Then, use
27;;
28;; M-x load-library
29;;
30;; to load the library in your Emacs session or add the following to
31;; your .emacs to always load this mode (not recommended):
32;;
33;; (load-library "clang-completion-mode")
34;;
Douglas Gregor3f1a5a22012-06-07 22:33:29 +000035;; Once you have done this, you can set various parameters with
36;;
37;; M-x customize-group RET clang-completion-mode RET
38;;
Douglas Gregora584fb32009-10-09 22:17:40 +000039;; Finally, to try Clang-based code completion in a particular buffer,
Douglas Gregor3f1a5a22012-06-07 22:33:29 +000040;; use M-x clang-completion-mode. When "Clang" shows up in the mode
Douglas Gregora584fb32009-10-09 22:17:40 +000041;; line, Clang's code-completion is enabled.
42;;
43;; Clang's code completion is based on parsing the complete source
44;; file up to the point where the cursor is located. Therefore, Clang
45;; needs all of the various compilation flags (include paths, dialect
46;; options, etc.) to provide code-completion results. Currently, these
Douglas Gregord2407242009-12-11 23:47:56 +000047;; need to be placed into the clang-flags variable in a format
48;; acceptable to clang. This is a hack: patches are welcome to
Douglas Gregora584fb32009-10-09 22:17:40 +000049;; improve the interface between this Emacs mode and Clang!
50;;
51
52;;; Code:
Douglas Gregord2407242009-12-11 23:47:56 +000053;;; The clang executable
54(defcustom clang "clang"
55 "The location of the Clang compiler executable"
Douglas Gregora584fb32009-10-09 22:17:40 +000056 :type 'file
57 :group 'clang-completion-mode)
58
Douglas Gregord2407242009-12-11 23:47:56 +000059;;; Extra compilation flags to pass to clang.
Douglas Gregored378362010-12-14 16:52:29 +000060(defcustom clang-flags nil
Douglas Gregora584fb32009-10-09 22:17:40 +000061 "Extra flags to pass to the Clang executable.
62This variable will typically contain include paths, e.g., -I~/MyProject."
Douglas Gregored378362010-12-14 16:52:29 +000063 :type '(repeat (string :tag "Argument" ""))
Douglas Gregora584fb32009-10-09 22:17:40 +000064 :group 'clang-completion-mode)
65
66;;; The prefix header to use with Clang code completion.
67(setq clang-completion-prefix-header "")
68
69;;; The substring we will use to filter completion results
70(setq clang-completion-substring "")
71
72;;; The current completion buffer
73(setq clang-completion-buffer nil)
74
Douglas Gregord2407242009-12-11 23:47:56 +000075(setq clang-result-string "")
Douglas Gregora584fb32009-10-09 22:17:40 +000076
77;;; Compute the current line in the buffer
78(defun current-line ()
79 "Return the vertical position of point..."
80 (+ (count-lines (point-min) (point))
81 (if (= (current-column) 0) 1 0)
82 -1))
83
84;;; Set the Clang prefix header
85(defun clang-prefix-header ()
86 (interactive)
87 (setq clang-completion-prefix-header
88 (read-string "Clang prefix header> " "" clang-completion-prefix-header
89 "")))
90
91;; Process "filter" that keeps track of the code-completion results
92;; produced. We store all of the results in a string, then the
93;; sentinel processes the entire string at once.
94(defun clang-completion-stash-filter (proc string)
Douglas Gregord2407242009-12-11 23:47:56 +000095 (setq clang-result-string (concat clang-result-string string)))
Douglas Gregora584fb32009-10-09 22:17:40 +000096
97;; Filter the given list based on a predicate.
98(defun filter (condp lst)
99 (delq nil
100 (mapcar (lambda (x) (and (funcall condp x) x)) lst)))
101
Gabor Greife47398a2012-04-24 15:42:03 +0000102;; Determine whether FIXME: explain better
Douglas Gregora584fb32009-10-09 22:17:40 +0000103(defun is-completion-line (line)
104 (or (string-match "OVERLOAD:" line)
105 (string-match (concat "COMPLETION: " clang-completion-substring) line)))
106
Douglas Gregor3f1a5a22012-06-07 22:33:29 +0000107
108;; re-process the completions when further input narrows the field
Douglas Gregora584fb32009-10-09 22:17:40 +0000109(defun clang-completion-display (buffer)
Douglas Gregor3f1a5a22012-06-07 22:33:29 +0000110 (fill-buffer buffer))
111
112(defun fill-buffer (buffer)
Douglas Gregord2407242009-12-11 23:47:56 +0000113 (let* ((all-lines (split-string clang-result-string "\n"))
Douglas Gregora584fb32009-10-09 22:17:40 +0000114 (completion-lines (filter 'is-completion-line all-lines)))
115 (if (consp completion-lines)
116 (progn
Gabor Greife47398a2012-04-24 15:42:03 +0000117 ;; Erase the process buffer.
Douglas Gregora584fb32009-10-09 22:17:40 +0000118 (let ((cur (current-buffer)))
119 (set-buffer buffer)
120 (goto-char (point-min))
121 (erase-buffer)
122 (set-buffer cur))
123
Gabor Greife47398a2012-04-24 15:42:03 +0000124 ;; Display the process buffer.
Douglas Gregora584fb32009-10-09 22:17:40 +0000125 (display-buffer buffer)
126
127 ;; Insert the code-completion string into the process buffer.
128 (with-current-buffer buffer
129 (insert (mapconcat 'identity completion-lines "\n")))
130 ))))
131
Gabor Greife47398a2012-04-24 15:42:03 +0000132;; Process "sentinel" that, on successful code completion, replaces the
Douglas Gregora584fb32009-10-09 22:17:40 +0000133;; contents of the code-completion buffer with the new code-completion results
134;; and ensures that the buffer is visible.
135(defun clang-completion-sentinel (proc event)
Douglas Gregor3f1a5a22012-06-07 22:33:29 +0000136 (fill-buffer (process-buffer proc)))
Douglas Gregora584fb32009-10-09 22:17:40 +0000137
138(defun clang-complete ()
John McCall7ae43732010-01-13 06:44:51 +0000139 (let* ((cc-point (concat (buffer-file-name)
140 ":"
141 (number-to-string (+ 1 (current-line)))
142 ":"
143 (number-to-string (+ 1 (current-column)))))
144 (cc-pch (if (equal clang-completion-prefix-header "") nil
145 (list "-include-pch"
146 (concat clang-completion-prefix-header ".pch"))))
147 (cc-flags (if (listp clang-flags) clang-flags nil))
148 (cc-command (append `(,clang "-cc1" "-fsyntax-only")
149 cc-flags
150 cc-pch
151 `("-code-completion-at" ,cc-point)
152 (list (buffer-file-name))))
153 (cc-buffer-name (concat "*Clang Completion for " (buffer-name) "*")))
Gabor Greife47398a2012-04-24 15:42:03 +0000154 ;; Start the code-completion process.
Douglas Gregora584fb32009-10-09 22:17:40 +0000155 (if (buffer-file-name)
156 (progn
157 ;; If there is already a code-completion process, kill it first.
158 (let ((cc-proc (get-process "Clang Code-Completion")))
159 (if cc-proc
160 (delete-process cc-proc)))
161
162 (setq clang-completion-substring "")
Douglas Gregord2407242009-12-11 23:47:56 +0000163 (setq clang-result-string "")
Douglas Gregora584fb32009-10-09 22:17:40 +0000164 (setq clang-completion-buffer cc-buffer-name)
165
John McCall7ae43732010-01-13 06:44:51 +0000166 (let ((cc-proc (apply 'start-process
167 (append (list "Clang Code-Completion" cc-buffer-name)
168 cc-command))))
Douglas Gregora584fb32009-10-09 22:17:40 +0000169 (set-process-filter cc-proc 'clang-completion-stash-filter)
170 (set-process-sentinel cc-proc 'clang-completion-sentinel)
171 )))))
172
173;; Code-completion when one of the trigger characters is typed into
174;; the buffer, e.g., '(', ',' or '.'.
175(defun clang-complete-self-insert (arg)
176 (interactive "p")
177 (self-insert-command arg)
178 (save-buffer)
179 (clang-complete))
180
181;; When the user has typed a character that requires the filter to be
182;; updated, do so (and update the display of results).
183(defun clang-update-filter ()
184 (setq clang-completion-substring (thing-at-point 'symbol))
185 (if (get-process "Clang Code-Completion")
186 ()
187 (clang-completion-display clang-completion-buffer)
188 ))
189
190;; Invoked when the user types an alphanumeric character or "_" to
191;; update the filter for the currently-active code completion.
192(defun clang-filter-self-insert (arg)
193 (interactive "p")
194 (self-insert-command arg)
195 (clang-update-filter)
196 )
197
198;; Invoked when the user types the backspace key to update the filter
199;; for the currently-active code completion.
200(defun clang-backspace ()
201 (interactive)
202 (delete-backward-char 1)
203 (clang-update-filter))
204
205;; Invoked when the user types the delete key to update the filter
206;; for the currently-active code completion.
207(defun clang-delete ()
208 (interactive)
209 (delete-backward-char 1)
210 (clang-update-filter))
211
212;; Set up the keymap for the Clang minor mode.
213(defvar clang-completion-mode-map nil
214 "Keymap for Clang Completion Mode.")
215
216(if (null clang-completion-mode-map)
217 (fset 'clang-completion-mode-map
218 (setq clang-completion-mode-map (make-sparse-keymap))))
219
220(if (not (assq 'clang-completion-mode minor-mode-map-alist))
221 (setq minor-mode-map-alist
222 (cons (cons 'clang-completion-mode clang-completion-mode-map)
223 minor-mode-map-alist)))
224
225;; Punctuation characters trigger code completion.
226(dolist (char '("(" "," "." ">" ":" "=" ")" " "))
227 (define-key clang-completion-mode-map char 'clang-complete-self-insert))
228
229;; Alphanumeric characters (and "_") filter the results of the
230;; currently-active code completion.
231(dolist (char '("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O"
232 "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
233 "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
234 "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
235 "_" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
236 (define-key clang-completion-mode-map char 'clang-filter-self-insert))
237
238;; Delete and backspace filter the results of the currently-active
239;; code completion.
240(define-key clang-completion-mode-map [(backspace)] 'clang-backspace)
241(define-key clang-completion-mode-map [(delete)] 'clang-delete)
242
243;; Set up the Clang minor mode.
244(define-minor-mode clang-completion-mode
245 "Clang code-completion mode"
246 nil
Douglas Gregord2407242009-12-11 23:47:56 +0000247 " Clang"
Douglas Gregora584fb32009-10-09 22:17:40 +0000248 clang-completion-mode-map)
249