1 ;;; 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 18 ;; "clang" variable below refers to the "clang" executable, 19 ;; 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 ;; 35 ;; Finally, to try Clang-based code completion in a particular buffer, 36 ;; use M-x clang-completion-mode. When "Clang-CC" shows up in the mode 37 ;; line, Clang's code-completion is enabled. 38 ;; 39 ;; Clang's code completion is based on parsing the complete source 40 ;; file up to the point where the cursor is located. Therefore, Clang 41 ;; needs all of the various compilation flags (include paths, dialect 42 ;; options, etc.) to provide code-completion results. Currently, these 43 ;; need to be placed into the clang-flags variable in a format 44 ;; acceptable to clang. This is a hack: patches are welcome to 45 ;; improve the interface between this Emacs mode and Clang! 46 ;; 47 48 ;;; Code: 49 ;;; The clang executable 50 (defcustom clang "clang" 51 "The location of the Clang compiler executable" 52 :type 'file 53 :group 'clang-completion-mode) 54 55 ;;; Extra compilation flags to pass to clang. 56 (defcustom clang-flags nil 57 "Extra flags to pass to the Clang executable. 58 This variable will typically contain include paths, e.g., -I~/MyProject." 59 :type '(repeat (string :tag "Argument" "")) 60 :group 'clang-completion-mode) 61 62 ;;; The prefix header to use with Clang code completion. 63 (setq clang-completion-prefix-header "") 64 65 ;;; The substring we will use to filter completion results 66 (setq clang-completion-substring "") 67 68 ;;; The current completion buffer 69 (setq clang-completion-buffer nil) 70 71 (setq clang-result-string "") 72 73 ;;; Compute the current line in the buffer 74 (defun current-line () 75 "Return the vertical position of point..." 76 (+ (count-lines (point-min) (point)) 77 (if (= (current-column) 0) 1 0) 78 -1)) 79 80 ;;; Set the Clang prefix header 81 (defun clang-prefix-header () 82 (interactive) 83 (setq clang-completion-prefix-header 84 (read-string "Clang prefix header> " "" clang-completion-prefix-header 85 ""))) 86 87 ;; Process "filter" that keeps track of the code-completion results 88 ;; produced. We store all of the results in a string, then the 89 ;; sentinel processes the entire string at once. 90 (defun clang-completion-stash-filter (proc string) 91 (setq clang-result-string (concat clang-result-string string))) 92 93 ;; Filter the given list based on a predicate. 94 (defun filter (condp lst) 95 (delq nil 96 (mapcar (lambda (x) (and (funcall condp x) x)) lst))) 97 98 ;; Determine whether 99 (defun is-completion-line (line) 100 (or (string-match "OVERLOAD:" line) 101 (string-match (concat "COMPLETION: " clang-completion-substring) line))) 102 103 (defun clang-completion-display (buffer) 104 (let* ((all-lines (split-string clang-result-string "\n")) 105 (completion-lines (filter 'is-completion-line all-lines))) 106 (if (consp completion-lines) 107 (progn 108 ;; Erase the process buffer 109 (let ((cur (current-buffer))) 110 (set-buffer buffer) 111 (goto-char (point-min)) 112 (erase-buffer) 113 (set-buffer cur)) 114 115 ;; Display the process buffer 116 (display-buffer buffer) 117 118 ;; Insert the code-completion string into the process buffer. 119 (with-current-buffer buffer 120 (insert (mapconcat 'identity completion-lines "\n"))) 121 )))) 122 123 ;; Process "sentinal" that, on successful code completion, replaces the 124 ;; contents of the code-completion buffer with the new code-completion results 125 ;; and ensures that the buffer is visible. 126 (defun clang-completion-sentinel (proc event) 127 (let* ((all-lines (split-string clang-result-string "\n")) 128 (completion-lines (filter 'is-completion-line all-lines))) 129 (if (consp completion-lines) 130 (progn 131 ;; Erase the process buffer 132 (let ((cur (current-buffer))) 133 (set-buffer (process-buffer proc)) 134 (goto-char (point-min)) 135 (erase-buffer) 136 (set-buffer cur)) 137 138 ;; Display the process buffer 139 (display-buffer (process-buffer proc)) 140 141 ;; Insert the code-completion string into the process buffer. 142 (with-current-buffer (process-buffer proc) 143 (insert (mapconcat 'identity completion-lines "\n"))) 144 )))) 145 146 (defun clang-complete () 147 (let* ((cc-point (concat (buffer-file-name) 148 ":" 149 (number-to-string (+ 1 (current-line))) 150 ":" 151 (number-to-string (+ 1 (current-column))))) 152 (cc-pch (if (equal clang-completion-prefix-header "") nil 153 (list "-include-pch" 154 (concat clang-completion-prefix-header ".pch")))) 155 (cc-flags (if (listp clang-flags) clang-flags nil)) 156 (cc-command (append `(,clang "-cc1" "-fsyntax-only") 157 cc-flags 158 cc-pch 159 `("-code-completion-at" ,cc-point) 160 (list (buffer-file-name)))) 161 (cc-buffer-name (concat "*Clang Completion for " (buffer-name) "*"))) 162 ;; Start the code-completion process 163 (if (buffer-file-name) 164 (progn 165 ;; If there is already a code-completion process, kill it first. 166 (let ((cc-proc (get-process "Clang Code-Completion"))) 167 (if cc-proc 168 (delete-process cc-proc))) 169 170 (setq clang-completion-substring "") 171 (setq clang-result-string "") 172 (setq clang-completion-buffer cc-buffer-name) 173 174 (let ((cc-proc (apply 'start-process 175 (append (list "Clang Code-Completion" cc-buffer-name) 176 cc-command)))) 177 (set-process-filter cc-proc 'clang-completion-stash-filter) 178 (set-process-sentinel cc-proc 'clang-completion-sentinel) 179 ))))) 180 181 ;; Code-completion when one of the trigger characters is typed into 182 ;; the buffer, e.g., '(', ',' or '.'. 183 (defun clang-complete-self-insert (arg) 184 (interactive "p") 185 (self-insert-command arg) 186 (save-buffer) 187 (clang-complete)) 188 189 ;; When the user has typed a character that requires the filter to be 190 ;; updated, do so (and update the display of results). 191 (defun clang-update-filter () 192 (setq clang-completion-substring (thing-at-point 'symbol)) 193 (if (get-process "Clang Code-Completion") 194 () 195 (clang-completion-display clang-completion-buffer) 196 )) 197 198 ;; Invoked when the user types an alphanumeric character or "_" to 199 ;; update the filter for the currently-active code completion. 200 (defun clang-filter-self-insert (arg) 201 (interactive "p") 202 (self-insert-command arg) 203 (clang-update-filter) 204 ) 205 206 ;; Invoked when the user types the backspace key to update the filter 207 ;; for the currently-active code completion. 208 (defun clang-backspace () 209 (interactive) 210 (delete-backward-char 1) 211 (clang-update-filter)) 212 213 ;; Invoked when the user types the delete key to update the filter 214 ;; for the currently-active code completion. 215 (defun clang-delete () 216 (interactive) 217 (delete-backward-char 1) 218 (clang-update-filter)) 219 220 ;; Set up the keymap for the Clang minor mode. 221 (defvar clang-completion-mode-map nil 222 "Keymap for Clang Completion Mode.") 223 224 (if (null clang-completion-mode-map) 225 (fset 'clang-completion-mode-map 226 (setq clang-completion-mode-map (make-sparse-keymap)))) 227 228 (if (not (assq 'clang-completion-mode minor-mode-map-alist)) 229 (setq minor-mode-map-alist 230 (cons (cons 'clang-completion-mode clang-completion-mode-map) 231 minor-mode-map-alist))) 232 233 ;; Punctuation characters trigger code completion. 234 (dolist (char '("(" "," "." ">" ":" "=" ")" " ")) 235 (define-key clang-completion-mode-map char 'clang-complete-self-insert)) 236 237 ;; Alphanumeric characters (and "_") filter the results of the 238 ;; currently-active code completion. 239 (dolist (char '("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" 240 "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" 241 "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" 242 "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" 243 "_" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9")) 244 (define-key clang-completion-mode-map char 'clang-filter-self-insert)) 245 246 ;; Delete and backspace filter the results of the currently-active 247 ;; code completion. 248 (define-key clang-completion-mode-map [(backspace)] 'clang-backspace) 249 (define-key clang-completion-mode-map [(delete)] 'clang-delete) 250 251 ;; Set up the Clang minor mode. 252 (define-minor-mode clang-completion-mode 253 "Clang code-completion mode" 254 nil 255 " Clang" 256 clang-completion-mode-map) 257 258