I ran into an issue with either Emacs, eglot, or jetls. @aviatesk was unable to reproduce it, so I made a minimal reproducible environment with straight.el at
I wonder if anyone can reproduce the issue running from ./run.sh, and if file.jl is otherwise fine in your standard config, how the versions of the relevant packages differ.
I really want to use jetls but there may be an issue lurking in my setup that I need to track down to make the experience hassle-free.
Thanks for putting together the MWE.
I dug into this and the eglot error message itself is a strong signal:
(args-out-of-range “inplace_∂g∂x_v!(x)” 21 22)
The string “inplace_∂g∂x_v!(x)” has:
18 characters
22 bytes in UTF-8 (each ∂ takes 3 bytes)
18 UTF-16 code units (∂ is in the BMP)
The args 21 22 only match the UTF-8 byte length. Emacs string indexing is character-based, so accessing index 21–22 in an 18-character string blows up. So eglot has a code path that’s receiving UTF-8 byte offsets but using them as Emacs character positions without converting. That a timer fires it suggests something in the eldoc / hover-related-info display.
What JETLS does: it checks general.positionEncodings from the client and prefers UTF-8 if advertised (since UTF-8 is the native encoding for Julia strings — no conversion needed server-side), falling back to UTF-16 otherwise. eglot 1.17+ advertises UTF-8, so JETLS picks UTF-8 when talking to it.
VS Code and Zed both handle the same UTF-8 positions correctly, which is consistent with this being a bug somewhere in eglot’s processing path rather than in the data JETLS sends.
You can verify this on your setup by forcing JETLS to use UTF-16. Set up a local JETLS checkout with this patch applied to JETLS:
diff --git a/src/initialize.jl b/src/initialize.jl
index 4ba882ae..022725cc 100644
--- a/src/initialize.jl
+++ b/src/initialize.jl
@@ -261,14 +261,15 @@ function handle_InitializeRequest(
end
end
- positionEncodings = getcapability(state, :general, :positionEncodings)
- if isnothing(positionEncodings) || isempty(positionEncodings)
- positionEncoding = PositionEncodingKind.UTF16
- elseif PositionEncodingKind.UTF8 in positionEncodings
- positionEncoding = PositionEncodingKind.UTF8
- else
- positionEncoding = first(positionEncodings)
- end
+ # positionEncodings = getcapability(state, :general, :positionEncodings)
+ # if isnothing(positionEncodings) || isempty(positionEncodings)
+ # positionEncoding = PositionEncodingKind.UTF16
+ # elseif PositionEncodingKind.UTF8 in positionEncodings
+ # positionEncoding = PositionEncodingKind.UTF8
+ # else
+ # positionEncoding = first(positionEncodings)
+ # end
+ positionEncoding = PositionEncodingKind.UTF16
state.encoding = positionEncoding
result = InitializeResult(;
If the error goes away, that confirms the issue lives on the eglot side, and we can take it upstream from there.