The goal of this project is to develop a new language server for Julia, currently called "JETLS". This language server 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.
- VSCode v1.93.0 or higher
- npm v11.0.0 or higher
- Julia
v"1.12.0-beta2"
or higher
- Run
julia --project=. -e 'using Pkg; Pkg.instantiate()'
in this folder to install all necessary Julia packages. - Run
npm install
in this folder to install all necessary node modules for the client. - Open this folder in VSCode.
- Press Ctrl+Shift+B to start compiling the client and server in watch mode.
- Switch to the Run and Debug View in the Sidebar (Ctrl+Shift+D).
- Select
Launch Client
from the drop-down menu (if it is not already selected). - Press
▷
to run the launch configuration (F5). - In the Extension Development Host instance of VSCode, open a Julia file.
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"
"/path/to/JETLS.jl/runserver.jl"))
Minimal Neovim setup (requires Neovim v0.11):
vim.lsp.config("jetls", {
cmd = {
"julia",
"--startup-file=no",
"--history-file=no",
"--project=/path/to/JETLS.jl",
"/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", "/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.
- Full-Analysis
- Document synchronization
- JuliaLowering integration
- Incremental analysis
- Recursive analysis for dependencies
- Cross-server-process cache system
- Diagnostics
- Report undefined bindings
- Report unused bindings
- Report potential
MethodError
- Completion
- Global symbol completion
- Local binding completion
- LaTeX/Emoji completion
- Method signature completion
- Signature Help
- Basic implementation
- Macro support
- Argument type based suggestion
- Definition
- Method defintion
- Global binding definition
- Local binding definition
- Type-aware method definition
- Hover
- Method documentation
- Global binding documentation
- Local binding location
- Type-aware method documentation
- Type of local binding on hover
- Formatting
- Make formatting backend configurable
- Runic integration
- JuliaFormatter integration
- TestRunner.jl integration
- Code lens for running individual
@testset
s - Code actions for running individual
@testset
s - Code actions for running individual
@test
cases - Inline test result diagnostics
- Work done progress during test execution
- Code lens for running individual
- Configuration system
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
@testset
block: Run the entire testset
- On an individual
@test
macro: 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
@testset
blocks (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
@test
macros (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
testrunner
is in your system PATH by runningwhich testrunner
: otherwise you may need to add~/.julia/bin
toPATH
- 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)