Browse files

Merge pull request #47 from vhallac/eclimd-module

Added a new module to start/stop eclimd from emacs
  • Loading branch information...
2 parents 3eeba58 + f7c800f commit dbfe951d10173c85de9d114ce30414ec941d3558 @fred-o fred-o committed Jun 15, 2012
Showing with 196 additions and 0 deletions.
  1. +1 −0 History.txt
  2. +50 −0
  3. +145 −0 eclimd.el
@@ -15,6 +15,7 @@
* functions for find declarations and refrences of java methods and members
* Error highlighting in code
* Support for auto-complete-mode
+ * eclimd module to start/stop eclimd from emacs
=== Bugfixes
* fixed a problem on startup when the eclimd server was not started
@@ -8,6 +8,9 @@ Emacs-eclim uses the eclim server to integrate eclipse with
emacs. This project wants to bring some of the invaluable features
from eclipse to emacs.
+It is also possible to start and stop the eclim daemon from emacs using the
+`eclimd` package.
## Installation
1. [download and install](
eclim. Please note that emacs-eclim does *not* yet work with eclim
@@ -22,6 +25,9 @@ from eclipse to emacs.
(setq eclim-auto-save t)
+1. If you want to control eclimd from emacs, also add
+ (require 'eclimd)
## Configuration
@@ -73,6 +79,30 @@ following to your .emacs:
(global-company-mode t)
+### Configuring eclimd module
+When `emacs-eclim` is configured correctly, you don't need to modify the
+configuration for the `eclimd` package. Still, there are some configurable
+variables you can tweak:
+1. `eclimd-executable`: This variable is used for locating the `eclimd`
+ executable file. You can set it to `nil` ("Same directory as eclim-executable
+ variable" choice in customization screen) to indicate that the executable is in
+ the same directory as the `eclim` program. Alternatively, you can give it a
+ string value ("Custom value" choice in customization screen) to specify the
+ location of the executable.
+1. `eclimd-default-workspace`: When `start-eclimd` is executed, it will ask for
+ the workspace directory to use. The default value for this question is
+ controlled by this variable.
+1. `eclimd-wait-for-process`: Normally, when `start-eclimd` starts the eclimd
+ process, it pauses emacs until `eclimd` is ready to accept commands. If you
+ change the value of this variable to `nil`, `start-eclimd` will return as
+ soon as `eclimd` is started. Eclimd startup takes several seconds, so if you
+ change the default value of this variable, `emacs-eclim` commands will fail
+ until `eclimd` is ready.
## Optional dependencies
* A recent version (0.6.0 or later) of [yasnippet]
* A recent version (tested with 0.5) of [company-mode]
@@ -90,6 +120,26 @@ your Eclipse installation directory.
* [Maven](
* [Problems and Errors](
+### Controlling eclimd
+When you import the `eclimd` package, you will have access to two commands:
+`start-eclimd`, and `stop-eclimd`.
+`start-eclimd` will ask for a workspace directory, and it will attempt to start
+`eclimd` program with the entered workspace directory. The configurable variable
+`eclimd-default-workspace` controls the default value of this directory. After
+`start-eclimd` runs the daemon, it will monitor its log output, and wait for the
+message that indicates that it is ready to accept commands. This is done to
+prevent failures with `emacs-eclim` commands while `eclimd` is starting up.
+While `start-eclimd` is waiting for the daemon to be ready, emacs will not
+accept any user input. To prevent this pause, you can modify the configurable
+variable `eclimd-wait-for-process`.
+Normally, simply killing the buffer `*eclimd*` will allow you to stop the eclimd
+daemon. However, there is a command to perform a graceful shutdown:
+`stop-eclimd`. You should use this command when you wish to stop the `eclimd`
## Contributing
The project is under active development and we are always looking for
145 eclimd.el
@@ -0,0 +1,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
+;; 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)

0 comments on commit dbfe951

Please sign in to comment.