1 ;;; company-clang.el --- company-mode completion back-end for Clang
3 ;; Copyright (C) 2009, 2011, 2013 Free Software Foundation, Inc.
5 ;; Author: Nikolaj Schumacher
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
29 (require 'company-template)
30 (eval-when-compile (require 'cl))
32 (defgroup company-clang nil
33 "Completion back-end for Clang."
36 (defcustom company-clang-executable
37 (executable-find "clang")
38 "Location of clang executable."
41 (defcustom company-clang-begin-after-member-access t
42 "When non-nil, automatic completion will start whenever the current
43 symbol is preceded by \".\", \"->\" or \"::\", ignoring
44 `company-minimum-prefix-length'.
46 If `company-begin-commands' is a list, it should include `c-electric-lt-gt'
47 and `c-electric-colon', for automatic completion right after \">\" and
50 (defcustom company-clang-arguments nil
51 "Additional arguments to pass to clang when completing.
52 Prefix files (-include ...) can be selected with `company-clang-set-prefix'
53 or automatically through a custom `company-clang-prefix-guesser'."
54 :type '(repeat (string :tag "Argument" nil)))
56 (defcustom company-clang-prefix-guesser 'company-clang-guess-prefix
57 "A function to determine the prefix file for the current buffer."
58 :type '(function :tag "Guesser function" nil))
60 (defvar company-clang-modes '(c-mode c++-mode objc-mode)
61 "Major modes which clang may complete.")
63 ;; prefix ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
65 (defvar company-clang--prefix nil)
67 (defsubst company-clang--guess-pch-file (file)
68 (let ((dir (directory-file-name (file-name-directory file))))
69 (when (equal (file-name-nondirectory dir) "Classes")
70 (setq dir (file-name-directory dir)))
71 (car (directory-files dir t "\\([^.]h\\|[^h]\\).pch\\'" t))))
73 (defsubst company-clang--file-substring (file beg end)
75 (insert-file-contents-literally file nil beg end)
78 (defun company-clang-guess-prefix ()
79 "Try to guess the prefix file for the current buffer."
80 ;; Prefixes seem to be called .pch. Pre-compiled headers do, too.
81 ;; So we look at the magic number to rule them out.
82 (let* ((file (company-clang--guess-pch-file buffer-file-name))
83 (magic-number (and file (company-clang--file-substring file 0 4))))
84 (unless (member magic-number '("CPCH" "gpch"))
87 (defun company-clang-set-prefix (&optional prefix)
88 "Use PREFIX as a prefix (-include ...) file for clang completion."
89 (interactive (let ((def (funcall company-clang-prefix-guesser)))
91 (setq def default-directory))
92 (list (read-file-name "Prefix file: "
93 (when def (file-name-directory def))
94 def t (when def (file-name-nondirectory def))))))
96 (setq company-clang--prefix (and (stringp prefix)
97 (file-regular-p prefix)
101 (add-hook 'kill-emacs-hook 'company-clang-set-prefix)
103 ;; parsing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
105 ;; TODO: Handle Pattern (syntactic hints would be neat).
106 ;; Do we ever see OVERLOAD (or OVERRIDE)?
107 (defconst company-clang--completion-pattern
108 "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?$")
110 (defconst company-clang--error-buffer-name "*clang error*")
112 (defvar company-clang--meta-cache nil)
114 (defun company-clang--lang-option ()
115 (if (eq major-mode 'objc-mode)
116 (if (string= "m" (file-name-extension buffer-file-name))
117 "objective-c" "objective-c++")
118 (substring (symbol-name major-mode) 0 -5)))
120 (defun company-clang--parse-output (prefix objc)
121 (goto-char (point-min))
122 (let ((pattern (format company-clang--completion-pattern
123 (regexp-quote prefix)))
124 (case-fold-search nil)
126 (setq company-clang--meta-cache (make-hash-table :test 'equal))
127 (while (re-search-forward pattern nil t)
128 (setq match (match-string-no-properties 1))
129 (unless (equal match "Pattern")
130 (let ((meta (match-string-no-properties 2)))
131 (when (and meta (not (string= match meta)))
132 (setq meta (company-clang--strip-formatting meta))
133 (when (and (not objc) (string-match "\\((.*)\\)" meta))
134 (setq match (concat match (match-string 1 meta))))
135 (puthash match meta company-clang--meta-cache)))
139 (defun company-clang--strip-formatting (text)
140 (replace-regexp-in-string
142 (replace-regexp-in-string "[<{[]#\\|#[>}]" "" text t)
145 (defun company-clang--handle-error (res args)
146 (goto-char (point-min))
147 (let* ((buf (get-buffer-create company-clang--error-buffer-name))
148 (cmd (concat company-clang-executable " " (mapconcat 'identity args " ")))
149 (pattern (format company-clang--completion-pattern ""))
150 (err (if (re-search-forward pattern nil t)
151 (buffer-substring-no-properties (point-min)
152 (1- (match-beginning 0)))
153 ;; Warn the user more aggressively if no match was found.
154 (message "clang failed with error %d:\n%s" res cmd)
157 (with-current-buffer buf
158 (let ((inhibit-read-only t))
160 (insert (current-time-string)
161 (format "\nclang failed with error %d:\n" res)
164 (setq buffer-read-only t)
165 (goto-char (point-min))))))
167 (defun company-clang--call-process (prefix &rest args)
168 (let ((objc (derived-mode-p 'objc-mode))
169 (buf (get-buffer-create "*clang-output*"))
171 (with-current-buffer buf (erase-buffer))
172 (setq res (if (company-clang--auto-save-p)
173 (apply 'call-process company-clang-executable nil buf nil args)
174 (apply 'call-process-region (point-min) (point-max)
175 company-clang-executable nil buf nil args)))
176 (with-current-buffer buf
178 (company-clang--handle-error res args))
179 ;; Still try to get any useful input.
180 (company-clang--parse-output prefix objc))))
182 (defsubst company-clang--build-location (pos)
186 (if (company-clang--auto-save-p) buffer-file-name "-")
188 (1+ (current-column)))))
190 (defsubst company-clang--build-complete-args (pos)
191 (append '("-cc1" "-fsyntax-only" "-code-completion-macros")
192 (unless (company-clang--auto-save-p)
193 (list "-x" (company-clang--lang-option)))
194 company-clang-arguments
195 (when (stringp company-clang--prefix)
196 (list "-include" (expand-file-name company-clang--prefix)))
197 '("-code-completion-at")
198 (list (company-clang--build-location pos))
199 (list (if (company-clang--auto-save-p) buffer-file-name "-"))))
201 (defun company-clang--candidates (prefix)
202 (and (company-clang--auto-save-p)
205 (when (null company-clang--prefix)
206 (company-clang-set-prefix (or (funcall company-clang-prefix-guesser)
208 (apply 'company-clang--call-process
210 (company-clang--build-complete-args (- (point) (length prefix)))))
212 (defun company-clang--prefix ()
213 (let ((symbol (company-grab-symbol)))
215 (if (and company-clang-begin-after-member-access
217 (forward-char (- (length symbol)))
218 (looking-back "\\.\\|->\\|::" (- (point) 2))))
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
225 (defconst company-clang-required-version 1.1)
227 (defvar company-clang--version nil)
229 (defun company-clang--auto-save-p ()
230 (< company-clang--version 2.9))
232 (defsubst company-clang-version ()
233 "Return the version of `company-clang-executable'."
235 (call-process company-clang-executable nil t nil "--version")
236 (goto-char (point-min))
237 (if (re-search-forward "clang\\(?: version \\|-\\)\\([0-9.]+\\)" nil t)
238 (let ((ver (string-to-number (match-string-no-properties 1))))
244 (defun company-clang-objc-templatify (selector)
245 (let* ((end (point-marker))
246 (beg (- (point) (length selector)))
247 (templ (company-template-declare-template beg end))
252 (while (search-forward ":" end t)
253 (company-template-add-field templ (point) (format "arg%d" cnt))
258 (company-template-move-to-first templ)))
260 (defun company-clang (command &optional arg &rest ignored)
261 "`company-mode' completion back-end for Clang.
262 Clang is a parser for C and ObjC. Clang version 1.1 or newer is required.
264 Additional command line arguments can be specified in
265 `company-clang-arguments'. Prefix files (-include ...) can be selected
266 with `company-clang-set-prefix' or automatically through a custom
267 `company-clang-prefix-guesser'.
269 With Clang versions before 2.9, we have to save the buffer before
270 performing completion. With Clang 2.9 and later, buffer contents are
271 passed via standard input."
272 (interactive (list 'interactive))
274 (interactive (company-begin-backend 'company-clang))
275 (init (when (memq major-mode company-clang-modes)
276 (unless company-clang-executable
277 (error "Company found no clang executable"))
278 (setq company-clang--version (company-clang-version))
279 (when (< company-clang--version company-clang-required-version)
280 (error "Company requires clang version 1.1"))))
281 (prefix (and (memq major-mode company-clang-modes)
283 company-clang-executable
284 (not (company-in-string-or-comment))
285 (company-clang--prefix)))
286 (candidates (company-clang--candidates arg))
287 (meta (gethash arg company-clang--meta-cache))
288 (crop (and (string-match ":\\|(" arg)
289 (substring arg 0 (match-beginning 0))))
290 (post-completion (cond
291 ((not (derived-mode-p 'objc-mode))
292 (company-template-c-like-templatify arg))
293 ((string-match ":" arg)
294 (company-clang-objc-templatify arg))))))
296 (provide 'company-clang)
297 ;;; company-clang.el ends here