X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/0970c3d32dc3aff696f41d9a4fe9050c2318d65b..69228c73e01ec9a3ae6cf5a1f8c4d83d8c6f4999:/company-eclim.el diff --git a/company-eclim.el b/company-eclim.el index cda300c12..b37f75602 100644 --- a/company-eclim.el +++ b/company-eclim.el @@ -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 @@ -21,50 +21,53 @@ ;;; 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,60 +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 3))) - (replace-match "\\1" t) - (decf end (length (match-string 2))) - (company-template-add-field templ (point) 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