-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
workspace path as lsp server command line option #63
Comments
CONTACT in the (MAJOR-MODE . CONTACT) association in eglot-server-programs can now be a function of no arguments producing any value previously valid for contact. This is useful for servers who insist on requiring project-specific command-line invocations. * README.md (Installation and usage): Add entry for java-mode. * eglot.el (eglot-server-programs): Add entry for java-mode. (eglot-server-programs): CONTACT can be a fucntion of no arguments. (eglot--guess-contact, eglot--connect): Accept function CONTACTs.
|
@gavocanov , notice that the new commit is not in master yet. You must checkout to it directly or to the |
I think the |
I think we'll also need a couple of defcustoms for path to the jar and config used (not just |
Yes, path to the jar, jar version, and config should be defcustoms, the command line arguments are not generic. |
@mkcms is right, So, no need for function in Thnx for your help guys! |
@mkcms, @gavocanov: off the bat: no server-specific defcustoms, sorry.
In your other message you said it worked based on Can you show the skeleton of a minimal java project and show the actual args used for a successful invocation of the server for that project? |
I thought you might say that and I agree that eglot should be minimal like that. I'll look into adding support for this server just by using |
;)
good idea |
I came up with the following, although I don't know how correct it is. This server is badly documented. Also I found that you can actually build a single executable of it with maven... But it's name is just From 33442448cfad3bd2bef26506b7564256d18d938c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20K?= <k.michal@zoho.com>
Date: Tue, 7 Aug 2018 00:13:45 +0200
Subject: [PATCH] Improve eclipse.jdt.ls server support
---
README.md | 4 ++--
eglot.el | 61 ++++++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 50 insertions(+), 15 deletions(-)
diff --git a/README.md b/README.md
index f836b7f..8d35443 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ for the language of your choice. Otherwise, it prompts you to enter one:
* PHP's [php-language-server][php-language-server]
* C/C++'s [cquery][cquery]
* Haskell's [IDE engine][haskell-ide-engine]
-* Java's [Eclipse JDT Language Server][eclipse-jdt]
+* Java's [Eclipse JDT Language Server][eclipse-jdt] (if you [download and extract it][jdt-langserver-download-link] and point `CLASSPATH` environment variable at the `org.eclipse.equinox.launcher` jar file)
I'll add to this list as I test more servers. In the meantime you can
customize `eglot-server-programs`:
@@ -279,4 +279,4 @@ Under the hood:
[windows-subprocess-hang]: https://www.gnu.org/software/emacs/manual/html_node/efaq-w32/Subprocess-hang.html
[haskell-ide-engine]: https://github.com/haskell/haskell-ide-engine
[eclipse-jdt]: https://github.com/eclipse/eclipse.jdt.ls
-
+[jdt-langserver-download-link]: http://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz
diff --git a/eglot.el b/eglot.el
index d1e5c95..96a9dd2 100644
--- a/eglot.el
+++ b/eglot.el
@@ -94,19 +94,34 @@ language-server/bin/php-language-server.php"))
(haskell-mode . ("hie-wrapper"))
(java-mode
. ,(lambda ()
- `("java"
- "-Declipse.application=org.eclipse.jdt.ls.core.id1"
- "-Dosgi.bundles.defaultStartLevel=4"
- "-Declipse.product=org.eclipse.jdt.ls.core.product"
- "-Dlog.protocol=true"
- "-Dlog.level=ALL"
- "-noverify"
- "-Xmx1G"
- "-jar" "plugins/org.eclipse.equinox.launcher_1.5.100.v20180611-1436.jar"
- "-configuration" "config_mac"
- "-data" ,(if-let ((proj (project-current)))
- (car (project-roots proj))
- default-directory)))))
+ (when-let* ((classpath (getenv "CLASSPATH"))
+ (jar (cl-find-if
+ (lambda (path)
+ (string-match-p
+ "org\\.eclipse\\.equinox\\.launcher_.*.jar$"
+ (file-name-nondirectory path)))
+ (split-string classpath ":")))
+ (config
+ (expand-file-name
+ (cond
+ ((string= system-type "darwin") "config_mac")
+ ((string= system-type "windows-nt") "config_win")
+ (t "config_linux"))
+ (expand-file-name ".." (file-name-directory jar))))
+ (workspace (locate-user-emacs-file "eglot-workspace")))
+ (cons 'eglot-eclipse-jdt
+ (list (executable-find "java")
+ "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044"
+ "-Declipse.application=org.eclipse.jdt.ls.core.id1"
+ "-Dosgi.bundles.defaultStartLevel=4"
+ "-Declipse.product=org.eclipse.jdt.ls.core.product"
+ "-Dlog.protocol=true"
+ "-Dlog.level=ALL"
+ "-noverify"
+ "-Xmx1G"
+ "-jar" jar
+ "-configuration" config
+ "-data" workspace))))))
"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
@@ -1683,6 +1698,26 @@ 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 jdt langserver.")
+
+(cl-defmethod eglot-initialization-options ((server eglot-eclipse-jdt))
+ "Passes through required jdt initialization options"
+ `(:workspaceFolders
+ [,(eglot--path-to-uri (car (project-roots (eglot--project server))))]
+ ,@(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")))))
+
+
;; 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")
--
2.11.0
|
@mkcms your code looks fine, should work and it's exactly what I came up to without dynamic vars and it works. @joaotavora I agree and understand about defcustoms per lsp server impl, makes total sense. Not sure how well JAVA_HOME will work for me personally, on OS level (MacOS here) it's set to latest version (10/11) but I need to use 1.8 for this server to work. These days as a Java dev I'm changing Java environment for almost every project. I guess I'll be overriding it and it will be possible, right ? I'm sure it will be a good starter and default to have in eglot anyway. |
@mkcms, OK, but note we only need the lambda if the conditions likely to change between the moment that
We might as well support |
You mean default |
Yeah, or whatever it takes to officially support it (would have to see the spec). But a default specialization for that methods sounds good (perhaps conditional on the capability), with the remaining methods appending to |
|
Yes. I read this in the spec.
So, minimally we must annouce the capability and send I think we should start with this minimal implementation, and only then move on to support the Now, this won't solve the java problem just yet, because But I'd like to first understand if it works at all (perhaps by hardcoding JAVA_HOME in there, or defining a new project class). Are you up for this or do you prefer I try it out? Obviously your advantage is that you have a working Java environment, and I have not, |
CONTACT in the (MAJOR-MODE . CONTACT) association in eglot-server-programs can now be a function of no arguments producing any value previously valid for contact. The function is called at time of `M-x eglot` or `eglot-ensure`. This is useful for servers requiring command-line invocations that depend on the specific momentary environment. * eglot.el (eglot-server-programs): CONTACT can be a fucntion of no arguments. (eglot--guess-contact, eglot--connect): Accept function CONTACTs.
* README.md (Supported Protocol features): Declare workspaceFolders partially supported. * eglot.el (eglot-client-capabilities): Declare workspaceFolders supported. (eglot--connect): Maybe send :workspaceFolders in :initialize request.
You can go ahead.
I just downloaded openjdk with my system package manager and eclipse + eclipse.jdt.ls from eclipse website. It's self contained, so if you want to temporarily install it just extract it and then delete this folder (I put it in I also wonder if we can have an "interactive" lambda as a contact? So that if we fail to find the required programs/jars we can ask the user for a path from it. |
Never mind, I did it myself (the minimal bit). Can you try it with your java setup? Instead of defining a new server class I suggest you add a method to |
Good question. Try adding some |
OK I'll try it. |
By the way, the |
Maybe eglot can call the contact with |
But what should we do when the call is non-interactive, like from |
|
No, because To do what you want, it's better just to specify in But can you first show an example of such a function? |
You forgot to eval inner expr in initialize. I'm getting this:
|
Right. Silly me. If you fix that does it work?
…On Wed, Aug 8, 2018, 15:59 mkcms ***@***.***> wrote:
Can you try it with your java setup?
You forgot to eval inner expr in initialize. I'm getting this:
client-request (id:1) Wed Aug 8 16:56:19 2018:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
(:processId
(unless
(eq
(jsonrpc-process-type server)
'network)
(emacs-pid))
:rootPath
(expand-file-name default-directory)
:rootUri
(eglot--path-to-uri default-directory)
:initializationOptions
(eglot-initialization-options server)
:capabilities
(eglot-client-capabilities server)))
server-reply (id:1) ERROR Wed Aug 8 16:56:19 2018:
(:jsonrpc "2.0" :id 1 :error
(:code -32700 :message "Message could not be parsed." :data
(:message "java.lang.IllegalStateException: Expected an int but was BEGIN_ARRAY at line 1 column 70 path $.params.processId")))
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#63 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAXnw0i-eUYGhEhYCJPTCZKsjlqLtlUKks5uOvzRgaJpZM4Vwq9g>
.
|
It seems to work for me, but I'm testing it in a simple project.
I meant more generally subprojects of a project. Is there anything in the spec that actually says what workspace folders are? Even the vscode website isn't helpful. Also you mentioned that the design decision to make
To me it's obvious that a project can span multiple directories, like |
Lsp-mode already have support for all of the custom code that you need to make jdt work via https://github.com/emacs-lsp/lsp-java you may use it as a guide where appropriate. In general without looking at vscode extension code it is impossible to make jdt work . There are couple of extension points that have to be added in eglot to make jdt work
|
Hi @yyoncho. Thanks for the pointer. I don't have vscode (@mkcms do you?). Can you clarify hat each of these is? I'm having trouble linking them to the spec.
Ins't this
What do you mean?
I'm even more confused by this one. |
I don't.
This server executes codeActions in a nonstandard way: |
So much for "the spec"...
Yes, now I understand this problem.
Can I have one or two of those? |
Sure, I will make a writeup in the PR later. |
Jdt expects uris not part of the to be with custom prefix (jdt:) . You may check lsp-java implementation. I have limited internet access so I cannot get into details. |
@gavocanov @yyoncho Can you test this PR? #65 |
Everything works as expected, if there is no CLASSPATH it asks, if there is it starts with defaults and all works fine. The only thing I'd change is the temporary folder created for the workspace. Should not be a temporary directory, should be a shared directory for all java-mode projects IMO, now for every eglot session all the project metadata is recreated instead of being persisted and incrementally updated. Makes startup/first completion (company) etc. slow for no good reason. One more thing worth taking a look at is what @yyoncho was referring to, uris with prefix, I think that this would fix goto definition for stuff in dependencies if source jars available ( Other then that, great work, thnx a lot! |
I guess a |
@gavocanov @joaotavora Thanks, I just pushed that change to the PR branch. |
The problem is that the server is really undocumented. And even if it was, I think the solution would be too hacky for eglot. |
I haven't read all the discussions but if you talked about root detection logic (as In emacs-ccls, the default logic I use (emacs-lsp/emacs-ccls@b02a5d8#diff-2093f0a348c7bfdc7e0a9006283e081fR100):
If a project (say llvm, clickhouse) has subprojects (e.g. git submodules), we don't want files in subprojects think they are within their own project ( Someone added |
* eglot.el (eglot-server-programs): Mention that the function must accept one argument. (eglot--guess-contact): Pass to functional contacts the interactive value.
* 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.
…programs CONTACT in the (MAJOR-MODE . CONTACT) association in eglot-server-programs can now be a function of no arguments producing any value previously valid for contact. The function is called at time of `M-x eglot` or `eglot-ensure`. This is useful for servers requiring command-line invocations that depend on the specific momentary environment. * eglot.el (eglot-server-programs): CONTACT can be a fucntion of no arguments. (eglot--guess-contact, eglot--connect): Accept function CONTACTs.
* eglot.el (eglot-server-programs): Mention that the function must accept one argument. (eglot--guess-contact): Pass to functional contacts the interactive value.
* 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.
…programs CONTACT in the (MAJOR-MODE . CONTACT) association in eglot-server-programs can now be a function of no arguments producing any value previously valid for contact. The function is called at time of `M-x eglot` or `eglot-ensure`. This is useful for servers requiring command-line invocations that depend on the specific momentary environment. * eglot.el (eglot-server-programs): CONTACT can be a fucntion of no arguments. (eglot--guess-contact, eglot--connect): Accept function CONTACTs.
* eglot.el (eglot-server-programs): Mention that the function must accept one argument. (eglot--guess-contact): Pass to functional contacts the interactive value.
* 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.
CONTACT in the (MAJOR-MODE . CONTACT) association in eglot-server-programs can now be a function of no arguments producing any value previously valid for contact. The function is called at time of `M-x eglot` or `eglot-ensure`. This is useful for servers requiring command-line invocations that depend on the specific momentary environment. * eglot.el (eglot-server-programs): CONTACT can be a fucntion of no arguments. (eglot--guess-contact, eglot--connect): Accept function CONTACTs. #63: joaotavora/eglot#63
* eglot.el (eglot-server-programs): Mention that the function must accept one argument. (eglot--guess-contact): Pass to functional contacts the interactive value. #63: joaotavora/eglot#63
* 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. #63: joaotavora/eglot#63
CONTACT in the (MAJOR-MODE . CONTACT) association in eglot-server-programs can now be a function of no arguments producing any value previously valid for contact. The function is called at time of `M-x eglot` or `eglot-ensure`. This is useful for servers requiring command-line invocations that depend on the specific momentary environment. * eglot.el (eglot-server-programs): CONTACT can be a fucntion of no arguments. (eglot--guess-contact, eglot--connect): Accept function CONTACTs. GitHub-reference: per joaotavora/eglot#63
* eglot.el (eglot-server-programs): Mention that the function must accept one argument. (eglot--guess-contact): Pass to functional contacts the interactive value. GitHub-reference: per joaotavora/eglot#63
* 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. GitHub-reference: per joaotavora/eglot#63
Hi,
I'm trying to use java lsp and all is working great, but I need to pass a command line argument for the workspace path when starting the lsp server.
I do not see a way to do it with the current options, is there anyway I can accomplish that ?
I should ad "-data" as the last option with project root. If I add a hardcoded path all works fine but I need this to be dynamic, ideally using
(projectile-project-root)
or something similar.Thnx in advance and keep up the good work, eglot is really great!
The text was updated successfully, but these errors were encountered: