tag: 1.2
commit 3532bd0f7c43f17b27f2b0a196c4f1a89f3cbd8d
Author: MichaĆ K <[email protected]>
Commit: mkcms <[email protected]>
Per #63: Add support for eclipse.jdt.ls server
* eglot.el (eglot-server-programs): Add java-mode entry.
(eglot-eclipse-jdt): New class.
(eglot-initialization-options): Override for eglot-eclipse-jdt.
(eglot--eclipse-jdt-contact): New function.
---
README.md | 2 ++
eglot.el | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index fc06d52..38698dd 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ for the language of your choice. Otherwise, it prompts you to
enter one:
* Rust's [rls][rls]
* Python's [pyls][pyls]
* Ruby's [solargraph][solargraph]
+* Java's [Eclipse JDT Language Server][eclipse-jdt]
* Bash's [bash-language-server][bash-language-server]
* PHP's [php-language-server][php-language-server]
* C/C++'s [ccls][ccls] ([cquery][cquery] and [clangd][clangd] also work)
@@ -301,4 +302,5 @@ Under the hood:
[haskell-ide-engine]: https://github.com/haskell/haskell-ide-engine
[kotlin-language-server]: https://github.com/fwcd/KotlinLanguageServer
[go-langserver]: https://github.com/sourcegraph/go-langserver
+[eclipse-jdt]: https://github.com/eclipse/eclipse.jdt.ls
diff --git a/eglot.el b/eglot.el
index 4376d3a..daae454 100644
--- a/eglot.el
+++ b/eglot.el
@@ -91,7 +91,9 @@
language-server/bin/php-language-server.php"))
(haskell-mode . ("hie-wrapper"))
(kotlin-mode . ("kotlin-language-server"))
- (go-mode . ("go-langserver" "-mode=stdio"
"-gocodecompletion")))
+ (go-mode . ("go-langserver" "-mode=stdio"
+ "-gocodecompletion"))
+ (java-mode . eglot--eclipse-jdt-contact))
"How the command `eglot' guesses the server to start.
An association list of (MAJOR-MODE . CONTACT) pairs. MAJOR-MODE
is a mode symbol, or a list of mode symbols. The associated
@@ -1893,6 +1895,96 @@ If SKIP-SIGNATURE, don't try to send
textDocument/signatureHelp."
:progressReportFrequencyMs -1)))
+;;; eclipse-jdt-specific
+;;;
+(defclass eglot-eclipse-jdt (eglot-lsp-server) ()
+ :documentation "Eclipse's Java Development Tools Language Server.")
+
+(cl-defmethod eglot-initialization-options ((server eglot-eclipse-jdt))
+ "Passes through required jdt initialization options"
+ `(:workspaceFolders
+ [,@(cl-delete-duplicates
+ (mapcar #'eglot--path-to-uri
+ (let* ((roots (project-roots (eglot--project server)))
+ (root (car roots)))
+ (append
+ roots
+ (mapcar
+ #'file-name-directory
+ (append
+ (file-expand-wildcards (concat root "*/pom.xml"))
+ (file-expand-wildcards (concat root "*/build.gradle"))
+ (file-expand-wildcards (concat root "*/.project")))))))
+ :test #'string=)]
+ ,@(if-let ((home (or (getenv "JAVA_HOME")
+ (ignore-errors
+ (expand-file-name
+ ".."
+ (file-name-directory
+ (file-chase-links (executable-find "javac"))))))))
+ `(:settings (:java (:home ,home)))
+ (ignore (eglot--warn "JAVA_HOME env var not set")))))
+
+(defun eglot--eclipse-jdt-contact (interactive)
+ "Return a contact for connecting to eclipse.jdt.ls server, as a cons cell."
+ (cl-labels
+ ((is-the-jar
+ (path)
+ (and (string-match-p
+ "org\\.eclipse\\.equinox\\.launcher_.*\\.jar$"
+ (file-name-nondirectory path))
+ (file-exists-p path))))
+ (let* ((classpath (or (getenv "CLASSPATH") ":"))
+ (cp-jar (cl-find-if #'is-the-jar (split-string classpath ":")))
+ (jar cp-jar)
+ (dir
+ (cond
+ (jar (file-name-as-directory
+ (expand-file-name ".." (file-name-directory jar))))
+ (interactive
+ (expand-file-name
+ (read-directory-name
+ (concat "Path to eclipse.jdt.ls directory (could not"
+ " find it in CLASSPATH): ")
+ nil nil t)))
+ (t (error "Could not find eclipse.jdt.ls jar in CLASSPATH"))))
+ (repodir
+ (concat dir
+ "org.eclipse.jdt.ls.product/target/repository/"))
+ (repodir (if (file-directory-p repodir) repodir dir))
+ (config
+ (concat
+ repodir
+ (cond
+ ((string= system-type "darwin") "config_mac")
+ ((string= system-type "windows-nt") "config_win")
+ (t "config_linux"))))
+ (workspace
+ (expand-file-name (md5 (car (project-roots (project-current))))
+ (concat user-emacs-directory
+ "eglot-eclipse-jdt-cache"))))
+ (unless jar
+ (setq jar
+ (cl-find-if #'is-the-jar
+ (directory-files (concat repodir "plugins") t))))
+ (unless (and jar (file-exists-p jar) (file-directory-p config))
+ (error "Could not find required eclipse.jdt.ls files (build
required?)"))
+ (when (and interactive (not cp-jar)
+ (y-or-n-p (concat "Add path to the server program "
+ "to CLASSPATH environment variable?")))
+ (setenv "CLASSPATH" (concat (getenv "CLASSPATH") ":" jar)))
+ (unless (file-directory-p workspace)
+ (make-directory workspace t))
+ (cons 'eglot-eclipse-jdt
+ (list (executable-find "java")
+ "-Declipse.application=org.eclipse.jdt.ls.core.id1"
+ "-Dosgi.bundles.defaultStartLevel=4"
+ "-Declipse.product=org.eclipse.jdt.ls.core.product"
+ "-jar" jar
+ "-configuration" config
+ "-data" workspace)))))
+
+
;; FIXME: A horrible hack of Flymake's insufficient API that must go
;; into Emacs master, or better, 26.2
(when (version< emacs-version "27.0")