152 lines
5.5 KiB
EmacsLisp
152 lines
5.5 KiB
EmacsLisp
(eval-when-compile (require 'cl))
|
|
|
|
(defvar clang-executable "clang")
|
|
(defvar clang-completion-doc-table (make-hash-table :test 'equal))
|
|
|
|
;; 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)
|
|
(defvar clang-completion-suppress-error nil)
|
|
|
|
(defun clang-process-exec (command)
|
|
(with-output-to-string
|
|
(with-current-buffer standard-output
|
|
(unless (or (eq (apply 'call-process (car command) nil '(t ".clang-completion-error") nil (cdr command)) 0) clang-completion-suppress-error)
|
|
(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-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 (list clang-executable "-cc1"
|
|
filename "-fsyntax-only" "-code-completion-at"
|
|
(format "%s:%s:%s" 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))))
|
|
(message (format "complete at %s:%s:%s" filename row col))
|
|
(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)
|