clang-completion-mode.el [plain text]
(defcustom clang "clang"
"The location of the Clang compiler executable"
:type 'file
:group 'clang-completion-mode)
(defcustom clang-flags nil
"Extra flags to pass to the Clang executable.
This variable will typically contain include paths, e.g., -I~/MyProject."
:type '(repeat (string :tag "Argument" ""))
:group 'clang-completion-mode)
(setq clang-completion-prefix-header "")
(setq clang-completion-substring "")
(setq clang-completion-buffer nil)
(setq clang-result-string "")
(defun current-line ()
"Return the vertical position of point..."
(+ (count-lines (point-min) (point))
(if (= (current-column) 0) 1 0)
-1))
(defun clang-prefix-header ()
(interactive)
(setq clang-completion-prefix-header
(read-string "Clang prefix header> " "" clang-completion-prefix-header
"")))
(defun clang-completion-stash-filter (proc string)
(setq clang-result-string (concat clang-result-string string)))
(defun filter (condp lst)
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))
(defun is-completion-line (line)
(or (string-match "OVERLOAD:" line)
(string-match (concat "COMPLETION: " clang-completion-substring) line)))
(defun clang-completion-display (buffer)
(let* ((all-lines (split-string clang-result-string "\n"))
(completion-lines (filter 'is-completion-line all-lines)))
(if (consp completion-lines)
(progn
(let ((cur (current-buffer)))
(set-buffer buffer)
(goto-char (point-min))
(erase-buffer)
(set-buffer cur))
(display-buffer buffer)
(with-current-buffer buffer
(insert (mapconcat 'identity completion-lines "\n")))
))))
(defun clang-completion-sentinel (proc event)
(let* ((all-lines (split-string clang-result-string "\n"))
(completion-lines (filter 'is-completion-line all-lines)))
(if (consp completion-lines)
(progn
(let ((cur (current-buffer)))
(set-buffer (process-buffer proc))
(goto-char (point-min))
(erase-buffer)
(set-buffer cur))
(display-buffer (process-buffer proc))
(with-current-buffer (process-buffer proc)
(insert (mapconcat 'identity completion-lines "\n")))
))))
(defun clang-complete ()
(let* ((cc-point (concat (buffer-file-name)
":"
(number-to-string (+ 1 (current-line)))
":"
(number-to-string (+ 1 (current-column)))))
(cc-pch (if (equal clang-completion-prefix-header "") nil
(list "-include-pch"
(concat clang-completion-prefix-header ".pch"))))
(cc-flags (if (listp clang-flags) clang-flags nil))
(cc-command (append `(,clang "-cc1" "-fsyntax-only")
cc-flags
cc-pch
`("-code-completion-at" ,cc-point)
(list (buffer-file-name))))
(cc-buffer-name (concat "*Clang Completion for " (buffer-name) "*")))
(if (buffer-file-name)
(progn
(let ((cc-proc (get-process "Clang Code-Completion")))
(if cc-proc
(delete-process cc-proc)))
(setq clang-completion-substring "")
(setq clang-result-string "")
(setq clang-completion-buffer cc-buffer-name)
(let ((cc-proc (apply 'start-process
(append (list "Clang Code-Completion" cc-buffer-name)
cc-command))))
(set-process-filter cc-proc 'clang-completion-stash-filter)
(set-process-sentinel cc-proc 'clang-completion-sentinel)
)))))
(defun clang-complete-self-insert (arg)
(interactive "p")
(self-insert-command arg)
(save-buffer)
(clang-complete))
(defun clang-update-filter ()
(setq clang-completion-substring (thing-at-point 'symbol))
(if (get-process "Clang Code-Completion")
()
(clang-completion-display clang-completion-buffer)
))
(defun clang-filter-self-insert (arg)
(interactive "p")
(self-insert-command arg)
(clang-update-filter)
)
(defun clang-backspace ()
(interactive)
(delete-backward-char 1)
(clang-update-filter))
(defun clang-delete ()
(interactive)
(delete-backward-char 1)
(clang-update-filter))
(defvar clang-completion-mode-map nil
"Keymap for Clang Completion Mode.")
(if (null clang-completion-mode-map)
(fset 'clang-completion-mode-map
(setq clang-completion-mode-map (make-sparse-keymap))))
(if (not (assq 'clang-completion-mode minor-mode-map-alist))
(setq minor-mode-map-alist
(cons (cons 'clang-completion-mode clang-completion-mode-map)
minor-mode-map-alist)))
(dolist (char '("(" "," "." ">" ":" "=" ")" " "))
(define-key clang-completion-mode-map char 'clang-complete-self-insert))
(dolist (char '("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O"
"P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
"a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
"p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
"_" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
(define-key clang-completion-mode-map char 'clang-filter-self-insert))
(define-key clang-completion-mode-map [(backspace)] 'clang-backspace)
(define-key clang-completion-mode-map [(delete)] 'clang-delete)
(define-minor-mode clang-completion-mode
"Clang code-completion mode"
nil
" Clang"
clang-completion-mode-map)