The goal of this project is to develop a new language server for Julia, currently called "JETLS". JETLS aims to enhance developer productivity by providing advanced static analysis and seamless integration with the Julia runtime. By leveraging tooling technologies like JET.jl, JuliaSyntax.jl and JuliaLowering.jl, JETLS aims to offer enhanced language features such as type-sensitive diagnostics, macro-aware go-to definition and such.
This repository manages JETLS.jl, a Julia package that implements a language
server, and jetls-client,
a sample VSCode extension that serves as a language client for testing JETLS.
For information on how to use JETLS with other frontends, please refer to the
Other editors section.
Important
Currently, the jetls-client VSCode extension is not bundled with JETLS.jl
as a Julia package, requiring you to explicitly specify the path to your
JETLS.jl installation via the jetls-client.jetlsDirectory configuration
and ensure the environment is properly initialized with Pkg.instantiate().
Since JETLS is currently distributed as source code, updates must be
performed manually using git pull, followed by Pkg.update() and
Pkg.instantiate() to refresh dependencies.
- Clone and initialize this repository:
git clone https://github.com/aviatesk/JETLS.jl.git cd JETLS.jl julia --project=. -e 'using Pkg; Pkg.instantiate()'
- Install the JETLS Client VSCode extension (
jetls-client):- Open VSCode
- Go to Extensions (Invoke the
View: Show Extensionscommand) - Search for
"JETLS Client" - Click
Install
- Configure the extension:
- Open VSCode settings
- Set
jetls-client.jetlsDirectoryto the path of the cloned JETLS.jl repository - (Optional) Set
jetls-client.juliaExecutablePathto your Julia executable path (default:julia)
- Open any Julia file
JETLS supports multiple communication channels between the client and server. Choose based on your environment and requirements:
The jetls-client VSCode extension automatically selects the most appropriate
channel based on your environment:
- Local development:
pipefor maximum safety - Remote SSH/WSL:
pipe(works well in these environments) - Dev Containers:
stdiofor compatibility
- Advantages: Complete isolation from
stdin/stdout, preventing protocol corruption; fastest for local communication - Best for: Local development, Remote SSH, WSL
- Limitations: Not suitable for cross-container communication
- Advantages: Complete isolation from
stdin/stdout, preventing protocol corruption; works across network boundaries; supports port forwarding - Best for: Remote development with port forwarding
- Limitations: May require firewall configuration; potentially less secure than local alternatives
- Advantages: Simplest setup; maximum compatibility; works everywhere
- Best for: Dev containers; environments where
pipedoesn't work - Limitations: Risk of protocol corruption if any code writes to
stdin/stdout
Warning
When using stdio mode, any println(stdout, ...) in your code or dependency
packages may corrupt the LSP protocol and break the connection. Prefer pipe
or socket modes when possible.
When using JETLS from the command line or with other editors:
# Standard input/output (default, --stdio can be omitted)
julia runserver.jl --stdio
# Unix domain socket or Windows named pipe
julia runserver.jl --pipe=/tmp/jetls.sock
# TCP socket
julia runserver.jl --socket=7777Important
These setups use generic language clients, requiring you to explicitly
specify the path to your JETLS.jl installation and ensure the environment
is properly initialized with Pkg.instantiate(). Since JETLS is currently
distributed as source code, updates must be performed manually using
git pull, followed by Pkg.update() and Pkg.instantiate() to refresh
dependencies.
Warning
These setups are basically very minimal and do not necessarily properly
utilize the communication channels described above. Many of these setups
simply use stdio as the communication channel, but as noted above, there
are potential risks of breaking LSP connections due to writes to stdout
that may occur when loading dependency packages.
Minimal Emacs (eglot client) setup:
(add-to-list 'eglot-server-programs
'(((julia-mode :language-id "julia")
(julia-ts-mode :language-id "julia"))
"julia"
"--startup-file=no"
"--history-file=no"
"--project=/path/to/JETLS.jl"
"--threads=auto"
"/path/to/JETLS.jl/runserver.jl"
"--socket"
:autoport))Minimal Neovim setup (requires Neovim v0.11):
vim.lsp.config("jetls", {
cmd = {
"julia",
"--startup-file=no",
"--history-file=no",
"--project=/path/to/JETLS.jl",
"--threads=auto",
"/path/to/JETLS.jl/runserver.jl",
},
filetypes = {"julia"},
})
vim.lsp.enable("jetls")Zed extension for Julia/JETLS is available: See aviatesk/zed-julia#avi/JETLS for installation steps.
Minimal Helix setup:
languages.toml
[[language]]
name = "julia"
language-servers = [ "jetls" ]
[language-server]
jetls = { command = "julia", args = ["--startup-file=no", "--history-file=no", "--project=/path/to/JETLS.jl", "--threads=auto", "/path/to/JETLS.jl/runserver.jl"] }This is a summary of currently implemented features and features that will likely be implemented in the near future, for those who want to test this server. Please note that not only the progress of the list, but also the structure of the list itself is subject to change.
- Analysis
- Document synchronization
- Incremental analysis
- JuliaLowering integration
- Recursive analysis for dependencies
- Cross-server-process cache system
- Diagnostics
- Syntax errors
- Lowering errors
- Undefined bindings
- Unused bindings
- Potential
MethodError - Configuration integration
- Completion
- Global symbol completion
- Local binding completion
- LaTeX/Emoji completion
- Method signature completion
- Property completion
- Signature Help
- Basic implementation
- Macro support
- Argument type based suggestion
- Definition
- Method defintion
- Global binding definition
- Local binding definition
- Type-aware method definition
- Document Highlight
- Highlight local binding
- Hover
- Method documentation
- Global binding documentation
- Local binding location
- Type-aware method documentation
- Type of local binding on hover
- Formatting
- Runic integration
- JuliaFormatter integration
- Make formatting backend configurable
- Rename
- Local binding
- Global binding
- Field name
- TestRunner.jl integration
- Code lens for running individual
@testsets - Code actions for running individual
@testsets - Code actions for running individual
@testcases - Inline test result diagnostics
- Code lens for running individual
- Configuration system
- Type stable config object implementation
- Support LSP configurations
- Documentation
- Schema support
- Parallel/concurrent message handling
- Work done progress support
- Message cancellation support
- Notebook support
- Release
- Publish a standalone VSCode language client extension
- Environment isolution
- Bundle JETLS (as a Julia package)
- Integration into julia-vscode
Detailed development notes and progress for this project are collected at https://publish.obsidian.md/jetls, so those interested might want to take a look.
JETLS integrates with TestRunner.jl
to provide an enhanced testing experience directly within your editor. This
feature allows you to run individual @testset blocks directly from your
development environment.
To use this feature, you need to install the testrunner executable:
julia -e 'using Pkg; Pkg.Apps.add(url="https://github.com/aviatesk/TestRunner.jl")'Note that you need to manually make ~/.julia/bin available on the PATH
environment for the testrunner executable to be accessible.
See https://pkgdocs.julialang.org/dev/apps/ for the details.
When you open a Julia file containing @testset blocks, JETLS displays
interactive code lenses above each @testset:
▶ Run "testset_name": Run the testset for the first time
After running tests, the code lens is refreshed as follows:
▶ Rerun "testset_name" [summary]: Re-run a testset that has previous results☰ Open logs: View the detailed test output in a new editor tab✓ Clear result: Remove the test results and inline diagnostics
You can trigger test runs via "code actions" when the code action range is requested:
- Inside a
@testsetblock: Run the entire testset
- On an individual
@testmacro: Run just that specific test case
Note that when running individual @test cases, the error results are displayed
as temporary diagnostics for 10 seconds. Click ☰ Open logs button in the
pop up message to view detailed error messages that persist.
Failed tests are displayed as diagnostics (red squiggly lines) at the exact lines where the failures occurred, making it easy to identify and fix issues:
For clients that support work done progress, JETLS shows progress notifications while tests are running, keeping you informed about long-running test suites.
The TestRunner integration supports:
- Named
@testsetblocks (via code lens or code actions):
using Test
# supported: named `@testset`
@testset "foo" begin
@test sin(0) == 0
@test sin(Inf) == 0
@test_throws ErrorException sin(Inf) == 0
@test cos(π) == -1
# supported: nested named `@testset`
@testset "bar" begin
@test sin(π) == 0
@test sin(0) == 1
@test cos(Inf) == -1
end
end
# unsupported: `@testset` inside function definition
function test_func1()
@testset "inside function" begin
@test true
end
end
# supported: this pattern is fine
function test_func2()
@testset "inside function" begin
@test true
end
end
@testset "test_func2" test_func2()- Individual
@testmacros (via code actions only):
# Run individual tests directly
@test 1 + 1 == 2
@test sqrt(4) ≈ 2.0
# Also works inside testsets
@testset "math tests" begin
@test sin(0) == 0 # Can run just this test
@test cos(π) == -1 # Or just this one
end
# Multi-line `@test` expressions are just fine
@test begin
x = complex_calculation()
validate(x)
end
# Other Test.jl macros are supported too
@test_throws DomainErrors sin(Inf)See the README.md of TestRunner.jl for more details.
If you see an error about testrunner not being found:
- Ensure you've installed TestRunner.jl as described above
- Check that
testrunneris in your system PATH by runningwhich testrunner: otherwise you may need to add~/.julia/bintoPATH - Restart your editor to ensure it picks up the updated PATH
Test execution requires that your file is saved and matches the on-disk version. If you see a message asking you to save the file first, make sure to save your changes before running tests.
- DEVELOPMENT.md: Developer notes
- AGENTS.md: Specific coding rules (recommended reading for human developers as well)









