]> code.delx.au - gnu-emacs-elpa/blobdiff - company-eclim.el
Make a new release
[gnu-emacs-elpa] / company-eclim.el
index 1637f3cab37859e1ade9ca5bad259153d6b620f2..b37f75602e01fadc1a9110805b0e08fee47f6659 100644 (file)
@@ -1,6 +1,6 @@
-;;; company-eclim.el --- A company-mode completion back-end for eclim.
+;;; company-eclim.el --- company-mode completion backend for Eclim
 
-;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011, 2013, 2015  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
 
 ;;; Commentary:
 ;;
-;; Eclim version 1.7.13 or newer (?) is required.
+;; Using `emacs-eclim' together with (or instead of) this backend is
+;; recommended, as it allows you to use other Eclim features.
 ;;
-;; This completion backend is pretty barebone.
-;;
-;; `emacs-eclim' provides an alternative backend, and it also allows you to
-;; actually control Eclim from Emacs.
+;; The alternative backend provided by `emacs-eclim' uses `yasnippet'
+;; instead of `company-template' to expand function calls, and it supports
+;; some languages other than Java.
 
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'company-template)
+(require 'cl-lib)
+
+(defgroup company-eclim nil
+  "Completion backend for Eclim."
+  :group 'company)
 
 (defun company-eclim-executable-find ()
   (let (file)
-    (dolist (eclipse-root '("/Applications/eclipse" "/usr/lib/eclipse"
+    (cl-dolist (eclipse-root '("/Applications/eclipse" "/usr/lib/eclipse"
                             "/usr/local/lib/eclipse"))
       (and (file-exists-p (setq file (expand-file-name "plugins" eclipse-root)))
            (setq file (car (last (directory-files file t "^org.eclim_"))))
            (file-exists-p (setq file (expand-file-name "bin/eclim" file)))
-           (return file)))))
+           (cl-return file)))))
 
 (defcustom company-eclim-executable
-  (or (executable-find "eclim") (company-eclim-executable-find))
+  (or (bound-and-true-p eclim-executable)
+      (executable-find "eclim")
+      (company-eclim-executable-find))
   "Location of eclim executable."
-  :group 'company
   :type 'file)
 
 (defcustom company-eclim-auto-save t
   "Determines whether to save the buffer when retrieving completions.
 eclim can only complete correctly when the buffer has been saved."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar company-eclim--project-dir 'unknown)
-(make-variable-buffer-local 'company-eclim--project-dir)
+(defvar-local company-eclim--project-dir 'unknown)
 
-(defvar company-eclim--project-name 'unknown)
-(make-variable-buffer-local 'company-eclim--project-name)
+(defvar-local company-eclim--project-name nil)
 
-(defvar company-eclim--doc nil)
-(make-variable-buffer-local 'company-eclim--doc)
+(declare-function json-read "json")
+(defvar json-array-type)
 
 (defun company-eclim--call-process (&rest args)
   (let ((coding-system-for-read 'utf-8)
@@ -86,28 +89,27 @@ eclim can only complete correctly when the buffer has been saved."
 
 (defun company-eclim--project-dir ()
   (if (eq company-eclim--project-dir 'unknown)
-      (setq company-eclim--project-dir
-            (directory-file-name
-             (expand-file-name
-              (company-locate-dominating-file buffer-file-name ".project"))))
+      (let ((dir (locate-dominating-file buffer-file-name ".project")))
+        (when dir
+          (setq company-eclim--project-dir
+                (directory-file-name
+                 (expand-file-name dir)))))
     company-eclim--project-dir))
 
 (defun company-eclim--project-name ()
-  (if (eq company-eclim--project-name 'unknown)
-      (setq company-eclim--project-name
-            (let ((project (find-if (lambda (project)
-                                      (equal (cdr (assoc 'path project))
-                                             (company-eclim--project-dir)))
-                                    (company-eclim--project-list))))
-              (when project
-                (cdr (assoc 'name project)))))
-    company-eclim--project-name))
+  (or company-eclim--project-name
+      (let ((dir (company-eclim--project-dir)))
+        (when dir
+          (setq company-eclim--project-name
+                (cl-loop for project in (company-eclim--project-list)
+                         when (equal (cdr (assoc 'path project)) dir)
+                         return (cdr (assoc 'name project))))))))
 
 (defun company-eclim--candidates (prefix)
   (interactive "d")
   (let ((project-file (file-relative-name buffer-file-name
                                           (company-eclim--project-dir)))
-        (project-name (company-eclim--project-name)))
+        completions)
     (when company-eclim-auto-save
       (when (buffer-modified-p)
         (basic-save-buffer))
@@ -115,61 +117,70 @@ eclim can only complete correctly when the buffer has been saved."
       (company-eclim--call-process "java_src_update"
                                    "-p" (company-eclim--project-name)
                                    "-f" project-file))
-    (setq company-eclim--doc
-          (make-hash-table :test 'equal))
     (dolist (item (cdr (assoc 'completions
                               (company-eclim--call-process
                                "java_complete" "-p" (company-eclim--project-name)
                                "-f" project-file
-                               "-o" (number-to-string (1- (point)))
+                               "-o" (number-to-string
+                                     (company-eclim--search-point prefix))
                                "-e" "utf-8"
                                "-l" "standard"))))
       (let* ((meta (cdr (assoc 'info item)))
              (completion meta))
-        (when (string-match " [:-]" completion)
+        (when (string-match " ?[(:-]" completion)
           (setq completion (substring completion 0 (match-beginning 0))))
-        (puthash completion meta company-eclim--doc))))
-  (let ((completion-ignore-case nil))
-    (all-completions prefix company-eclim--doc)))
+        (put-text-property 0 1 'meta meta completion)
+        (push completion completions)))
+    (let ((completion-ignore-case nil))
+      (all-completions prefix completions))))
+
+(defun company-eclim--search-point (prefix)
+  (if (or (cl-plusp (length prefix)) (eq (char-before) ?.))
+      (1- (point))
+    (point)))
 
 (defun company-eclim--meta (candidate)
-  (gethash candidate company-eclim--doc))
-
-(defun company-eclim--templatify (call)
-  (let* ((end (point))
-         (beg (- (point) (length call)))
-         (templ (company-template-declare-template beg end)))
-    (save-excursion
-      (goto-char beg)
-      (while (re-search-forward "\\([(,] ?\\)\\(?:[^ ]+ \\)\\([^ ,)]*\\)" end t)
-        (let ((name (match-string 2)))
-          (replace-match "\\1" t)
-          (decf end (- (length (match-string 0))
-                       (length (match-string 1))))
-          (company-template-add-field templ (point) (format "<%s>" name)))))
-    (company-template-move-to-first templ)))
+  (get-text-property 0 'meta candidate))
+
+(defun company-eclim--annotation (candidate)
+  (let ((meta (company-eclim--meta candidate)))
+    (when (string-match "\\(([^-]*\\) -" meta)
+      (substring meta (match-beginning 1) (match-end 1)))))
+
+(defun company-eclim--prefix ()
+  (let ((prefix (company-grab-symbol)))
+    (when prefix
+      ;; Completion candidates for annotations don't include '@'.
+      (when (eq ?@ (string-to-char prefix))
+        (setq prefix (substring prefix 1)))
+      prefix)))
 
 (defun company-eclim (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for eclim.
-eclim provides access to Eclipse Java IDE features for other editors.
+  "`company-mode' completion backend for Eclim.
+Eclim provides access to Eclipse Java IDE features for other editors.
+
+Eclim version 1.7.13 or newer (?) is required.
 
 Completions only work correctly when the buffer has been saved.
 `company-eclim-auto-save' determines whether to do this automatically."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-eclim))
     (prefix (and (derived-mode-p 'java-mode 'jde-mode)
                  buffer-file-name
                  company-eclim-executable
                  (company-eclim--project-name)
                  (not (company-in-string-or-comment))
-                 (or (company-grab-symbol) 'stop)))
+                 (or (company-eclim--prefix) 'stop)))
     (candidates (company-eclim--candidates arg))
     (meta (company-eclim--meta arg))
     ;; because "" doesn't return everything
     (no-cache (equal arg ""))
-    (post-completion (when (string-match "([^)]" arg)
-                       (company-eclim--templatify arg)))))
+    (annotation (company-eclim--annotation arg))
+    (post-completion (let ((anno (company-eclim--annotation arg)))
+                       (when anno
+                         (insert anno)
+                         (company-template-c-like-templatify anno))))))
 
 (provide 'company-eclim)
 ;;; company-eclim.el ends here