Can't get Eglot + JDTLS to work #1185
-
This is how I install Eglot: (use-package eglot
:hook ((c-mode c++-mode java-mode shell-script-mode) . eglot-ensure)
:config
(setq eglot-autoshutdown t)) I'm using the system-installed JDTLS, so not a local one.
Other than that, nothing. No Flymake diagnostics, no completions. Here's the Eglot log, I have no idea how to decipher it: java.log And by the way, I did test the C and C++ modes using clangd and had no issues. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 9 replies
-
As far as I understand, the Java language server has to build your project, and maybe just |
Beta Was this translation helpful? Give feedback.
-
Example for jdtls user How Eglot launch JDTLS(require 'eglot)
(defun jdtls-command-contact (&optional interactive)
(let* ((jdtls-cache-dir (file-name-concat user-emacs-directory "cache" "lsp-cache"))
(project-dir (file-name-nondirectory (directory-file-name (project-root (project-current)))))
(data-dir (expand-file-name (file-name-concat jdtls-cache-dir (md5 project-dir))))
(jvm-args `(,(concat "-javaagent:" (expand-file-name "~/.m2/repository/org/projectlombok/lombok/1.18.20/lombok-1.18.20.jar"))
"-Xmx8G"
;; "-XX:+UseG1GC"
"-XX:+UseZGC"
"-XX:+UseStringDeduplication"
;; "-XX:FreqInlineSize=325"
;; "-XX:MaxInlineLevel=9"
"-XX:+UseCompressedOops"))
(jvm-args (mapcar (lambda (arg) (concat "--jvm-arg=" arg)) jvm-args))
;; tell jdtls the data directory and jvm args
(contact (append '("jdtls") jvm-args `("-data" ,data-dir))))
contact))
(push '((java-mode java-ts-mode) . jdtls-command-contact) eglot-server-programs) How Eglot initialize JDTLS (User-specific configuration)(defun jdtls-initialization-options ()
(let ((setting-json-file (file-name-concat user-emacs-directory "lsp-config" "jdtls.json")))
(with-temp-buffer
(insert-file-contents setting-json-file)
(json-parse-buffer :object-type 'plist :false-object :json-false))))
(cl-defmethod eglot-initialization-options (server &context (major-mode java-mode))
(jdtls-initialization-options))
(cl-defmethod eglot-initialization-options (server &context (major-mode java-ts-mode))
(jdtls-initialization-options)) jdtls.json example {
"settings": {
"java": {
"maxConcurrentBuilds": 1,
"autobuild": {
"enabled": false
},
"import": {
"maven": {
"enabled": true
},
"exclusions": [
"**/node_modules/**",
"**/.metadata/**",
"**/archetype-resources/**",
"**/META-INF/maven/**"
]
},
"configuration": {
"updateBuildConfiguration": "automatic",
"checkProjectSettingsExclusions": true,
"runtimes": [
{
"name": "JavaSE-1.8",
"path": "/usr/local/java-8"
},
{
"name": "JavaSE-11",
"path": "/usr/local/java-11"
},
{
"name": "JavaSE-17",
"path": "/usr/local/java-17"
},
{
"name": "JavaSE-19",
"path": "/usr/local/java-19",
"default": true
}
]
},
"project": {
"importHint": true,
"importOnFirstTimeStartup": "automatic",
"referencedLibraries": [
"lib/**"
],
"resourceFilters": [
"node_modules",
"\\.git",
".metadata",
"archetype-resources",
"META-INF/maven"
]
},
"server": {
"launchMode": "Hybrid"
},
"format": {
"settings": {
"url": "/home/zsxh/.emacs.d/cache/eclipse-java-google-style.xml",
"profile": "GoogleStyle"
}
},
"contentProvider": {
"preferred": "fernflower"
},
"completion": {
"guessMethodArguments": true,
"overwrite": true,
"enabled": true,
"favoriteStaticMembers": [
"org.junit.Assert.*",
"org.junit.Assume.*",
"org.junit.jupiter.api.Assertions.*",
"org.junit.jupiter.api.Assumptions.*",
"org.junit.jupiter.api.DynamicContainer.*",
"org.junit.jupiter.api.DynamicTest.*",
"org.mockito.Mockito.*",
"org.mockito.ArgumentMatchers.*",
"org.mockito.Answers.*"
]
}
}
},
"extendedClientCapabilities": {
"classFileContentsSupport": true,
"overrideMethodsPromptSupport": true
},
"bundles": [
"/home/zsxh/.emacs.d/cache/lsp-servers/java/bundles/dg.jdt.ls.decompiler.cfr-0.0.3.jar",
"/home/zsxh/.emacs.d/cache/lsp-servers/java/bundles/dg.jdt.ls.decompiler.common-0.0.3.jar",
"/home/zsxh/.emacs.d/cache/lsp-servers/java/bundles/dg.jdt.ls.decompiler.fernflower-0.0.3.jar",
"/home/zsxh/.emacs.d/cache/lsp-servers/java/bundles/dg.jdt.ls.decompiler.procyon-0.0.3.jar"
]
} You gonna download the bundles, formatter from vscode plugins yourself How Eglot handle jdt:// scheme uri(defvar eglot-path-uri-cache (make-hash-table :test #'equal)
"File path to uri cache.")
(cl-defgeneric +eglot/ext-uri-to-path (uri)
"Support extension uri."
nil)
(define-advice eglot--uri-to-path (:around (orig-fn uri) advice)
"Support non standard LSP uri scheme."
(when (keywordp uri) (setq uri (substring (symbol-name uri) 1)))
(or (+eglot/ext-uri-to-path uri)
(funcall orig-fn uri)))
(define-advice eglot--path-to-uri (:around (orig-fn path) advice)
"Support non standard LSP uri scheme."
(or (gethash path eglot-path-uri-cache)
(funcall orig-fn path)))
(defun +eglot/jdtls-uri-to-path (uri)
"Support Eclipse jdtls `jdt://' uri scheme."
(when-let* ((jdt-scheme-p (string-prefix-p "jdt://" uri))
(filename (when (string-match "^jdt://contents/\\(.*?\\)/\\(.*\\)\.class\\?" uri)
(format "%s.java" (replace-regexp-in-string "/" "." (match-string 2 uri) t t))))
(source-dir (file-name-concat (project-root (eglot--current-project)) ".eglot"))
(source-file (expand-file-name (file-name-concat source-dir filename))))
(unless (file-directory-p source-dir)
(make-directory source-dir t))
(unless (file-readable-p source-file)
(let ((content (jsonrpc-request (eglot--current-server-or-lose)
:java/classFileContents
(list :uri uri))))
(with-temp-file source-file (insert content))))
(puthash source-file uri eglot-path-uri-cache)
source-file))
(cl-defmethod +eglot/ext-uri-to-path (uri &context (major-mode java-mode))
(+eglot/jdtls-uri-to-path uri))
(cl-defmethod +eglot/ext-uri-to-path (uri &context (major-mode java-ts-mode))
(+eglot/jdtls-uri-to-path uri)) How Eglot handle (some) non standard LSP commands;; https://github.com/joaotavora/eglot/discussions/888#discussioncomment-2386710
(cl-defmethod eglot-execute-command
(_server (_cmd (eql java.apply.workspaceEdit)) arguments)
"Command `java.apply.workspaceEdit' handler."
(mapc #'eglot--apply-workspace-edit arguments))
(cl-defmethod eglot-execute-command
(_server (_cmd (eql java.action.overrideMethodsPrompt)) arguments)
"Command `java.action.overrideMethodsPrompt' handler."
(let* ((argument (aref arguments 0))
(list-methods-result (jsonrpc-request (eglot--current-server-or-lose)
:java/listOverridableMethods
argument))
(methods (plist-get list-methods-result :methods))
(menu-items (mapcar (lambda (method)
(let* ((name (plist-get method :name))
(parameters (plist-get method :parameters))
(class (plist-get method :declaringClass)))
(cons (format "%s(%s) class: %s" name (string-join parameters ", ") class) method)))
methods))
(selected-methods (cl-map 'vector
(lambda (choice) (alist-get choice menu-items nil nil 'equal))
(delete-dups
(completing-read-multiple "overridable methods: " menu-items))))
(add-methods-result (jsonrpc-request (eglot--current-server-or-lose)
:java/addOverridableMethods
(list :overridableMethods selected-methods :context argument))))
(eglot--apply-workspace-edit add-methods-result))) |
Beta Was this translation helpful? Give feedback.
As far as I understand, the Java language server has to build your project, and maybe just
~/test.java
isn't a very good way to make a buildable java project? I haven't programmed Java in a million years, but I'd say at least a~/test-project/test.java
maybe with a Git-initialized.git
directory is a better experiment? Create such a minimal project and try it with both Eglot and Neovim. If you're still stumped, follow the instructions of https://joaotavora.github.io/eglot/#Troubleshooting-Eglot and make a bug report.