eglot与jdtls的最新版在Windows上的配合

·  阅读 294

问题,无法找到可执行文件

最新版的eglot已经去掉了原先在eglot.el中为jdtls的特殊兼容代码,而使用jdtls最新的python脚本来启动。

但jdtls的Python脚本只提供了适合于*inx环境的(不带后缀的)jdtls可执行文件。这样以来Windows的环境就无法正常运行起来。

因为,eglot--executable-find函数(底层是executable-find)无法在Windows平台上找到可执行文件(jdtls.exe或者jdtls.bat)。这一点通过执行以上两个文件即可得出结论,以下均返回nil。

(eglot--executable-find "jdtls")
(executable-find "jdtls")

既然问题已经找到了,我们就尝试解决一下。不是找不到可执行文件么?我们来创建一个不就行了?


尝试,生成一个jdtls.exe

既然是使用Python写成的代码,而且jdtls中的代码极其简单(就是调用jdtls.py来组装一个java命令,然后通过os.system运行它),那么我们用pyinstaller生成一个即可。

pip install pyinstaller
pyinstaller --onefile jdtls
mv .\dist\jdtls.exe .

运行这个exe,发现失败了。失败是符合预期的,因为main函数中需要传递sys.argv[1:],但是失败的报错却是非预期的:

Error: Unable to access jarfile '<...省略一部分路径>/org.eclipse.equinox.launcher_1.6.<...省略一部分版本>.jar'

分析,关于jar的错误

实际上,我们直接使用python来运行也是这样的错误。

python .\jdtls

我们尝试修改jdtls.py文件,把最后组装的命令打印出来为:

java -Declipse.application=org.eclipse.jdt.ls.core.id1 -Dosgi.bundles.defaultStartLevel=4 -Declipse.product=org.eclipse.jdt.ls.core.product -Dosgi.checkConfiguration=true -Dosgi.sharedConfiguration.area='D:\Tools\java\jdtls\server\config_win' -Dosgi.sharedConfiguration.area.readOnly=true -Dosgi.configuration.cascaded=true -noverify -Xms1G --add-modules=ALL-SYSTEM --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED -jar 'D:\Tools\java\jdtls\server\plugins\org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar'

其中D:/Tools/java/jdtls/server是我本机存放jdtls的目录。

如果你对Windows下的CMD命令熟悉的话,大概一眼就能看出问题了。那就是路径的问题。预期是:

D:/Tools/java/jdtls/server/plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar

实际是:

'D:\Tools\java\jdtls\server\plugins\org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar'

斜杠与引号的问题。


解决,手写一个可执行文件

我们其实已经拿到了最终的命令,而且纵览整个jdtls以及jdtls.py,它全部的功能就是为了生成这条命令,那么我们直接来简单粗暴的写一个可执行文件来调用这条命令即可。方法有二。

方法一,还是用Python生成exe

但代码内容就非常粗暴了。

# jdtls-for-win.py
import os
import sys

if getattr(sys, "frozen", False):
    dir_path = os.path.dirname(os.path.dirname(os.path.abspath(sys.executable)))
else:
    dir_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

cmd = (
    "java"
    " -Declipse.application=org.eclipse.jdt.ls.core.id1"
    " -Dosgi.bundles.defaultStartLevel=4"
    " -Declipse.product=org.eclipse.jdt.ls.core.product"
    " -Dosgi.checkConfiguration=true"
    f" -Dosgi.sharedConfiguration.area={dir_path}/config_win"
    " -Dosgi.sharedConfiguration.area.readOnly=true"
    " -Dosgi.configuration.cascaded=true"
    " -noverify"
    " -Xms1G"
    " --add-modules=ALL-SYSTEM"
    " --add-opens java.base/java.util=ALL-UNNAMED"
    " --add-opens java.base/java.lang=ALL-UNNAMED"
    f" -jar {dir_path}/plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar"
    f" {' '.join(sys.argv[1:])}"
)

os.system(cmd)

然后生成exe文件,放到bin下即可。

pyinstaller --onefile jdtls-for-win.py

这样就解决了。

方法二,如果你不想生成一个exe

不论你是因为不想安装Python/Pyinstaller或者是其他的原因,你都可以不生成一个exe文件,而换成bat文件的。因为在Windows下,bat也是一个可执行文件的后缀。

但这里需要注意,bat中需要稍微费点精力来解决传参的问题:

@echo off
​
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
​
java -Declipse.application=org.eclipse.jdt.ls.core.id1 -Dosgi.bundles.defaultStartLevel=4 -Declipse.product=org.eclipse.jdt.ls.core.product -Dosgi.checkConfiguration=true -Dosgi.sharedConfiguration.area=D:/Tools/java/jdtls/server/config_win -Dosgi.sharedConfiguration.area.readOnly=true -Dosgi.configuration.cascaded=true -noverify -Xms1G --add-modules=ALL-SYSTEM --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED -jar D:/Tools/java/jdtls/server/plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar %CMD_LINE_ARGS%
​

这样也能解决问题。


特殊提醒

以上的所有的前提是server/bin在环境变量PATH里面。

分类:
开发工具
标签:
分类:
开发工具
标签:
收藏成功!
已添加到「」, 点击更改