-;;; company-eclim.el --- a company-mode completion back-end for eclim.
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.4.3.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-eclim.el --- A company-mode completion back-end for eclim.
+
+;; Copyright (C) 2009, 2011, 2013 Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
-;;
+
;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Eclim version 1.7.13 or newer (?) is required.
+;;
+;; This completion backend is pretty barebone.
+;;
+;; `emacs-eclim' provides an alternative backend, and it also allows you to
+;; actually control Eclim from Emacs.
+
+;;; Code:
(require 'company)
(eval-when-compile (require 'cl))
(defcustom company-eclim-executable
(or (executable-find "eclim") (company-eclim-executable-find))
- "*Location of eclim executable"
+ "Location of eclim executable."
:group 'company
:type 'file)
-(defcustom company-eclim-auto-save nil
- "*Determines whether to save the buffer when retrieving completions.
+(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)
(defvar company-eclim--doc nil)
(make-variable-buffer-local 'company-eclim--doc)
-(defun company-eclim--buffer-lines ()
- (goto-char (point-max))
- (let (lines)
- (while (= 0 (forward-line -1))
- (push (buffer-substring-no-properties (point-at-bol) (point-at-eol))
- lines))
- lines))
-
(defun company-eclim--call-process (&rest args)
(let ((coding-system-for-read 'utf-8)
res)
+ (require 'json)
(with-temp-buffer
(if (= 0 (setq res (apply 'call-process company-eclim-executable nil t nil
"-command" args)))
- (company-eclim--buffer-lines)
+ (let ((json-array-type 'list))
+ (goto-char (point-min))
+ (unless (eobp)
+ (json-read)))
(message "Company-eclim command failed with error %d:\n%s" res
(buffer-substring (point-min) (point-max)))
nil))))
(defun company-eclim--project-list ()
- (mapcar (lambda (line) (nreverse (split-string line " *- *" nil)))
- (company-eclim--call-process "project_list")))
+ (company-eclim--call-process "project_list"))
(defun company-eclim--project-dir ()
(if (eq company-eclim--project-dir 'unknown)
(defun company-eclim--project-name ()
(if (eq company-eclim--project-name 'unknown)
(setq company-eclim--project-name
- (car (cddr (assoc (company-eclim--project-dir)
- (company-eclim--project-list)))))
+ (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))
(defun company-eclim--candidates (prefix)
(company-eclim--project-dir)))
(project-name (company-eclim--project-name)))
(when company-eclim-auto-save
- (save-buffer)
+ (when (buffer-modified-p)
+ (basic-save-buffer))
;; FIXME: Sometimes this isn't finished when we complete.
(company-eclim--call-process "java_src_update"
- "-p" (company-eclim--project-name)
- "-f" project-file))
+ "-p" (company-eclim--project-name)
+ "-f" project-file))
(setq company-eclim--doc
- (mapcar (lambda (line)
- (cdr (split-string line "|" nil)))
- (company-eclim--call-process
- "java_complete" "-p" (company-eclim--project-name)
- "-f" project-file
- "-o" (number-to-string (1- (point)))
- "-e" "utf-8"
- "-l" "standard"))))
+ (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)))
+ "-e" "utf-8"
+ "-l" "standard"))))
+ (let* ((meta (cdr (assoc 'info item)))
+ (completion meta))
+ (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 (mapcar 'car company-eclim--doc))))
+ (all-completions prefix company-eclim--doc)))
+
+(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)))
(defun company-eclim (command &optional arg &rest ignored)
"A `company-mode' completion back-end for eclim.
`company-eclim-auto-save' determines whether to do this automatically."
(interactive (list 'interactive))
(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)))
- ('candidates (company-eclim--candidates arg))
- ('meta (cadr (assoc arg company-eclim--doc)))
+ (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)))
+ (candidates (company-eclim--candidates arg))
+ (meta (company-eclim--meta arg))
;; because "" doesn't return everything
- ('no-cache (equal arg ""))))
+ (no-cache (equal arg ""))
+ (common (when (string-match "(" arg)
+ (substring arg 0 (match-beginning 0))))
+ (post-completion (when (string-match "([^)]" arg)
+ (company-eclim--templatify arg)))))
(provide 'company-eclim)
;;; company-eclim.el ends here