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