Skip to content
This repository
branch: master
Vedat Hallac vhallac
file 145 lines (126 sloc) 5.54 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
;;; eclimd.el --- Start and stop eclimd from within emacs

;; Copyright (C) 2012 Vedat Hallac

;; Authors: Vedat Hallac
;; Version: 1.0
;; Created: 2012/05/11
;; Keywords: java, emacs-eclim

;; This file is NOT part of Emacs.
;;
;; 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,
;; 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, write to the Free Software
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
;; MA 02110-1301, USA.

(require 'eclim)

(defgroup eclimd nil
  "eclimd customizations"
  :prefix "eclimd-"
  :group 'eclim)

(defcustom eclimd-executable
  nil
  "The eclimd executable to use.
Set to nil to auto-discover from `eclim-executable' value (the default value).
Set to \"eclimd\" if eclim and eclimd are in `exec-path'. Otherwise, set to
the full path to eclimd executable."
  :type '(choice (const :tag "Same directory as eclim-executable variable" nil)
                 (string :tag "Custom value" "eclimd"))
  :group 'eclimd)

(defcustom eclimd-default-workspace
  "~/workspace"
  "The workspace to use with eclimd"
  :type 'directory
  :group 'eclimd)

(defcustom eclimd-wait-for-process
  t
  "Set to t if you want `start-eclimd' to wait until the eclimd process is ready.
When this variable is nil, `start-eclimd' returns immediately after
eclimd process is started. Since the eclimd process startup takes a few seconds,
running eclim commands immediately after the function returns may cause failures.
You can freeze emacs until eclimd is ready to accept commands with this variable."
  :tag "Wait until eclimd is ready"
  :type 'boolean
  :group 'eclimd)

(defvar eclimd-process-buffer nil
  "Buffer used for communication with eclimd process")

(defvar eclimd-process nil
  "The active eclimd process")

(defconst eclimd-process-buffer-name "eclimd")

(defun eclimd--executable-path ()
  (if eclimd-executable
      (executable-find eclimd-executable)
    (let ((eclim-prog (executable-find eclim-executable)))
      (expand-file-name "eclimd" (file-name-directory eclim-prog)))))

(defun eclimd--running-p ()
  (not (null (get-buffer-process eclimd-process-buffer))))

(defun eclimd--match-process-output (regexp proc)
  "Wait for the given process to output a string that matches the specified regexp.
Return the string used for `match-string' if a match is found, and nil if the process is killed.

The caller must use `save-match-data' to preserve the match data if necessary."
  (let ((old-filter (process-filter proc))
(old-sentinel (process-sentinel proc))
(output "")
(terminated-p))
    (set-process-filter proc (lambda (proc string)
(setf output (concat output string))
;; Chain to the old filter
(if old-filter
(funcall old-filter proc string))))
    (set-process-sentinel proc (lambda (proc state)
(unless (eq 'run
(process-status proc))
(setf terminated-p t))))
    (while (and (not terminated-p)
(not (string-match regexp output)))
      (accept-process-output proc))
    (set-process-sentinel proc old-sentinel)
    (set-process-filter proc old-filter)
    (and (not terminated-p) output)))

(defun wait-eclimd-start ()
  "Wait for the eclimd server to become active.
This function also waits for the eclimd server to report that it is started.
It returns the port it is listening on"
  (let ((eclimd-start-regexp "Eclim Server Started on\\(?: port\\|:\\) \\(?:\\(?:[0-9]+\\.\\)\\{3\\}[0-9]+:\\)?\\([0-9]+\\)"))
    (save-match-data
      (let ((output (eclimd--match-process-output eclimd-start-regexp eclimd-process)))
(when output
(setq eclimd-port (match-string 1 output))
(message (concat "eclimd serving at port " eclimd-port)))))
    eclimd-port))

(defun start-eclimd (workspace-dir)
  (interactive (list (read-directory-name "Workspace directory: "
                                          eclimd-default-workspace nil t)))
  (let ((eclimd-prog (eclimd--executable-path)))
    (if (not eclimd-prog)
        (message "Cannot start eclimd: check eclimd-executable variable.")
      (if (eclimd--running-p)
          (message "Cannot start eclimd: eclimd is already running.")
        (message (concat "Starting eclimd for workspace: " workspace-dir "..."))
        (setq eclimd-process-buffer
              (make-comint eclimd-process-buffer-name
                           eclimd-prog
                           nil
                           (concat "-Dosgi.instance.area.default="
                                   (replace-regexp-in-string "~" "@user.home" workspace-dir))))
        (setq eclimd-process (get-buffer-process eclimd-process-buffer))
        (when eclimd-wait-for-process
          (wait-eclimd-start))))))

(defun stop-eclimd ()
  (interactive)
  (when eclimd-process
    (eclim/execute-command "shutdown")
    (eclimd--match-process-output "Process eclimd finished" eclimd-process)
    (delete-process eclimd-process)
    (setq eclimd-process nil))
  (when eclimd-process-buffer
    (kill-buffer eclimd-process-buffer)
    (setq eclimd-process-buffer nil)))

(provide 'eclimd)
Something went wrong with that request. Please try again.