yveszoundi / eglot-java Goto Github PK
View Code? Open in Web Editor NEWJava extension for the eglot LSP client
License: GNU General Public License v3.0
Java extension for the eglot LSP client
License: GNU General Public License v3.0
I really enjoy this package, but it wholly expects us to let it manage the download and build of the JDT Language Server.
This is fine for most cases. However, if you're a weirdo like me, who strives to make their configurations work as reliably as possible across systems, we like to use things like Nix/OS to provide runtime dependencies. This is mainly because in the nixpkgs stable checkout we can usually expect all of the runtime dependencies to work together really well. When we update our things, if they break due to some change in requirements, we can roll back until such a time that we can investigate what changed.
It would be nice if we could configure eglot-java to not have hard-coded paths to the jdt language server launcher, or the launcher config directory. Or better yet, be able to take an arbitrary launch command for the guess contact function to accept and use to bypass the built-in convenience features :)
Thoughts?
Currently it's only possible to run tests for an entire class.
The eglot-java-run-test
function behavior will be changed:
There's no built-in LSP server handler that will return automatically all the available test methods in a given file.
If the mouse cursor is near a helper method, this package will blindly assume that "you know what you're doing" and you'll get an error message from the Junit console logs.
I am editing a simple Java for Android project, and (eglot-java-mode)
does not even start.
Error buffer:
[jsonrpc] D[09:52:40.631] Running language server: /usr/lib64/zulu-openjdk11/bin/java -Declipse.application=org.eclipse.jdt.ls.core.id1 -Dosgi.bundles.defaultStartLevel=4 -Declipse.product=org.eclipse.jdt.ls.core.product -jar /home/lockywolf/.emacs.d/share/eclipse.jdt.ls/plugins/org.eclipse.equinox.launcher_1.6.700.v20231214-2017.jar -configuration /home/lockywolf/.emacs.d/share/eclipse.jdt.ls/config_linux -data /home/lockywolf/.emacs.d/eglot-java-eclipse-jdt-cache/fb975d1c5daaeb77385e3b232729edd2
[jsonrpc] e[09:52:40.633] --> initialize[1] {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":4795,"clientInfo":{"name":"Eglot","version":"1.15"},"rootPath":"/home/lockywolf/OfficialRepos/Telegram/TMessagesProj/","rootUri":"file:///home/lockywolf/OfficialRepos/Telegram/TMessagesProj","initializationOptions":{"extendedClientCapabilities":{"classFileContentsSupport":true},"workspaceFolders":["file:///home/lockywolf/OfficialRepos/Telegram/TMessagesProj"],"settings":{"java":{"home":"/usr/lib64/zulu-openjdk8"},"import":{"gradle":{"enabled":true},"wrapper":{"enabled":true}}}},"capabilities":{"workspace":{"applyEdit":true,"executeCommand":{"dynamicRegistration":false},"workspaceEdit":{"documentChanges":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":false},"configuration":true,"workspaceFolders":true},"textDocument":{"synchronization":{"dynamicRegistration":false,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":false,"completionItem":{"snippetSupport":true,"deprecatedSupport":true,"resolveSupport":{"properties":["documentation","details","additionalTextEdits"]},"tagSupport":{"valueSet":[1]}},"contextSupport":true},"hover":{"dynamicRegistration":false,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":false,"signatureInformation":{"parameterInformation":{"labelOffsetSupport":true},"documentationFormat":["markdown","plaintext"],"activeParameterSupport":true}},"references":{"dynamicRegistration":false},"definition":{"dynamicRegistration":false,"linkSupport":true},"declaration":{"dynamicRegistration":false,"linkSupport":true},"implementation":{"dynamicRegistration":false,"linkSupport":true},"typeDefinition":{"dynamicRegistration":false,"linkSupport":true},"documentSymbol":{"dynamicRegistration":false,"hierarchicalDocumentSymbolSupport":true,"symbolKind":{"valueSet":[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]}},"documentHighlight":{"dynamicRegistration":false},"codeAction":{"dynamicRegistration":false,"resolveSupport":{"properties":["edit","command"]},"dataSupport":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"isPreferredSupport":true},"formatting":{"dynamicRegistration":false},"rangeFormatting":{"dynamicRegistration":false},"rename":{"dynamicRegistration":false},"inlayHint":{"dynamicRegistration":false},"publishDiagnostics":{"relatedInformation":false,"codeDescriptionSupport":false,"tagSupport":{"valueSet":[1,2]}}},"window":{"showDocument":{"support":true},"workDoneProgress":true},"general":{"positionEncodings":["utf-32","utf-8","utf-16"]},"experimental":{}},"workspaceFolders":[{"uri":"file:///home/lockywolf/OfficialRepos/Telegram/TMessagesProj","name":"~/OfficialRepos/Telegram/TMessagesProj/"}]}}
[stderr] Picked up _JAVA_OPTIONS: -Dsun.java2d.uiScale=1.35 -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Dswing.crossplatformlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel
[stderr] Jan 19, 2024 9:52:41 AM org.apache.aries.spifly.BaseActivator log
[stderr] INFO: Registered provider ch.qos.logback.classic.servlet.LogbackServletContainerInitializer of service jakarta.servlet.ServletContainerInitializer in bundle ch.qos.logback.classic
[stderr] Jan 19, 2024 9:52:41 AM org.apache.aries.spifly.BaseActivator log
[stderr] INFO: Registered provider ch.qos.logback.classic.spi.LogbackServiceProvider of service org.slf4j.spi.SLF4JServiceProvider in bundle ch.qos.logback.classic
[jsonrpc] D[09:52:41.541] Connection state change: `exited abnormally with code 13
'
----------b---y---e---b---y---e----------
[stderr]
[stderr]
[stderr] nil
[stderr] nil
[stderr] Process EGLOT (TMessagesProj/(java-mode java-ts-mode)) stderr finished
I have been looking at an issue over in the JDT LSP repository: eclipse-jdtls/eclipse.jdt.ls#2322
A summary of how I reproduce this issue (with the latest snapshot of jdtls, not using eglot-java at all)
eglot-server-programs
: (java-mode . ("jdtls" :initializationOptions (:extendedClientCapabilities (:classFileContentsSupport t))))
groot/src/main/java/org/jlab/groot/math/F1D.java
xref-find-definitions
on the Expression
symbol on line 23The relevant eglot logs
(:jsonrpc "2.0" :id 8 :method "textDocument/definition" :params
(:textDocument
(:uri "file:///home/user/dev/groot/src/main/java/org/jlab/groot/math/F1D.java")
:position
(:line 22 :character 4)))
[server-reply] (id:8) Sun Nov 13 13:37:57 2022:
(:jsonrpc "2.0" :id 8 :result
[(:uri "jdt://contents/exp4j-0.4.4.jar/net.objecthunter.exp4j/Expression.class?=groot/%5C/home%5C/user%5C/.m2%5C/repository%5C/net%5C/objecthunter%5C/exp4j%5C/0.4.4%5C/exp4j-0.4.4.jar=/maven.pomderived=/true=/=/javadoc_location=/jar:file:%5C/home%5C/user%5C/.m2%5C/repository%5C/net%5C/objecthunter%5C/exp4j%5C/0.4.4%5C/exp4j-0.4.4-javadoc.jar%5C!%5C/=/=/maven.groupId=/net.objecthunter=/=/maven.artifactId=/exp4j=/=/maven.version=/0.4.4=/=/maven.scope=/compile=/=/maven.pomderived=/true=/%3Cnet.objecthunter.exp4j(Expression.class" :range
(:start
(:line 24 :character 13)
:end
(:line 24 :character 23)))])
I think this package would be a good place to handle those JDT URIs. There is a reply in the issue over in JDTLS repository that explains the process for handling them. Essentially the client must make an extra request to the java/classFileContents
method of the language server, which will serve back the contents of the decompiled class. From there the client is free to dump the contents into a buffer.
I would be happy to take a swing at implementing this here at some point, but wanted to drop an issue here in case someone else wants to try and beat me to it.
Since 2017-2018 (before the code was even on GitHub), eglot-java
always had very minimal configuration options for the Eclipse JDT language server. It might be time to add few settings found in forks.
It's not possible to manual define the following
java
executable, if the java
executable is not already in the user PATH
environment variableNow that with eglot-java it's possible to easily run main classes and test classes/methods, I would like to understand how it could support specific configurations for such runs.
The following come to mind:
One specific case is for projects that use Lombok. With the following in .dir-locals.el
we can convince jdtls
to process Lombok's annotations:
((nil . ((eval . (setq-local eglot-java-eclipse-jdt-args
(push (concat "-javaagent:" "/PATH/TO/lombok.jar")
eglot-java-eclipse-jdt-args))))))
I wonder whether .dir-locals.el
is a good mechanism to set Java run configurations in general. For main class args that doesn't seem very convenient, but for environment vars and JVM args it may be.
What are you thoughts?
Obsolete eglot
functions were removed as part of #37, as well as some "hacks" (AOP advices) handling older eglot versions. This removes compilation warnings (among other things), but introduce challenging side effects.
When people get error messages such as void function eglot-path-to-uri
, there are no clear action items:
eglot
itself works
See this reddit comment thread as reference: https://www.reddit.com/r/emacs/comments/1ce0ho9/comment/l1h36jn/
Screenshot of the problem for someone using the built-in eglot version on Arch Linux.
Users cannot start eglot-java
.
The functions and hacks removed create problems for users running older eglot
and emacs versions.
Undo changes introduced in #37, without trying to conditionally add aliases and other logic (defalias
and more code branches).
There's currently no way to customize eglot
initialization options.
That would allow for example registering extended client capabilities such as classFileContentsSupport
in the context of Java support. It's probably best to focus only on extendedClientCapabilities
for now.
The initial rationale was to used default project.el
functions (See #35). This essentially seems to translate into an infinite loop, maybe only on emacs-master
.
(cl-defmethod project-root ((project (head java)))
"Get the root of a JAVA PROJECT."
(project-root project))
Emacs git master: GNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.33, cairo version 1.16.0) of 2024-02-26
Example on a Git versioned Java project (maven-wrapper), open any Java file.
Debugger entered--Lisp error: (error "Lisp nesting exceeds ‘max-lisp-eval-depth’")
project-root((java . "~/Projects/maven-wrapper/"))
#f(compiled-function (project) "Get the root of a JAVA PROJECT." #<bytecode 0x1383aa4aefdec6fc>)((java . "~/Projects/maven-wrapper/"))
apply(#f(compiled-function (project) "Get the root of a JAVA PROJECT." #<bytecode 0x1383aa4aefdec6fc>) (java . "~/Projects/maven-wrapper/") nil)
#f(compiled-function (arg &rest args) #<bytecode 0x18d0a9b38b36bb46>)((java . "~/Projects/maven-wrapper/"))
apply(#f(compiled-function (arg &rest args) #<bytecode 0x18d0a9b38b36bb46>) (java . "~/Projects/maven-wrapper/"))
project-root((java . "~/Projects/maven-wrapper/"))
#f(compiled-function (project) "Get the root of a JAVA PROJECT." #<bytecode 0x1383aa4aefdec6fc>)((java . "~/Projects/maven-wrapper/"))
apply(#f(compiled-function (project) "Get the root of a JAVA PROJECT." #<bytecode 0x1383aa4aefdec6fc>) (java . "~/Projects/maven-wrapper/") nil)
#f(compiled-function (arg &rest args) #<bytecode 0x18d0a9b38b36bb46>)((java . "~/Projects/maven-wrapper/"))
apply(#f(compiled-function (arg &rest args) #<bytecode 0x18d0a9b38b36bb46>) (java . "~/Projects/maven-wrapper/"))
project-root((java . "~/Projects/maven-wrapper/"))
#f(compiled-function (project) "Get the root of a JAVA PROJECT." #<bytecode 0x1383aa4aefdec6fc>)((java . "~/Projects/maven-wrapper/"))
Hi! Awesome package and much appreciated :)
Small tweaks here would make it perfect for my use cases:
These are small things... I am always wondered by the Emacs evolution in recent years!
I am currently in a Termux session so can't really try to open a PR easilly here but I might try it in the future. Leaving this here for reference if anyone can do it before me (which might take a while since I am no pro in Elisp).
Thanks once again for your work! Happy incoming new year!
Gradle added Kotlin support in late 2016, starting with version 3.0.
eglot-java
never included any Kotlin
support for Gradle projects for 2 main reasons:
Kotlin
professionally, but I did try it few times (mostly in its early days)Kotlin
As of mid-2023, it seems that Kotlin
is now the default DSL for Gradle project files.
There's no support for Gradle
Kotlin
files : no build.gradle.kts
or settings.gradle.kts
existence checks.
Some people might prefer Kotlin
to the Groovy
syntax, maybe even more likely when working on Android projects.
project.el
(see eglot-java--project-try
)eglot-java--project-gradle-p
)setttings.gradle.kts
if it exists (See eglot-java--project-name-gradle
)build.gradle.kts
file (See eglot-java-project-build-refresh
)When you invoke the eglot-java-run-test
function, it will attempt to download the maven junit-platform-console-standalone
jar artifact (if not already cached locally). You can describe the variable eglot-java-junit-platform-console-standalone-jar
for more details (C-h v
).
It is not current possible to systemically upgrade the install junit standalone console jar. This is similar in nature to issue #16 .
Check for the latest version and then upgrade any existing download.
It is possible that a version might denote a milestone (e.g., 1.0.0-M1
or 1.0.0-rc1
). It is not guaranteed that those versions will be recorded as "releases" in the maven repository metadata.xml
.
Core emacs functions will report 1.0.0-M1
as invalid, in comparison to 1.0.0
. => (version< "1.0.0-M1" "1.0.0")
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>org.junit</groupId>
<artifactId>junit-gradle</artifactId>
<versioning>
<latest>5.0.0-ALPHA</latest>
<release>5.0.0-ALPHA</release>
<versions>
<version>5.0.0-ALPHA</version>
</versions>
<lastUpdated>20160201140008</lastUpdated>
</versioning>
</metadata>
Let's assume that the latest available version is 1.0.0-M2
and the installed version is 1.0.0-M1
:
-
)(version<= "1.0.0" "1.0.0")
M2
with the installed version M1
string> "M2" "M1"
)When eglot tries to launch an LSP server, a timeout error can happen if the LSP server is not ready very quickly.
From a user perspective, the timeout error could be seen as a bug??
The documentation task seem like a better option. The user may want all the connectivity to be async with eglot-sync-connect
set to 0
.
While automatically installing the eclipse lsp works fine, there no longer is a eglot--eclipse-jdt or similar in eglot master, so starting it fails.
In order to support JDT URIs (#6), a custom AOP advice was introduced. This should not be required in future MELPA versions of eglot.
Remove the AOP advice around eglot URI functions (see TODO markers in eglot-java.el
).
When you invoke the eglot-java-run-test
function, it will attempt to download the maven junit-platform-console-standalone
jar artifact (if not already cached locally).
sonatype.org
repositories.eglot-java-junit-platform-console-standalone-jar-url
variable (C-h v
).When behind a VPN (e.g., NordVPN), sonatype.org
might request some user credentials for the junit jar download (as no browser captcha will be displayed to check whether you're a bot or a real human).
Please note that I'm not promoting a specific VPN such as NordVPN.
junit-platform-console-standalone
root maven url, such as https://repo1.maven.org/maven2/. If that URL creates problems, users can change it themselves with another URL that doesn't attempt to block them behind their particular network setup.eglot-java-junit-platform-console-standalone-jar-url
as obsolete (See the make-obsolete-variable
function)metadata > versioning > latest
).
metadata.xml
contents into a temporary buffer (with the url-insert-file-contents
function)XML_STRING
) by parsing the current temporary XML buffer(caddar (xml-get-children (car (xml-get-children (car (XML_STRING)) 'versioning)) 'release))
I have a failure with ensure-eglot
due to these lines. This can't be serialized to JSON because it's an invalid property list (a tag with 2 values).
Lines 146 to 149 in ea51c47
Moving a left parenthesis seems to fix it, though I'm just guessing that :import
is another setting of :java
.
`(:settings (:java (:home ,home)
:import (:gradle (:enabled t)))
)
https://discourse.doomemacs.org/t/error-when-loading-eglot-java/3923
For multibyte issues, not really sure about what can be done, buffer local settings would be set for a given file mode apparently.
For functions not automatically discovered, libraries can be eagerly loaded (xml
and tar-mode
libraries)
Eglot and eglot-java didn't start when I open any file with java source code from my project.
Steps to reproduce:
File mode specification error: (wrong-type-argument consp nil)
Emacs 28.2
Eglot 1.10
Eglot-java 20221218.1809 from MELPA
Му configuration:
(use-package eglot)
(use-package eglot-java
:requires eglot
:config
(progn
(add-hook 'java-mode-hook 'eglot-java-mode)))
I found (via M-x toggle-debug-on-error
) what problem also reproduces, when I call M-x eglot-java-mode
after open the java file.
Debugger entered--Lisp error: (wrong-type-argument consp nil)
eglot-java--init()
eglot-java-mode(toggle)
funcall-interactively(eglot-java-mode toggle)
call-interactively(eglot-java-mode record nil)
command-execute(eglot-java-mode record)
execute-extended-command(nil "eglot-java-mode" "eglot-java-m")
funcall-interactively(execute-extended-command nil "eglot-java-mode" "eglot-java-m")
call-interactively(execute-extended-command nil nil)
command-execute(execute-extended-command)
I use eglot-java with a Gradle multi-project. For example the sub-projects are named "lib" and "app". I visit a Java file of project "lib" and enable eglot-java-mode. This starts a jdtls process. I visit a Java file of project "app" and enable eglot-java-mode. This starts another jdtls process. So there are two jdtls processes running in parallel. When I do the same just with eglot-mode itself, only one jdtls process is running.
For projects with a lot of sub-projects a lot of memory might be allocated. Is there a way to achieve that only one process is started for the whole multi-project?
I guess the function eglot-java--project-try
is involved because it finds the Gradle build file of the sub-project. This function is added to the project-find-functions
by eglot-java--init
.
Emacs version 28.2
OS version: MacOS 13.3.1
Architecture: ARM (Apple M1)
(setq eglot-java-eclipse-jdt-args
'(
"-noverify"
"-Xmx1G"
"-XX:+UseG1GC"
"-XX:+UseStringDeduplication"
"-javaagent:/.m2/repository/org/projectlombok/lombok/1.18.20/lombok-1.18.20.jar"/.m2/repository/org/projectlombok/lombok/1.18.20/lombok-1.18.20.jar"
"-Xbootclasspath/a:
))
jsonrpc-request: jsonrpc-error: "request id=73 failed:", (jsonrpc-error-code . -32603), (jsonrpc-error-message . "Internal error."), (jsonrpc-error-data . "java.util.concurrent.CompletionException: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @377c7eaf
at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:649)
at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @377c7eaf
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.overrideLoadResult(ModuleClassLoader.java:86)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
at org.eclipse.jdt.internal.compiler.parser.Parser.consumeExitVariableWithInitialization(Parser.java:4205)
at org.eclipse.jdt.internal.compiler.SourceElementParser.consumeExitVariableWithInitialization(SourceElementParser.java:406)
at org.eclipse.jdt.internal.compiler.parser.Parser.consumeRule(Parser.java:7156)
at org.eclipse.jdt.internal.compiler.parser.Parser.parse(Parser.java:13179)
at org.eclipse.jdt.internal.compiler.parser.Parser.parse(Parser.java:13434)
at org.eclipse.jdt.internal.compiler.parser.Parser.parse(Parser.java:13391)
at org.eclipse.jdt.internal.compiler.SourceElementParser.parseCompilationUnit(SourceElementParser.java:1122)
at org.eclipse.jdt.internal.core.CompilationUnit.buildStructure(CompilationUnit.java:196)
at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:266)
at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:597)
at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:328)
at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:314)
at org.eclipse.jdt.internal.core.Openable.getBuffer(Openable.java:296)
at org.eclipse.jdt.ls.core.internal.JDTUtils.findElementsAtSelection(JDTUtils.java:992)
at org.eclipse.jdt.ls.core.internal.JDTUtils.findElementAtSelection(JDTUtils.java:978)
at org.eclipse.jdt.ls.core.internal.handlers.NavigateToDefinitionHandler.computeDefinitionNavigation(NavigateToDefinitionHandler.java:83)
at org.eclipse.jdt.ls.core.internal.handlers.NavigateToDefinitionHandler.definition(NavigateToDefinitionHandler.java:73)
at org.eclipse.jdt.ls.core.internal.handlers.JDTLanguageServer.lambda$7(JDTLanguageServer.java:658)
at org.eclipse.jdt.ls.core.internal.BaseJDTLanguageServer.lambda$0(BaseJDTLanguageServer.java:87)
at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:646)
... 6 more
")
The above setting for lsp-java does work, so I wonder why passing the same jvm argument will cause the discrepancy.
One of the great things about getting java development going on lsp-mode is the ability for lsp-mode to install jdtls for you. would be great to have that added here.
I cannot imagine why it would work in some cases, but not in others, but throughout the majority of the project things work fine, until I see the @Getter
annotation.
Everything works fine when I compile the thing.
Also, my lombok verrsion (1.18.30) seems to work fine with lsp-mode
and nvim-jdtls.
When things go wrong, I get a lint error at the top of the buffer which reads:
Java [0]: Lombok annotation handler class lombok.eclipse.handlers.HandleGetter failed - See error log.
and sometimes, but not always, missing references down the buffer from there.
My vmargs are set as such:
(defun td-eglot-java-setup ()
(setq eglot-java-eclipse-jdt-args (list (concat "-javaagent:"
td-eglot-java-lombok-path)))
(td-bind-keys '(("C-c e n" . eglot-java-file-new)
("C-c e x" . eglot-java-run-main)
("C-c e t" . eglot-java-run-test)
("C-c e N" . eglot-java-project-new)
("C-c e T" . eglot-java-project-build-task)
("C-c e R" . eglot-java-project-build-refresh))
eglot-java-mode-map))
(add-hook 'eglot-java-mode-hook 'td-eglot-java-setup)
When I check the jdt args at run time, they look pretty good to me:
Its value is
("-javaagent:/home/trev/.emacs.d/eglot-java/lombok/lombok.jar" "-jar" "/home/trev/.emacs.d/share/eclipse.jdt.ls/plugins/org.eclipse.equinox.launcher_1.6.700.v20231214-2017.jar" "-configuration" "/home/trev/.emacs.d/share/eclipse.jdt.ls/config_linux" "-data" "/home/trev/.emacs.d/eglot-java-eclipse-jdt-cache/ba359c4c589a8cb98349d0107123787e")
Original value was nil
Any ideas as to what's going on here?
Default value of
eglot-java-eclipse-jdt-ls-download-url
is a snapshot download. If you are unlucky to install it a time when the latest snapshot is buggy, good luck understanding what's wrong when you are not familiar with eglot.
Switching from release snapshots to release milestones could mitigate this issue.
Sadly, it seems that there's no official Eclipse website API endpoint to retrieve available jdtls
releases. (i.e., in comparison to let's say fetching GitHub releases for a given project).
One option is to leverage the Homebrew jdtls formula REST endpoint to retrieve the latest "known" stable version.
The property paths of interest are .urls.stable.url
and .versions.stable
, per JSON response exceprt below.
{
"name": "jdtls",
...
"versions": {
"stable": "1.30.0",
"head": null,
"bottle": true
},
"urls": {
"stable": {
"url": "https://www.eclipse.org/downloads/download.php?file=/jdtls/milestones/1.30.0/jdt-language-server-1.30.0-202311301503.tar.gz",
"tag": null,
"revision": null,
"using": null,
"checksum": "579809f27df5f4e53566217f7273fa25cd45a22d3870c0aafd4f84cdd4c97acd"
}
},
...
}
We probably need to record the installed jdtls
version ( in some form of metadata file??).
jdtls
version recorded in the Homebrew formula might not be the latest available release milestone.There appears to be no "official" way to upgrade the installed JDT LS. You could delete the installation directory, but it's obviously a hack. Probably also need to shut down (how exactly?) the eglot server and (manually?) start again after deleting.
eglot-java-mode
, ensure that the eglot-server is not running, otherwise stop it: Maybe just disabling eglot-java-mode
is good enoughjdtls
version to a temporary folderjdtls
installation folder to a temporary folderjdtls
to its new destinationjdtls
installation folderjava-mode
, ensure that the eglot-server is running, by reassociating the buffer with eglot-java-mode
This depends on #15 .
This key should be reserved for users and never be automatically bound.
At present when doing eglot-rename on a type, the class file is not renamed at the same time and the server sends an error about the two not matching. Doing rename-visited-file confuses the server further because the file open and close events aren't sent. This is pretty annoying for me as i like to chop and change my names pretty often if I'm working on my own project. From what I can see, JDT.LS does send a rename event if the client sends capabilities.workspaceEdit.resourceOperations: ["rename"]
but Eglot by default does not.
I did have some code that tried to brute force figuring out whether we just renamed a class and to do the rename in Emacs, but it didn't feel safe for a potentially destructive action. The other option I'm thinking of is trying to send the resourceOperations
capability to the server and listening for rename events inside eglot-java. (Of course the nicer option would be to have this work inside Eglot itself, but I do not have the patience for trying to get code into Emacs git.) Any comments would be welcomed
Hi,
would you consider adding this package to ELPA? If so, may I suggest to get in touch with @phikal to check what you need to do?
Thank you!
By default, eglot-java
doesn't use the Eclipse JDT LS startup scripts (jdtls
binary).
jdtls
startup scripts existed (See eclipse-jdtls/eclipse.jdt.ls#1823)jdtls
startup scripts require a Python
installation
Python
is typically pre-installed on Linux, as many programs use thatPython
is not pre-installedPython
is also not bundled anymore as of MacOS Monterey 12.3By default, eglot-java
dynamically modifies the eglot-server-programs
variable for launching the Eclipse JDT LS server.
Some users might not realize that, even though it's documented (Package headers and GitHub project README), and that will result into both frustration and time wasted.
Scenario 1 - eglot changes how LSP servers can be mapped to programming modes
eglot
won't be able to start the LSP server, with obscure error emacs-lisp messagesScenario 2 - users have already configured eglot-server-programs to their liking for jdtls
There's an existing variable that controls how eglot-java
dynamically modifies the value of eglot-server-programs
.
eglot-java-eglot-server-programs-manual-updates is a variable defined in ‘eglot-java.el’.
Its value is nil
Do not try to automatically update eglot-server-programs
The change will change the default value of eglot-java-eglot-server-programs-manual-updates
to t
. The project documentation will also need to be updated to reflect that
eglot-java
when they do not want an involved configurationjdtls
startup scripts and mostly value eglot-java
for its ability to automatically install the Eclipse JDT LS server.Python
installed and they might not be aware that the jdtls
script needs it...I don't feel that eglot
java defaults are that good myself: see joaotavora/eglot#1008 (comment). Either way, it's probably better to have an explicit user opt-in (eglot-java
magic), instead of people continuously running into configuration issues...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.