]> code.delx.au - gnu-emacs-elpa/blobdiff - company-clang.el
company-backends: Move semantic in front of clang
[gnu-emacs-elpa] / company-clang.el
index 7fc66a93b9c0e725fb7e731e89589e59f0e8f13e..60e29c1694c15a96812c47bbfadf3375a55ce37f 100644 (file)
@@ -1,4 +1,4 @@
-;;; company-clang.el --- A company-mode completion back-end for clang
+;;; company-clang.el --- company-mode completion back-end for Clang
 
 ;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
 
 ;;; Code:
 
 (require 'company)
+(require 'company-template)
 (eval-when-compile (require 'cl))
 
+(defgroup company-clang nil
+  "Completion back-end for Clang."
+  :group 'company)
+
 (defcustom company-clang-executable
   (executable-find "clang")
   "Location of clang executable."
-  :group 'company-clang
   :type 'file)
 
 (defcustom company-clang-auto-save t
   "Determines whether to save the buffer when retrieving completions.
 clang can only complete correctly when the buffer has been saved."
-  :group 'company-clang
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
@@ -46,15 +49,13 @@ clang can only complete correctly when the buffer has been saved."
 Prefix files (-include ...) can be selected with
 `company-clang-set-prefix' or automatically through a custom
 `company-clang-prefix-guesser'."
-  :group 'company-clang
   :type '(repeat (string :tag "Argument" nil)))
 
 (defcustom company-clang-prefix-guesser 'company-clang-guess-prefix
   "A function to determine the prefix file for the current buffer."
-  :group 'company-clang
   :type '(function :tag "Guesser function" nil))
 
-(defvar company-clang-modes '(c-mode objc-mode)
+(defvar company-clang-modes '(c-mode c++-mode objc-mode)
   "Major modes which clang may complete.")
 
 ;; prefix ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -99,15 +100,16 @@ Prefix files (-include ...) can be selected with
 
 ;; parsing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; TODO: How to handle OVERLOAD and Pattern?
+;; TODO: Handle Pattern (syntactic hints would be neat).
+;; Do we ever see OVERLOAD (or OVERRIDE)?
 (defconst company-clang--completion-pattern
-  "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?")
+  "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?$")
 
 (defconst company-clang--error-buffer-name "*clang error*")
 
 (defvar company-clang--meta-cache nil)
 
-(defun company-clang--parse-output (prefix)
+(defun company-clang--parse-output (prefix objc)
   (goto-char (point-min))
   (let ((pattern (format company-clang--completion-pattern
                          (regexp-quote prefix)))
@@ -116,13 +118,22 @@ Prefix files (-include ...) can be selected with
     (setq company-clang--meta-cache (make-hash-table :test 'equal))
     (while (re-search-forward pattern nil t)
       (setq match (match-string-no-properties 1))
-      (let ((meta (match-string-no-properties 2)))
-        (when (and meta (not (string= match meta)))
-          (puthash match meta company-clang--meta-cache)))
       (unless (equal match "Pattern")
+        (let ((meta (match-string-no-properties 2)))
+          (when (and meta (not (string= match meta)))
+            (setq meta (company-clang--strip-formatting meta))
+            (when (and (not objc) (string-match "\\((.*)\\)" meta))
+              (setq match (concat match (match-string 1 meta))))
+            (puthash match meta company-clang--meta-cache)))
         (push match lines)))
     lines))
 
+(defun company-clang--strip-formatting (text)
+  (replace-regexp-in-string
+   "#]" " "
+   (replace-regexp-in-string "[<{[]#\\|#[>}]" "" text t)
+   t))
+
 (defun company-clang--handle-error (res args)
   (goto-char (point-min))
   (let* ((buf (get-buffer-create company-clang--error-buffer-name))
@@ -146,12 +157,13 @@ Prefix files (-include ...) can be selected with
         (goto-char (point-min))))))
 
 (defun company-clang--call-process (prefix &rest args)
-  (with-temp-buffer
-    (let ((res (apply 'call-process company-clang-executable nil t nil args)))
-      (unless (eq 0 res)
-        (company-clang--handle-error res args))
-      ;; Still try to get any useful input.
-      (company-clang--parse-output prefix))))
+  (let ((objc (derived-mode-p 'objc-mode)))
+    (with-temp-buffer
+      (let ((res (apply 'call-process company-clang-executable nil t nil args)))
+        (unless (eq 0 res)
+          (company-clang--handle-error res args))
+        ;; Still try to get any useful input.
+        (company-clang--parse-output prefix objc)))))
 
 (defsubst company-clang--build-location (pos)
   (save-excursion
@@ -198,18 +210,25 @@ Prefix files (-include ...) can be selected with
 (defun company-clang-objc-templatify (selector)
   (let* ((end (point))
          (beg (- (point) (length selector)))
-         (templ (company-template-declare-template beg end)))
+         (templ (company-template-declare-template beg end))
+         (cnt 0))
     (save-excursion
       (goto-char beg)
       (while (search-forward ":" end t)
-        (replace-match ": ")
-        (incf end)
-        (company-template-add-field templ (1- (match-end 0)) "<arg>"))
-      (delete-char -1))
+        (let* ((name (format "arg%d" cnt))
+               (len (length name)))
+          (incf end len)
+          (let ((pt (point)))
+            (insert name)
+            (company-template-add-field templ pt (point)))
+          (when (< (point) end)
+            (insert " ")
+            (incf end))
+          (incf cnt))))
     (company-template-move-to-first templ)))
 
 (defun company-clang (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for clang.
+  "`company-mode' completion back-end for Clang.
 Clang is a parser for C and ObjC.  Clang version 1.1 or newer is required.
 
 Additional command line arguments can be specified in
@@ -233,15 +252,14 @@ Completions only work correctly when the buffer has been saved.
                  (not (company-in-string-or-comment))
                  (or (company-grab-symbol) 'stop)))
     (candidates (company-clang--candidates arg))
-    (meta (let ((meta (gethash arg company-clang--meta-cache)))
-            (when meta
-              (replace-regexp-in-string
-               "#]" " "
-               (replace-regexp-in-string "[<{[]#\\|#[>}]" "" meta t)
-               t))))
-    (post-completion (and (derived-mode-p 'objc-mode)
-                          (string-match ":" arg)
-                          (company-clang-objc-templatify arg)))))
+    (meta (gethash arg company-clang--meta-cache))
+    (crop (and (string-match ":\\|(" arg)
+               (substring arg 0 (match-beginning 0))))
+    (post-completion (cond
+                      ((not (derived-mode-p 'objc-mode))
+                       (company-template-c-like-templatify arg))
+                      ((string-match ":" arg)
+                       (company-clang-objc-templatify arg))))))
 
 (provide 'company-clang)
 ;;; company-clang.el ends here