CHANGELOG

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog.

Note

JETLS uses date-based versioning (YYYY-MM-DD) rather than semantic versioning, as it is not registered in General due to environment isolation requirements.

Each dated section below corresponds to a release that can be installed via Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="YYYY-MM-DD")

To install the latest version regardless of date, re-run the installation command:

julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release")'

Unreleased

Announcement

Important

JETLS supports Julia 1.12.2 through 1.13. It does not support Julia 1.12.1 or earlier, nor Julia 1.14+/nightly.

Note

The official Zed extension for Julia, JuliaEditorSupport/zed-julia, now uses JETLS as its default language server since v0.2.0. Install the Julia extension from Zed's extensions view: like jetls-client, it installs and updates the pinned JETLS release automatically, so Zed users no longer need to install jetls or keep it up to date manually (still needed if you also use the jetls CLI, e.g. jetls check). This is a breaking migration from LanguageServer.jl for existing users of the extension; see Migrating to version 0.2. If you have been using the aviatesk/zed-julia fork, switch to the official extension, and move your settings from lsp.JETLS to lsp.jetls, since the language server ID is now jetls. Please report extension-specific problems (installation, startup, extension UI) to JuliaEditorSupport/zed-julia issues; language-feature issues belong here as before.

Note

TestRunner.jl is now developed in this repository as a subpackage and released together with JETLS, and aviatesk/TestRunner.jl is no longer updated. Installing JETLS is all you need to run tests with TestRunner.jl: the TestRunner integration keeps using the TestRunner.jl bundled with JETLS, and the new jetls test command runs tests with it from the command line:

jetls test test/runtests.jl "selected tests"

If you want to run TestRunner.jl without loading JETLS, install the standalone testrunner executable from this repository, which replaces the one installed from aviatesk/TestRunner.jl:

julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", subdir="TestRunner", rev="release")'
Warning

JETLS currently has a known memory leak issue where memory usage grows with each re-analysis (aviatesk/JETLS.jl#357). As a temporary workaround, you can disable full-analysis for specific files using the analysis_overrides initialization option:

// VSCode settings.json example
{
  "jetls-client.initializationOptions": {
    "analysis_overrides": [
      { "path": "src/**/*.jl" },
      { "path": "test/**/*.jl" }
    ]
  }
}

This disables full analysis for matched files; see Files without full analysis for what remains available for them. Note that analysis_overrides is provided as a temporary workaround and may be removed or changed at any time. A proper fix is being worked on.

Note: Path glob patterns use / as the separator on all platforms, including Windows; backslashes are not supported as separators.

Added

  • Added inference/failing-test diagnostic that reports a @test that always fails, i.e. whose expression is inferred to evaluate to false or to a non-boolean value:
    @testset "foo" begin
        v = [1, 2, 3]
        @test length(v)  # this test always fails since its expression evaluates to non-boolean `Int64`
    end
    @test_broken, @test ex broken=true, and tests in function bodies are not reported. (aviatesk/JET.jl#896)

Changed

  • Full analysis now analyzes test sets as if they were declared with failfast=true, so it analyzes the code after @test ex assuming that ex is true:

    @testset "foo" begin
        x = rand((0, nothing))
        @test x isa Int
        sin(x)  # no longer reported as `sin(::Nothing)`
    end

    The code after a test that always fails is not analyzed, while inference/failing-test reports such a test. Test sets that specify failfast=false and test sets of a custom type are analyzed as declared. (aviatesk/JET.jl#895, aviatesk/JET.jl#896)

  • Hover, inlay hints, and other features that show inferred types now also infer the code after @test ex assuming that ex is true, so they show x as Int64 after @test x isa Int in the example above.

  • Go to definition on a string literal that names an existing file, such as the path in include("utils/binding.jl") or joinpath(@__DIR__, "data.toml"), now jumps to that file instead of to the definition of the function it is passed to. The path is resolved relative to the directory of the current file, and go to definition on include itself still jumps to the definition of include.

Fixed

  • Fixed false lowering/macro-expansion-error diagnostics on @doc docstrings inside blocks such as if blocks and on @doc lookups such as string(@doc sin) when JETLS also analyzes code that loads DocStringExtensions.jl, e.g. a docs/make.jl using Documenter.jl.

  • Fixed missing references, rename edits, and lowering/undef-global-var diagnostics for docstrings that document a method signature:

    """
        someinterface(::Type{<:Integer})
    
    Docstring for `someinterface` on integer types.
    """
    someinterface(::Type{<:Integer})

    The documented signature on the last line now counts as a reference to someinterface and Integer, so renaming someinterface also updates it, and a misspelled argument type there is reported at its exact location.

  • Fixed rename failing with an error when invoked on a long string literal such as a docstring.

2026-10-14

  • Commit: 64dd358
  • Diff: ab294bc...64dd358
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-10-14")'

Added

  • Added the on_include field to analysis_overrides entries. With on_include = "skip", full analysis skips an include of a matched file and continues with the rest of the analysis unit, reporting toplevel/analysis-skipped as information at the call. This suits files whose definitions the rest of the unit does not use, such as an expensive test file included from test/runtests.jl:
    [[initialization_options.analysis_overrides]]
    path = "test/test_expensive.jl"
    on_include = "skip"
    The default on_include = "stop" stops the unit with toplevel/analysis-stopped (see the fix below). Like analysis_overrides itself, on_include is experimental and may be removed or changed at any time.

Changed

  • toplevel/abstract-field is now reported as a hint instead of information, since abstract fields are often intentional. jetls check no longer shows it by default (use --show-severity=hint to show it), and editors render it less prominently. To restore the previous severity, configure it with diagnostic.patterns:

    [[diagnostic.patterns]]
    pattern = "toplevel/abstract-field"
    match_by = "code"
    match_type = "literal"
    severity = "info"
  • Files excluded by analysis_overrides now report toplevel/analysis-skipped as information at their first line, naming the matched pattern, so that the exclusion is visible. The files of a package or its tests whose entry file is excluded report it as well, naming the entry file. Passing such files to jetls check now reports it along with the diagnostics that do not require full analysis, instead of failing with could not find any files to analyze. Package extension files keep reporting it as a warning.

  • Files under the src/ or test/ directory of a package that no include from src/<name>.jl or test/runtests.jl reaches now report toplevel/analysis-skipped as information at their first line, naming the entry file, since such files are often no longer used. Saving such a file no longer reanalyzes the whole package or its tests.

  • Changing full_analysis.concretization_patterns now reanalyzes only the analysis units containing files the added or removed patterns apply to, instead of every analyzed unit. Package source analysis is no longer rerun, since it does not use the configured patterns.

  • Reduced the startup latency of jetls check and of language server sessions by precompiling more of what they always run, such as loading the configuration, handling the initialized notification, publishing diagnostics, and full analysis. For example, jetls check on a small script now finishes in about 1.5 seconds instead of 2.8 seconds.

  • The jetls commands that do not need the language server, namely jetls --help, jetls --version, jetls schema, and the --help of each command, now finish in about 0.1 seconds instead of 0.9 seconds. Clients that check the installed version before starting the server, such as the Zed extension, start it about 0.8 seconds faster accordingly.

Fixed

  • Fixed analysis_overrides being ignored when full analysis reached an excluded file through include, or when the excluded file was the entry file of a package or its tests. Full analysis now stops that unit before loading the excluded file and reports the new toplevel/analysis-stopped warning at the include call, unless the override sets on_include = "skip" (see above). Diagnostics from top-level code before the include are kept, but code after it and method bodies are not analyzed. Other analysis units are unaffected. Since this is a warning, it causes jetls check to fail by default. Like analysis_overrides itself, toplevel/analysis-stopped is experimental and may be removed or changed at any time. The files of a package or its tests whose entry file is excluded are no longer analyzed, and report toplevel/analysis-skipped instead.

  • Fixed a WARNING: Detected access to binding ... in a world prior to its definition world message that full analysis could print for scripts that define a global const inside a let block and use it within the same block, e.g. during jetls check.

  • Fixed the TestRunner integration and jetls test running all tests in a test file whose module has a docstring, instead of only the selected ones.

  • Fixed full-analysis diagnostics in code checked by Test.jl macros, such as the body of a @testset or a multi-line @test expression, being reported on the first line of the enclosing top-level statement, e.g. the outermost @testset, so that diagnostics with the same message on different lines were reported only once. They are now reported on the line of the code that causes them:

    f(x::Int) = x
    @testset "outer" begin    # previously, both `f` calls were reported here, only once
        @testset "inner" begin
            f("julia")        # now reported here
        end
        @test begin
            y = "julia"
            f(y) == 1         # and here
        end
    end
  • Fixed diagnostics on an include call inside a block or a function being reported on the first line of the enclosing top-level statement instead of on the include call.

  • Fixed full analysis failing without reporting any diagnostics when the analyzed code calls include with arguments that no include method accepts, such as include(Symbol("file.jl")), or calls Base.include(mapexpr, mod, path). The former is now reported as toplevel/error, and the latter as toplevel/unsupported-feature, with the included file analyzed in mod without applying mapexpr.

  • Fixed full analysis of a package stopping with ArgumentError: Module Main does not correspond to a loaded package! at top-level uses of Preferences.jl such as @load_preference, which left the rest of the package unanalyzed. @load_preference no longer reports lowering/macro-expansion-error with the same error either. (Closed aviatesk/JETLS.jl#478)

  • Fixed pathof, pkgdir, and pkgversion returning nothing for the module of the analyzed package and its submodules during full analysis, which stopped the analysis with errors such as MethodError: no method matching dirname(::Nothing) at code like include(joinpath(dirname(pathof(@__MODULE__)), "file.jl")) and left the rest of the package unanalyzed. They now return the location and version of the analyzed package, also when called from functions defined in the package. (Closed aviatesk/JETLS.jl#630)

  • Fixed test files of a package with a test/Project.toml, e.g. a [workspace] member of the package, being analyzed on their own unless test/runtests.jl had been analyzed first, without what test/runtests.jl loads and defines before including them, which caused false diagnostics such as $`@testset` not defined$. They are now analyzed from test/runtests.jl in the environment of test/Project.toml, as documented for package test files. As for packages without a test/Project.toml, files under test/ that test/runtests.jl does not include are not analyzed and report toplevel/analysis-skipped instead.

2026-10-11

  • Commit: ab294bc
  • Diff: 53cd4a5...ab294bc
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-10-11")'

Added

  • Added the jetls test command, which runs tests from the command line with the TestRunner.jl bundled with JETLS, as the TestRunner integration does. It runs only the tests that match the given patterns, such as a testset name or a line range, applies the [testrunner] configuration of .JETLSConfig.toml, and accepts --julia and --project to select the Julia and the environment of the tests:
    jetls test test/runtests.jl "basic tests"
    jetls test --julia=/path/to/julia-nightly test/runtests.jl L15:25

Fixed

  • Fixed running a test set nested in other test sets with the TestRunner integration reporting no results when a test set next to it, or next to one of its enclosing test sets, contains other test sets. For example, running "a" in the following code reported no results:
    @testset "outer" begin
        @testset "a" begin
            @test f() == 1
        end
        @testset "b" begin
            @testset "c" begin
                @test g() == 2
            end
        end
    end

2026-10-08

  • Commit: 53cd4a5
  • Diff: 3efdc63...53cd4a5
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-10-08")'

Added

  • Added package directory input to jetls check: jetls check /path/to/SomePkg analyzes the package through its src/SomePkg.jl, and jetls check without paths analyzes the package in the current directory. When a single package directory is given, its .JETLSConfig.toml is loaded and paths are displayed relative to it, unless --root is specified. The files input of the GitHub Action is now optional and defaults to the package at the repository root.

  • Added stdin input to jetls check: jetls check - reads Julia source from stdin and analyzes it as a standalone script, like an unsaved buffer in the language server:

    echo 'f(x) = undefined_name + x' | jetls check -

    With the new --stdin-filename=<path> option, the source is analyzed in place of the file at <path> instead: for a package source file, the package is analyzed with the source substituted for the file on disk. This allows checking changes to a package file before writing them, e.g. renaming helper to helper2 in src/utils.jl:

    sed 's/helper/helper2/g' src/utils.jl | jetls check --stdin-filename=src/utils.jl -

    Without --stdin-filename, names defined in the other files of the package would be reported as undefined.

  • Added the lowering/orphaned-docstring diagnostic, reported on docstrings that silently document nothing:

    • docstrings separated from the definition by a blank line or comment
    • docstrings in if blocks (including @static if) without @doc
    • raw"..." docstrings without @doc
    • docstrings in local scope such as function bodies
    • field docstrings of structs that have no docstring themselves (which Julia discards)

    For example, area below is left undocumented, since a raw"..." docstring needs @doc:

    raw"""
        area(r)
    
    Compute ``\pi r^2``.
    """  # (JETLS lowering/orphaned-docstring)
    area(r) = π * r^2

    The "Attach docstring to the following definition" code action fixes them by prefixing @doc and removing the blank lines as needed. This check was suggested in JuliaLang/julia#63631, which fixed such docstrings in Julia itself.

  • Added the config/deprecated-key and config/deprecated-value warnings on deprecated keys and values of .JETLSConfig.toml, with quick fixes that remove a key, move its value to the new key, or replace a value, while keeping the rest of the file, including comments, as it is. The warning message shown when JETLS loads such a file now also offers a "Fix all" action that applies these fixes to the file. The legacy true and false values of full_analysis.auto_instantiate are now reported the same way, and also come with a warning when set through LSP settings.

  • Added the Analysis documentation page, which explains the two layers of JETLS's analysis: full analysis, which loads your code with package analysis or script analysis, and live analysis, which builds on the module context that full analysis establishes. It also describes how each file is analyzed depending on its location and environment, when full analysis runs, and what remains available for files that full analysis does not cover.

  • Added the toplevel/unsupported-feature warning, reported when full analysis loads code that uses a feature JETLS does not support and analyzes it with an approximation instead. It is currently reported for include(mapexpr, filename) calls, whose included file is analyzed without applying mapexpr.

Changed

  • Package extension files (files under the ext directory of a package) are no longer full-analyzed, and the new toplevel/analysis-skipped warning is reported at the top of each such file instead. They were previously analyzed as standalone scripts in the package environment, where weak dependencies are not installed, so their analysis typically stopped at a misleading toplevel/error with a message like Package SomeDep not found in current path. Since the new diagnostic is a warning, jetls check fails by default when package extension files are passed to it.

  • Full analysis now stops at the first top-level error, such as toplevel/error, toplevel/missing-concretization, or toplevel/concretization-timeout: code after the error is no longer loaded or analyzed, so follow-up errors caused by the incompletely loaded code are no longer reported. Diagnostics for top-level code before the error are still reported, and method bodies are analyzed again once the error is fixed. Code that cannot be lowered or whose macros fail to expand is now also reported as toplevel/error to show where full analysis stopped.

  • Syntax warnings detected by JuliaSyntax.jl, such as parentheses are not required here, are now reported with the new syntax/parse-warning code instead of syntax/parse-error, so they can be configured separately from syntax errors. diagnostic.patterns entries matching the syntax/parse-error code no longer apply to them.

  • The messages of toplevel/error, toplevel/missing-concretization, and toplevel/concretization-timeout now start with a one-line summary, followed by a blank line and the details. Errors raised while loading code are summarized with the first line of the error message, e.g. JET could not execute this top-level code: UndefVarError: .... The details are wrapped at 90 columns, or at the terminal width in jetls check when the terminal is narrower.

  • Running tests with the TestRunner integration no longer runs the unselected tests nested in other code, such as in let blocks, or in files included outside the selected tests, e.g. by a top-level include("helpers.jl"). For example, running "b" in the following code no longer runs "a" or the tests in helpers.jl, while setup() and the definitions in helpers.jl still run:

    include("helpers.jl")
    
    let x = setup()
        @testset "a" begin
            @test f(x) == 1
        end
    end
    
    @testset "b" begin
        @test g() == 2
    end

    See Test selection for what runs along with the selected tests.

  • Completion of global names now also offers the names defined in open files, including unsaved edits, so definitions you have just written can be completed before full analysis loads them on save. For files without full analysis, it now offers the global names the file itself defines in addition to the names of the fallback context.

  • textDocument/completion and completionItem/resolve requests now stop partway when the client cancels them, e.g. when the editor requests completions again while you keep typing, or when VSCode moves the focus to another completion item before the details of the previous one are resolved.

Fixed

  • Fixed files with syntax warnings but no syntax errors getting no lowering/* diagnostics in the editor or from jetls check, and not being reanalyzed by full analysis on save.

  • Fixed toplevel/abstract-field being reported on functions containing closures that capture a @nospecialized argument, such as f(@nospecialize x) = () -> x.

  • Fixed toplevel/abstract-field and toplevel/method-overwrite never being reported by jetls check, and not being reported in the editor for files that are not open, such as files included by a package.

  • Fixed running tests with the TestRunner integration in files that call include with mapexpr, e.g. Base.include(mapexpr, mod, path), failing with an unreachable error or running the included file without applying mapexpr.

  • Fixed running a test set nested in other test sets with the TestRunner integration skipping the code in the enclosing test sets that it doesn't use directly, such as include calls or settings of environment variables, which could cause errors such as UndefVarError or test failures. For example, running "b" in the following code skipped the include call and the ENV setting, so helper() was not defined and run_mode() did not see the setting:

    @testset "outer" begin
        include("helpers.jl")  # defines `helper`
        ENV["MODE"] = "fast"   # read by `run_mode`
        @testset "b" begin
            @test helper() == 1
            @test run_mode() == "fast"
        end
    end

    That code now always runs, as described in Test selection.

  • Fixed @test_throws, @test_broken, @test_skip, @test_logs, @test_warn, @test_nowarn and @test_deprecated written at the top level always running with the TestRunner integration, even when they were not selected.

  • Fixed saving a file not updating diagnostics from full analysis in editors that do not include the document text in save notifications.

  • Fixed a string at the end of a notebook cell being treated as the docstring of the first expression in the next cell.

  • Fixed full analysis aborting with an internal error, and reporting no diagnostics for the file, when a docstring is attached to an expression that cannot be documented, such as an if block. Such code is now reported as a toplevel/error with the error Julia raises, cannot document the following expression.

  • Fixed files under a package's src/ and test/ directories being analyzed on their own as scripts when another file in the same package environment, such as a script at the package root or a file under docs/, had been analyzed first. They are now analyzed through src/<name>.jl and test/runtests.jl, as described in How each file is analyzed.

  • Fixed JETLS/save diagnostics not being shown until the next save when opening a file that full analysis has already analyzed, such as another file of an analyzed package or a file reopened after closing it, with diagnostic.all_files disabled on clients that set the pull_diagnostics initialization option, such as the VSCode extension.

2026-10-04

  • Commit: 3efdc63
  • Diff: 5ed21cb...3efdc63
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-10-04")'

Changed

Fixed

  • Fixed a crash that could occur when hover documentation, diagnostics, or error messages were rendered concurrently on Julia versions without the upstream display fix.

  • Fixed JETLS/live diagnostics lagging one edit behind while typing on clients that set the pull_diagnostics initialization option, such as the VSCode extension: diagnostics shown after an edit now reflect that edit instead of the text before it.

  • Fixed memory usage growing each time type inlay hints are computed, e.g. while editing a file with the hints shown. The memory retained after full-analysis is also reduced (related: aviatesk/JETLS.jl#357).

  • Fixed toplevel/method-overwrite diagnostics for method definitions whose body only returns a constant, such as f() = 1, being placed at an invalid location instead of the definition line.

2026-09-27

  • Commit: 5ed21cb
  • Diff: 906d919...5ed21cb
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-09-27")'

Added

  • Added the testrunner.env and testrunner.julia_args configurations for the Julia process that runs tests. testrunner.env sets its environment variables, where JULIA_APPS_JULIA_CMD or JULIAUP_CHANNEL runs tests with a Julia other than the one running JETLS:
    [testrunner]
    env = { JULIAUP_CHANNEL = "1.12" }
    julia_args = ["--threads=4"]

Changed

  • The TestRunner integration now uses the TestRunner.jl bundled with JETLS, so the testrunner executable no longer needs to be installed. Tests run with the Julia running JETLS by default, and the new testrunner.env configuration allows running them with another Julia via JULIAUP_CHANNEL or JULIA_APPS_JULIA_CMD. If you installed testrunner only for JETLS, you can uninstall it with pkg> app rm TestRunner.

  • The testrunner.executable configuration is deprecated and no longer has any effect.

  • Bumped JuliaSyntax and JuliaLowering revisions (c941fbc399), bringing several upstream JuliaLowering bug fixes (JuliaLang/julia#63006, JuliaLang/julia#63009).

Fixed

  • Fixed global function definitions such as global f() = ... and global function f() end, including those inside let/for/while blocks, not appearing in the document outline and workspace symbol search. For example, sayhi in the following code is now listed:
    let
        sentence = "Hi"
        global sayhi() = println(sentence)
    end
    Method definitions like Base.show(io::IO, x::Foo) = ... inside these blocks are now listed as well.

2026-09-25

  • Commit: 906d919
  • Diff: 685e812...906d919
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-09-25")'

Fixed

  • Fixed spurious inference/type-error/non-bool-cond and inference/method-error diagnostics caused by values without type annotations possibly being missing, such as if x == :flag or if x in (:a, :b) for an untyped argument x. Code whose types involve Missing, like xs[i] == 0 for xs::Vector{Union{Missing,Int}}, is still checked.

  • Fixed spurious inference/method-error diagnostics in numerical code using complex, such as complex(x[1], x[2]) / 2 for a x::StridedVector.

  • Fixed spurious inference/bounds-error diagnostics for ntuple calls with an unknown length. For example, the following function no longer reports a spurious bounds error at index 5:

    prefix(t::NTuple{4,Float64}, n::Int) = 1 ≤ n ≤ 4 && ntuple(i -> t[i], n)
  • Improved analysis accuracy for code that uses Libdl.dlsym.

  • Improved analysis accuracy for code that uses all or any on vectors whose element types are not precisely known, when SparseArrays is loaded.

2026-09-23

  • Commit: 685e812
  • Diff: 71fb0bf...685e812
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-09-23")'

Changed

  • JETLS/live diagnostics of the file being edited are now republished as soon as typing pauses, even in large workspaces, instead of waiting until diagnostics of the whole workspace have been recomputed.

  • Clients that opt into initialization_options.pull_diagnostics (such as the VSCode extension) are now asked to re-pull less often: once per batch of file changes on disk (e.g. after git checkout) instead of once per file.

Fixed

  • Fixed occasional segmentation faults of the language server, most likely to occur while JETLS/live diagnostics were being updated after edits. These were caused by a Julia codegen bug (JuliaLang/julia#63320), which JETLS now works around.

  • Fixed JETLS/live diagnostics of notebooks on clients that do not set the pull_diagnostics initialization option: false lowering/undef-local-var and lowering/ambiguous-soft-scope diagnostics for code relying on soft scope, e.g. x = 0; for i in 1:3; x += i; end, are no longer reported in notebook cells in such clients, and diagnostics of a deleted cell or of a cell turned into a markdown cell are now cleared.

  • Fixed false lowering/unused-local diagnostics for @testset loop variables used only in the description, e.g. i in @testset "case $i" for i in 1:3. Identifiers in @testset descriptions, options, and testset types are now analyzed like other code.

  • Fixed missing lowering/unused-local reports for unused variables of outer iteration specifications in for loops with multiple iteration specifications, e.g. i in for i in xs, j in ys; println(j); end.

2026-09-22

  • Commit: 71fb0bf
  • Diff: 2b51ac0...71fb0bf
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-09-22")'

Added

  • Added toplevel/concretization-timeout diagnostics when concrete execution of a top-level statement exceeds its time limit during full analysis, including a stack trace when available. The limit defaults to 10 seconds and can be adjusted with full_analysis.concretization_timeout, or disabled with "inf". Checks cover recursively interpreted callees, but cannot interrupt native calls, including those in pattern-selected blocks and package source analysis.

  • Added live Pkg output to progress messages for environment instantiation triggered by full_analysis.auto_instantiate, showing the latest activity while resolving and installing dependencies.

Changed

  • jetls check now defaults to --show-severity=info, hiding hint diagnostics. With default diagnostic severities, this hides:

    The display threshold remains independent of --exit-severity, and the summary includes counts of hidden diagnostics by severity.

    The output also suggests how to display hidden diagnostics and ends with a pass/fail result based on --exit-severity.

  • The jetls check GitHub Action now uses Julia 1.13 by default instead of 1.12. Set julia-version: "1.12" if you want to keep analyzing your package against Julia 1.12.

  • JETLS/live diagnostics are now pushed via textDocument/publishDiagnostics for open and unopened files alike; JETLS no longer offers workspace/diagnostic, and offers textDocument/diagnostic only to clients that set the new pull_diagnostics initialization option (as the jetls-vscode extension does). Open files are republished as you edit, tagged with the document version, and unopened files as soon as their diagnostics may have changed (full-analysis resolving module contexts, edits in the same analysis unit, watched-file or configuration changes, opening or closing a file). Every client sees the same diagnostics for open and closed files, and clients without pull diagnostics support now get JETLS/live diagnostics too.

  • JETLS no longer spends CPU while idle on workspace diagnostics. Clients used to poll workspace/diagnostic at a fixed interval, and each poll rescanned the workspace even when nothing had changed; the live diagnostics worker now wakes up only for events that can change the diagnostics and stays asleep otherwise.

  • JETLS/live diagnostics are now refreshed as soon as full-analysis has resolved module contexts, before signature analysis finishes, instead of after the whole analysis completes.

Fixed

  • Fixed intermittent missing or incorrect completion suggestions and signature help after edits, including macro completions triggered by @ and requests in notebook cells.

  • Fixed spurious inference/field-error diagnostics on parametric type definitions with inner constructors in script analysis mode.

  • Fixed false lowering/macro-expansion-error diagnostics for @static conditions containing anonymous functions on Julia 1.12 and 1.13.

  • Fixed toplevel/missing-concretization diagnostics for ordinary global assignments inside conditional branches in script analysis (aviatesk/JET.jl#866).

  • Fixed a WARNING: Detected access to binding ... in a world prior to its definition world message that full analysis could print when analyzing calls with keyword arguments, e.g. during jetls check.

  • Fixed JETLS/live diagnostics that depend on the module context, such as lowering/undef-global-var, not appearing for a freshly opened standalone file until it was edited: the refresh after full-analysis resolved the context was answered as unchanged.

  • Fixed stale diagnostics not being cleared when a file is closed with diagnostic.all_files=false.

  • Fixed a race in pull diagnostics (textDocument/diagnostic) where an edit arriving while a request was being handled could leave diagnostics computed from the previous document contents displayed until the next edit.

  • Fixed a race during background analysis that could cause diagnostics and other language features to use outdated document contents after an edit.

  • Fixed errors logged when in-flight requests or progress notifications finished during language server shutdown.

  • Fixed requests for LSP requests the server does not support being left unanswered; they now receive a MethodNotFound error response.

  • Fixed the macro expansion and type annotation code views in notebook cells, which previously failed with a Source document is not available message and, in any code cell but the first, were offered for the wrong top-level form.

  • Fixed diagnostics of a notebook being reported on the .ipynb file itself, at line numbers of the concatenated cells, when the notebook was closed while its analysis was still running.

2026-09-06

  • Commit: 2b51ac0
  • Diff: 9cebe8b...2b51ac0
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-09-06")'

Added

Changed

  • full_analysis.auto_instantiate no longer runs Pkg.resolve() and Pkg.instantiate() on environments that are already instantiated with an up-to-date manifest. JETLS now inspects the environment first and leaves it untouched when its manifest is up to date and nothing is missing, so opening a project whose Manifest.toml was written by a different Julia version no longer rewrites it just to update the recorded julia_version. Pkg.resolve() is run only when the manifest is missing or out of date; otherwise only Pkg.instantiate() runs.

  • full_analysis.auto_instantiate is now a string option taking "always", "prompt", or "never", and its default changed from true to "prompt". With "prompt", JETLS asks for confirmation via window/showMessageRequest before running Pkg.resolve() and Pkg.instantiate() on an environment that needs it, once per environment per server session. Alternatively, the environment can be instantiated manually while the prompt is open; after the operation finishes, choosing "Skip" makes JETLS recheck and use the updated environment without running Pkg itself. Choosing "Skip" while the environment is still incomplete analyzes the code with it as is. "always" restores the previous behavior of instantiating without asking, and "never" only warns. jetls check is unaffected: it has no client to ask, so "prompt" instantiates like "always" there, as the CLI already did before. For backward compatibility, the legacy values true and false are still accepted at runtime as aliases of "always" and "never". Configuration schemas intentionally reject these legacy boolean values to prompt migration to the string form.

Fixed

  • Fixed the "environment has not been instantiated" warning shown when full_analysis.auto_instantiate is disabled not appearing for environments without a Manifest.toml. The warning now also covers environments whose manifest is out of date with respect to Project.toml.

  • jetls check now prints the messages that the language server would show in an editor (e.g. the warning about an uninstantiated environment, or configuration problems) to stderr as log messages instead of silently dropping them. --quiet suppresses the info and warning ones, as it does for other log messages.

2026-09-01

  • Commit: 9cebe8b
  • Diff: 8dab3d9...9cebe8b
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-09-01")'

Changed

  • inference/method-error now distinguishes ambiguous calls from calls with no matching method, lists the conflicting or closest candidate methods, and suggests a disambiguating signature when possible.

  • inference/method-error no longer reports a redundant Core.kwcall method error when the unsupported keyword argument diagnostic already explains the failure.

  • inference/field-error now reports field accesses whose receiver may be a type without the field: x.regex where x::Union{Nothing,Regex} reports a FieldError for the Nothing case, and accesses on fieldless receivers like x.foo where x::Nothing are reported as well.

  • Updated JuliaSyntax.jl and JuliaLowering.jl revisions, bringing in JuliaLowering bugfixes for various lowering edge cases found in real-world packages (JuliaLang/julia#62862).

2026-08-29

  • Commit: 8dab3d9
  • Diff: 1b45195...8dab3d9
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-08-29")'

2026-08-28

  • Commit: 1b45195
  • Diff: 26d6318...1b45195
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-08-28")'

Added

  • Added --pipe=<path> as an alias for jetls serve --pipe-connect=<path>, following the flag convention of VSCode's LSP client.

2026-08-23

  • Commit: 26d6318
  • Diff: 29f138d...26d6318
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-08-23")'

Changed

  • JETLS now displays a warning when workspace analysis and folder-local configuration are unavailable because a server was started without a workspace folder, with an unsupported root URI scheme, or with multiple workspace folders. For multi-root workspaces, configure the editor to start one server per top-level folder.

  • The jetls version command now starts faster even when precompile workloads are disabled.

  • The jetls version output now uses the lowercase jetls version ..., julia version ... format, consistent with other Julia apps such as runic and juliac. (aviatesk/JETLS.jl#830)

2026-08-07

  • Commit: 29f138d
  • Diff: 6dacc52...29f138d
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-08-07")'

Added

  • Added a dedicated toplevel/missing-concretization diagnostic for top-level bindings whose concrete values JET needs during full analysis. Users can configure now full_analysis.concretization_patterns through .JETLSConfig.toml or LSP settings to evaluate selected top-level assignments in workspace files. The diagnostic offers a quick fix that creates or updates .JETLSConfig.toml with a pattern scoped to the assignment file, and JETLS automatically reanalyzes affected analysis units after the setting changes. (Closed aviatesk/JETLS.jl#464)

  • Added the experimental reuse_native_inference initialization option (disabled by default): when enabled, calls to methods defined outside the modules being analyzed reuse results from Julia's native inference cache instead of being analyzed recursively:

    # .JETLSConfig.toml example
    [initialization_options]
    reuse_native_inference = true

    This can substantially speed up full analysis of packages with large dependencies, provided those dependencies are precompiled, since the analysis then reuses the inference results cached in their precompiled images. Packages whose analysis time is dominated by their own code see little change. Note that analysis results may change slightly with this option, which can change the diagnostics that are reported.

Changed

  • Full analysis is now substantially faster for test files with many standard Test macros such as @test and @testset, while still analyzing the expressions inside them (aviatesk/JET.jl#856).

  • Text and notebook document synchronization now use dynamic registration when supported, allowing regular text synchronization to be scoped to supported Julia buffers and server-provided virtual documents. Static fallbacks remain available for other clients.

Fixed

  • Fixed type inlay hints for typed vector literals with splatted values, which now show the constructed vector type instead of an unrelated union containing tuple types.

  • Fixed type inlay hints for matrix and multidimensional array literals, which now show the constructed array type without annotations for internal row dimensions. (Closed aviatesk/JETLS.jl#841)

  • Fixed the TestRunner integration treating failed or errored tests as an unexpected TestRunner execution failure instead of reporting their results.

  • Fixed watched-file registration for clients that do not support relative glob patterns, while keeping handled file events scoped to the workspace root.

2026-08-05

  • Commit: 6dacc52
  • Diff: b74025b...6dacc52
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-08-05")'

Fixed

  • Fixed crashes and incorrect synchronization state when language clients send text-document notifications for unsupported files, such as unrelated TOML files.

  • Fixed delays when clients send textDocument/* requests for unsupported files. Such requests now return promptly once JETLS determines that the document is not supported for synchronization.

  • Hover and completion no longer append Base's auto-generated type summary for global bindings, matching how local bindings have always been rendered.

  • Fixed hover for script globals whose values full-analysis only tracks abstractly: hover no longer leaks the internal JET.AbstractBindingState placeholder and now shows the analyzed binding type (e.g. release_commit :: String) and any attached docstring.

  • Fixed the same placeholder leaking into resolved completion items for such globals: completion documentation, kind, and detail now reflect the analyzed binding. Signature help, goto-definition, and dot-prefix completion also resolve these bindings now.

2026-08-02

  • Commit: b74025b
  • Diff: f64faec...b74025b
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-08-02")'

Changed

  • Function-definition hover now shows return types inferred from declared signature types alongside the source signature. For example, hovering over pair in:
    function pair(x::Int, y::AbstractString)
        return x => y
    end
    shows:
    pair(x::Int, y::AbstractString) :: Pair{Int64, <:AbstractString}

Fixed

  • Fixed diagnostic path patterns and analysis_overrides on Windows, allowing forward-slash glob patterns to match files under the workspace root.

  • Fixed LaTeX/emoji completion in clients such as Zed and Helix whose completion filtering cannot handle the \/^/: characters: e.g. Unicode superscript completion like \^a now works (Closed aviatesk/JETLS.jl#821).

  • Fixed Go to Definition jumping to stale line positions when unsaved edits move method definitions in synchronized documents.

2026-08-01

  • Commit: f64faec
  • Diff: 0d67c12...f64faec
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-08-01")'

Breaking

  • Removed the experimental n_analysis_workers initialization option. Full-analysis requests are now processed serially, while signature analysis within each request remains parallel based on the available Julia threads. Existing client or .JETLSConfig.toml configurations must remove this option.

  • inference/non-boolean-cond is now reported as inference/type-error/non-bool-cond. Existing diagnostic pattern configurations that match the old code continue to apply for now, but this compatibility support may be removed in a future release.

Added

  • Added Julia 1.13 compatibility, allowing JETLS to run on Julia 1.13 runtimes. JETLS selects pinned Compiler.jl sources for the active Julia runtime while retaining Julia 1.12 support.

  • Added the inference/type-error/type-assert diagnostic for type assertions that inference can prove will fail:

    let x = rand()
        x::Int  # TypeError: expected Int64, got Float64 (JETLS inference/type-error/type-assert)
    end
  • Added detection of unsupported keyword arguments: a call that passes a keyword argument the called method does not accept is now reported under the inference/method-error diagnostic:

    kwfunc(; kw1=nothing) = kw1
    kwfunc(; kw3=42)  # unsupported keyword argument `kw3` (JETLS inference/method-error)
  • Added the inference/undef-keyword diagnostic: a call that omits a required keyword argument (one declared without a default), which raises UndefKeywordError at runtime, is now reported:

    required_keyword(pos; key) = (pos, key)
    required_keyword(42)  # missing keyword argument `key` (JETLS inference/undef-keyword)
  • Added the inference/type-error/keyword diagnostic: a call that passes a keyword argument whose value type does not match the keyword's declared type, which raises TypeError at runtime, is now reported:

    typed_keyword(; key::Int=0) = key
    typed_keyword(; key=1.0)  # TypeError: expected `Int64`, got `Float64` (JETLS inference/type-error/keyword)

Changed

  • Updated JuliaSyntax.jl and JuliaLowering.jl revisions, incorporating JuliaLowering's new standard-tree SyntaxTree representation (JuliaLang/julia#62474), which makes lowering — the backbone of most lowering-based LSP features — several times faster and reduces its memory footprint.

  • Improved startup latency by precompiling the initialize request round-trip, so the first request is less likely to hit strict client initialize timeouts (such as Helix's 20-second default). On slower machines, raising the client-side timeout may still be needed. (xref: aviatesk/JETLS.jl#784)

  • Updated Compiler.jl API compatibility for the incoming Julia 1.12.7 release while retaining support for Julia pre-1.12.6 Compiler.jl APIs.

  • JETLS servers started without a workspace root (i.e., when an LSP InitializeRequest specifies neither workspaceFolders nor rootUri) now analyze opened Julia files as standalone scripts instead of discovering nearby project environments. This avoids automatic environment setup and package-wide analysis in rootless LSP sessions.

  • inference/* diagnostic related information now labels inference frames as origin, via, or entry, making it clearer where the error originated and which analysis entry reported it.

  • inference/type-error/* now groups diagnostics for the subset of runtime TypeError cases that JETLS can infer, including non-Bool conditions and statically failing type assertions. Users can ignore or reconfigure this family together with a regex code match such as inference/type-error/.*.

  • Reworked the diagnostics documentation: a new Analysis stages section explains what produces each diagnostic category, which tool powers it, when it runs, and how the stages depend on one another. It also adds a security caveat that full analysis loads and runs your code (so JETLS should not be run on untrusted code), and documents how each inference/* diagnostic corresponds to the Julia runtime error it predicts.

Fixed

  • Fixed false lowering/macro-expansion-error diagnostics when an old-style macro is nested inside a new-style macro. The failed expansion could also contaminate enclosing forms and produce repeated lowering diagnostics across a project, as reported for Makie. This incorporates JuliaLang/julia#62221 and addresses JuliaLang/JuliaLowering.jl#108. (Closed aviatesk/JETLS.jl#554)

  • Fixed missing or incorrect references, rename edits, document highlights, and diagnostics around qualified or aliased macros such as Test.@test; unrelated user-defined macros with the same name are no longer mistaken for built-in macros.

  • Fixed many missing references, rename edits, document highlights, and lowering/unused-import diagnostic results for identifiers inside quoted expressions used by helper functions, macros, and generated functions.

  • Fixed a false lowering/error diagnostic for docstring signatures such as someinterface(::Type{<:Integer}).

  • Fixed a false lowering/unused-import report for a name used only inside a @static condition or a branch not selected by the JETLS analysis process:

    using Base: VERSION
    @static if VERSION ≥ v"1.12"
        # `VERSION` is no longer misreported as an unused import
    end
  • Fixed a false lowering/unused-import report for names imported only to extend methods without qualification:

    import Base: show  # no longer reported as an unused import
    struct A; x::Int; end
    show(io::IO, a::A) = print(io, "A with ", a.x)
  • Document-highlight and rename now also cover identifiers used in @static branches not selected by the JETLS analysis process.

  • Fixed false lowering/unused-local, lowering/unused-argument, and lowering/unused-assignment reports for a binding whose only use is in a @static branch not selected by the JETLS analysis process.

  • Fixed inference/field-error diagnostics for direct transparent custom getproperty implementations that forward to getfield(o, s), so missing-property errors point at the user's property access instead of the forwarding implementation as the primary diagnostic location. (Closed aviatesk/JETLS.jl#469)

  • Fixed missing diagnostics, references, rename, and document-highlight support for identifiers interpolated into lazy"..." strings.

  • Fixed textDocument/references with includeDeclaration=false incorrectly including a struct definition as a reference.

  • Fixed references, definition lookup, document highlights, and rename not recognizing struct inner constructor names as definitions of the struct binding.

  • Fixed generated helpers and temporary bindings in new-style @something, lazy"...", and @assert expansions resolving in the caller's scope, where shadowing could change macro behavior or capture user variables.

  • Fixed @static conditions generated by another new-style macro resolving names in the generating macro's module instead of the caller's module.

  • Fixed @static false && expr and @static true || expr expanding to nothing instead of false and true, respectively.

  • Fixed document formatting and TestRunner execution hanging on large documents or test output. TestRunner cancellation now also waits for the child process to stop cleanly, and formatter and TestRunner failures include process exit details in the server log.

2026-06-26

  • Commit: 0d67c12
  • Diff: 35c3262...0d67c12
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-06-26")'

Changed

  • Updated JuliaSyntax.jl, JuliaLowering.jl, JET.jl and JuliaInterpreter.jl revisions, bringing in several lowering fixes and fixes for world-age-related analysis errors.

Fixed

  • Fixed toplevel/error diagnostics reporting method too new to be called from this world context when analyzing top-level @eval loops that generate methods. (Closed aviatesk/JETLS.jl#341)

  • Fixed hover on symbol literals such as :foo to show the literal expression (:foo :: Symbol) instead of the bare name with internal Core.Const details.

  • Fixed stale methods from previous script or notebook analyses lingering after re-analysis or occasionally triggering Method ... already disabled cleanup errors.

  • Fixed property completion (obj.) returning no suggestions in some contexts where the incomplete dot-access prevented type inference, such as inside try/catch blocks or on the right-hand side of an assignment (out = obj.).

2026-06-23

  • Commit: 35c3262
  • Diff: d15f92f...35c3262
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-06-23")'

Fixed

  • Fixed spurious Any type annotations caused by free static parameters left inside inferred method argument types, such as Vector{T} in f(a::Vector{T}) where {T}. (Closed aviatesk/JETLS.jl#768)

  • Fixed type annotation for script-mode files so inferred const globals use their actual type instead of an internal JET.AbstractBindingState, avoiding spurious annotations.

2026-06-20

  • Commit: d15f92f
  • Diff: 5643648...d15f92f
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-06-20")'

Fixed

  • Fixed false "not concretized" toplevel/error diagnostics on top-level for loops over const globals when the loop body contains a comprehension. (Fixed aviatesk/JETLS.jl#555 via aviatesk/JET.jl#830)

  • Fixed type annotation for nested local closures that capture values already captured by an enclosing closure.

  • Fixed type annotation results for methods whose signature contains static parameters such as f(a::Vector{T}) where {T} so reachable calls like copy(a) no longer collapse to Union{}. (Closed aviatesk/JETLS.jl#764)

  • Fixed the names introduced by import/using/export/public statements nested in a block (e.g. version-gated imports) not being recognized by document highlight, find references, rename, and semantic tokens.

2026-06-18

  • Commit: 5643648
  • Diff: a42a435...5643648
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-06-18")'

Added

  • Added type inlay hints showing inferred types next to expressions (bindings, calls, function return types, branch results, etc.) so types are visible inline without hovering. Method bodies are inferred against their declared signature, and top-level chunks (e.g. standalone let blocks) are inferred independently. Hints are enabled by default; [inlay_hint.types] enabled toggles them. See the Type hints page for examples.
Inlay type hint demo
  • Added a macro expansion view that shows expanded macro code in a read-only document — served through the LSP 3.18 workspace/textDocumentContent request, or a temporary-file fallback for clients without that capability. It is triggered through code actions: one expands the macro call under the cursor, and one recursively expands every macro in the enclosing top-level form. See the Macro expansion code view page for details.

  • Added a type annotation view that shows a top-level form with its inferred types applied as explicit ::T annotations in a read-only document — served through the LSP 3.18 workspace/textDocumentContent request, or a temporary-file fallback for clients without that capability. It is triggered through a code action on the enclosing top-level form. See the Type annotation code view page for details.

  • Added lowering/inactive-code diagnostic that marks @static branches not taken in the current environment (e.g. a Windows-only branch when analyzing on macOS) at Hint severity with the Unnecessary tag, so editors gray out code that is excluded from analysis.

  • Added lowering/unconstrained-static-parameter diagnostic that warns when a method declares a static parameter that does not appear in the type of any function parameter, so its value cannot be deduced when the method is called. This matches the warning Julia itself emits when evaluating such a method definition. For example:

    f(::T) where {T,S} = S  # Method definition declares type variable `S` but does not use it in the type of any function parameter
                            # (JETLS lowering/unconstrained-static-parameter)
  • Added support for the LSP 3.18 textDocument/rangesFormatting request so clients that advertise textDocument.rangeFormatting.rangesSupport can format multiple ranges in a single request.

Changed

  • Improved type precision for local closures with untyped parameters (do x, x -> ...): their parameter types are now inferred from the argument types observed at the closure's call sites instead of degrading to Any, so hover, inlay hints and other type-aware features show precise types in closure bodies, in comprehensions, and for results of higher-order calls like map. Parameter annotations other than ::Any are always respected as-is.

  • Added hover and inlay hints for unannotated parameters of local closures, showing the parameter types inferred from the closure's call sites (e.g. map(xs) do x::Int for xs::Vector{Int}, or f = x::Union{Float64, Int} -> 2x when f is called with both Float64 and Int). This covers all local-closure forms — arrow and do-block lambdas, anonymous and named local closures. Destructuring parameters are annotated per component (e.g. do (key::String, val::Int)), consistent with for-loop iteration variables. Parameters whose type cannot be narrowed beyond Any are left without a hint.

  • Hover headers now include inferred lattice details as a Julia comment when the displayed type hides more precise information.

  • JETLS now performs correct scope resolution on identifiers used inside @static macrocalls, which previously could yield incorrect results in edge cases. Invalid @static usage (an unsupported expression shape, or a condition that fails to evaluate to a Bool) is now reported in place as lowering/macro-expansion-error while the code still flows through to analysis.

  • The "JuliaFormatter" preset now supports textDocument/rangeFormatting and textDocument/rangesFormatting, which previously failed with a "JuliaFormatter does not support range formatting" error. This requires JuliaFormatter v2.7.0 or later. See the formatter integration docs for setup.

  • Allows scope resolution for identifiers inside @lock blocks so language features distinguish bindings introduced in the protected body from surrounding bindings.

  • Signature help now uses LSP 3.18 activeParameter: null for clients that support it, so editors can avoid highlighting a stale parameter after all known keywords have already been filled.

  • Changed TestRunner log viewing to use readonly virtual documents when supported, and cleanup-enabled temporary files otherwise, avoiding empty untitled: log tabs and mismatched log file paths.

Fixed

  • Fixed language feature registrations so JETLS only targets supported Julia documents — saved files (file:), unsaved buffers (untitled: and buffer:), and notebook cells — while still keeping virtual documents from unsupported schemes (e.g. jetls:) from triggering diagnostics, code actions, and other file-backed features.

  • Fixed language feature requests for unsupported document URIs (e.g. virtual documents, or any request from clients that ignore the registered document selectors) blocking for up to 10 seconds before returning an empty result; such requests now return immediately.

  • Fixed diagnostic.patterns order handling so declaration order is preserved after configuration merging. When multiple matching rules have the same priority, later rules now override earlier rules.

  • Fixed type information collapsing to Any inside closures defined in functions that have default positional arguments or keyword arguments. Hover, inlay hints and other type-aware features now show precise types for such closure bodies and their captured variables.

  • Fixed renaming symbols inside Jupyter notebook cells on VS Code, which previously failed with a "The rename edit returned from the server is not valid anymore and cannot be applied." error.

  • Fixed dot completion erroring (or offering nothing) when the prefix sits in code that inference proves unreachable, such as code after a non-returning call. Module and global-const prefixes such as Base. now resolve their members there as usual.

  • Fixed hover on unannotated local closure parameters showing Core.OpaqueClosure internals instead of the inferred argument type.

  • Fixed hover and other type-aware features inside local closure bodies losing constant-propagated details for captured values.

  • Fixed false positive lowering/undef-local-var diagnostics for variables guarded by negated @isdefined conditions, including && and || combinations where definedness is guaranteed.

  • Fixed false positive lowering/unused-assignment diagnostics on phantom struct type parameters such as struct MyVal{T} end.

2026-06-03

  • Commit: a42a435
  • Diff: 0b038c7...a42a435
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-06-03")'

Removed

  • Removed the legacy inlay_hint.block_end_min_lines configuration alias. Use inlay_hint.block_end.min_lines instead.

  • Removed support for the legacy completion.method_signature.prepend_inference_result configuration key. Inferred return types are now always shown in completion details and method signature documentation.

Changed

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest.

  • Improved responsiveness for repeated requests against the same document version. After an edit, follow-up LSP features such as diagnostics, document highlights, code actions, hover, definition etc. now reuse the current file's prepared syntax tree instead of rebuilding it for each request.

  • Improved performance of type-aware features on open files. Repeated hover, definition, declaration and type definition requests in the same top-level expression can now reuse prior analysis results instead of rerunning inference each time.

  • Improved unused-variable diagnostic message for assignments returned from tail position. For both lowering/unused-local and lowering/unused-assignment, JETLS now explains when Julia is implicitly returning the assignment expression's value, suggests return name when the binding itself should be returned, and offers an "Insert explicit return" quick fix for simple tail assignments. (Closed aviatesk/JETLS.jl#723)

Fixed

  • Fixed false lowering/unused-argument reports — and missed argument occurrences for find-references / document-highlight / rename — on @generated functions nested inside another construct (e.g. as an inner constructor in a struct body). (Closed aviatesk/JETLS.jl#722)

2026-05-27

  • Commit: 0b038c7
  • Diff: 72cc49c...0b038c7
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-05-27")'

Added

  • Added support for "Go to Type Definition" (textDocument/typeDefinition). Invoking it on an expression jumps to the definition of its inferred type — e.g. landing on a binding of type Foo jumps to the struct Foo definition. For Union types the response includes one location per constituent. (aviatesk/JETLS.jl#686)
type definition demo
  • Added property completion (x.│ / x.partial│). Typing . after a typed expression now offers the properties that propertynames(::T) reports for the dot prefix's inferred type — both plain struct fields and types with a custom propertynames overload are handled uniformly. Each candidate's inferred property type (x.field :: T) is resolved lazily, only when the client requests details for a focused item. The resolved documentation also includes the per-field docstring attached to that field in its struct definition, when present. For union-typed prefixes the offered names are the union of each component's propertynames, so the common Union{T, Nothing} pattern still surfaces T's properties even though propertynames(::Nothing) == (); type details merge each component's per-property type at resolve time.

Changed

  • textDocument/hover now surfaces inferred types alongside documentation. Any identifier, dot expression, call result, or indexing position can be queried — func(x) :: Int, s[2] :: Float64, Base.Pair :: typeof(Pair), etc. — and the type is queried at the cursor's byte range so flow-sensitive type narrowing is reflected. Binding hovers additionally carry a kind tag — (argument), (local), (static parameter), or (global) — before the name, making the binding's role in scope visible. Closures display as function-arrow signatures like (x::Int, y::Int) -> Int, with argument names recovered from the body when available. Documentation is gathered both from the binding's own docstring and from the docstring of whatever value the expression resolves to via type inference. So e.g. given sv = Some(sin), hovering on sv.value shows sin's docstring even though sin doesn't appear at the cursor. For dot expressions whose LHS is a struct instance (x.y│), the per-field docstring attached to y in its struct definition is also surfaced when present. When the cursor is on the callee identifier (e.g. sin│(rand(Int)), Base.Math.sin│(x)), the header is promoted to the full call expression (sin(rand(Int)) :: Float64) and the docstring is narrowed to the dispatched method's doc when dispatch resolves to a single method (sin(::Real)). When the cursor sits past a call-like surface's closing punctuation (f(args)│, xs[i]│, [a, b]│, …), only the expr :: T header is shown without any docstring body. Non-call cursors (f│) still show every overload's doc. (aviatesk/JETLS.jl#687)

    Hover on call<img width="1086" height="418" alt="Hover on call demo" src="https://github.com/user-attachments/assets/cf3d2eb8-3036-44e2-b075-b3c9ca09dc35" />
    Hover on closure<img width="1086" height="418" alt="Hover on closure demo" src="https://github.com/user-attachments/assets/285de208-a704-4978-9a89-829654f561bc" />
  • textDocument/definition on a call site (f(arg)│ or f│(arg)) now narrows to the method dispatch picked for the inferred argument types — e.g. sin│(42) jumps to sin(::Real) only, not to every method of sin. Bare cursors on the function name (sin│) still return all definitions.

  • textDocument/signatureHelp and method-signature completion (textDocument/completion) now narrow overloads using the inferred type of each argument at the call site, including arbitrary local-scope expressions. Previously only top-level globals and literal arguments contributed to filtering, so let x = rand(); sin(x,│); end showed every sin method; with the local x :: Float64 now folded in, only sin(::T) where T<:Union{Float32, Float64} is offered.

  • textDocument/semanticTokens now classifies type parameters declared in struct / abstract type / primitive type headers (and their use sites inside the type body) as typeParameter. Previously these identifiers were classified as plain variable.

  • lowering/undef-global-var now suppresses reports as soon as a sibling file in the same analysis unit defines the referenced name. Previously, adding foo = ... to one file left foo references in other files of the same unit flagged as undefined until the next full-analysis cycle (typically triggered on save) caught up.

  • lowering/macro-expansion-error no longer aborts analysis of the enclosing top-level form. Any misuse JETLS's stubs for Base macros detect — invalid threadpool literal in Threads.@spawn, duplicate kwarg in @info/@warn/…, @test with skip + broken, wrong argument count in @assert/@invoke/@kwdef/@assume_effects/…, non-call shape passed to @invoke, malformed @testset body, and so on — is now reported in place while the macrocall body still flows through to scope and type analysis. Previously any of these would propagate a MacroExpansionError, remove the entire macrocall from analysis, and take every other LSP feature requiring full lowering of the enclosing function (hover, inlay, signature help, undef-var, references, …) down with it. Reports come with Error severity when Base would reject the misuse and Warning severity when Base accepts it silently or only deprecates.

  • Documenter admonitions (!!! note, !!! tip, !!! warning, !!! danger, !!! info, !!! compat) in docstrings now render as Markdown blockquotes with a category-emoji header (e.g. > **💡 Tip**) wherever JETLS surfaces docstrings (hover, completion documentation, signature help). Previously the !!! block leaked through verbatim, leaving the editor's Markdown view to render it in unintended ways.

  • Hover and method-signature completion documentation no longer surface Base's "No documentation found for ..." placeholder paragraph for bindings that exist but carry no docstring. The auto-generated method / type summary that follows the placeholder is still shown, so the hover stays informative without the placeholder noise.

Fixed

  • Fixed spurious diagnostics like $`{ }` outside of `where` is reserved for future use$ falsely appearing on Jupyter notebook (.ipynb) files in VS Code. (Fixed aviatesk/JETLS.jl#703)

  • Fixed jetls check failing with "could not find any files to analyze" on Windows when the current working directory's drive letter casing differed from the URI-normalized form (Closed aviatesk/JETLS.jl#679).

  • jetls check no longer rejects files outside the current working directory. Previously, paths such as jetls check ../foo.jl were classified as out-of-scope by the LSP-style workspace boundary guard and produced "could not find any files to analyze". The CLI now analyzes any file passed on the command line regardless of where it lives relative to the cwd.

  • jetls check now reports parse errors. Previously, files with syntax errors (e.g. an unclosed parenthesis like f(x) = println(x) silently produced "No diagnostics found".

  • Fixed spurious WARNING: Detected access to binding ... in a world prior to its definition world messages emitted by jetls check and other server analyses.

  • Identifiers interpolated into docstrings (e.g. $(TYPEDEF) / $(TYPEDSIGNATURES) from DocStringExtensions.jl) are now treated as real references during scope resolution. As a result, lowering/unused-import no longer falsely reports imports that are only used through docstring interpolations, and lowering/undef-global-var flags interpolations of names that aren't actually in scope. Other LSP features (hover, go-to-definition, find-references, …) also work on identifiers inside docstring interpolations. (Fixed aviatesk/JETLS.jl#699)

  • Identifiers inside keyword arguments of @test, @test_broken, and @test_skip (e.g. flag in @test x broken=flag) are now picked up by scope resolution, so undef-var diagnostics and find-references work for them. Previously the keyword arguments were dropped during macro expansion.

  • Identifiers inside @show, @debug, @info, @warn, @error, and @logmsg calls — including kwarg values (e.g. flag in @info "msg" extra=flag) and splatted operands (e.g. kws in @info "msg" kws...) — are now picked up by scope resolution, so undef-var diagnostics and find-references work for them. Previously the identifiers in these macros were silently ignored. For the logging macros, duplicate kwarg names also surface as lowering/macro-expansion-error anchored at the call site.

  • Fixed completion items to honor the client's completionItem.resolveSupport.properties capability. Previously, properties such as kind and labelDetails were updated during completionItem/resolve regardless of whether the client advertised lazy support for them, which caused visible glitches in some clients (e.g. flickering completion lists in cmp-nvim-lsp). (Closed aviatesk/JETLS.jl#711)

2026-05-08

  • Commit: 72cc49c
  • Diff: 732c537...72cc49c
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-05-08")'

Fixed

  • JETLS now performs correct scope resolution on identifiers used inside Test.jl macro calls (i.e., @testset, @test, @test_throws, @test_broken, @test_skip, @test_warn, @test_nowarn, @test_logs, @test_deprecated, and @inferred), which previously could yield incorrect results in edge cases.

  • Fixed pull-model diagnostics (textDocument/diagnostic and workspace/diagnostic) to refresh after [diagnostic] configuration changes. Previously, changing settings such as diagnostic.enabled, diagnostic.allow_unused_underscore, or diagnostic.patterns did not invalidate the client's cached results, so stale diagnostics remained until the file was edited.

Changed

  • Configuration parse errors now point at the offending key with its full dotted path, e.g. Invalid value at `diagnostic.allow_unused_underscore`: expected Bool, got String for type mismatches and Configuration file at … contains an unknown key: \`diagnostic.unknown_field\` for unrecognized keys. Previously these messages either omitted the location entirely or referenced only the immediate key.

  • Dropped the dependency on Configurations.jl. Configuration parsing and validation are now handled in-tree, so JETLS pulls in fewer transitive packages on first install and load.

2026-05-06

  • Commit: 732c537
  • Diff: 563fd7e...732c537
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-05-06")'

Changed

  • Block-end inlay hints now display as #= … =# block comments (e.g. end #= module Foo =#), so what's shown matches the text inserted when the hint is applied.

  • textDocument/diagnostic now returns an unchanged report when neither the document nor its analysis-unit siblings have changed since the previous pull, skipping diagnostic recomputation. This reduces redundant work on clients that aggressively re-pull diagnostics across all open files on each edit (e.g., Zed).

  • Test runner code lens / code action now runs against the current editor buffer rather than the saved file. JETLS pipes the live buffer to the testrunner subprocess over stdin, so unsaved edits (including brand-new @testset / @test cases) execute as-is and the previous "Save the file first to run tests" error no longer occurs. The integration also works for buffers (untitled: for VSCode / buffer: for Sublime Text) that have never been saved to disk: relative include calls in the buffer resolve from the workspace root. This requires upgrading the testrunner CLI to a version that understands the --read-stdin flag. Reinstall the latest release with:

    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/TestRunner.jl", rev="release")'

    and confirm the upgrade by running testrunner --help and checking that --read-stdin appears under Options:.

Fixed

  • lowering/unused-assignment no longer flags an assignment in a try (or catch) body as dead when the assigned variable is read in the enclosing finally, even if the assignment is followed by return. The finally block runs before the return takes effect, so the value is live.

    function f()
        local x::Float64
        try
            y = sin(rand((rand(), Inf)))
            x = y               # previously: dead store
            return 0
        catch
            x = 0.0             # previously: dead store
            return 1
        finally
            push!(xs, x)
        end
    end
  • lowering/unused-assignment no longer flags intermediate assignments in a try body when a later statement might throw. Common state-tracking idioms like the following now keep state = "step1 starting" and state = "step2 starting" live with respect to log(state):

    function process()
        state = "init"
        try
            state = "step1 starting"  # previously: dead store
            step1()
            state = "step2 starting"  # previously: dead store
            step2()
            state = "done"
        finally
            log(state)
        end
    end

2026-05-05

  • Commit: 563fd7e
  • Diff: 28972ef...563fd7e
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-05-05")'

Added

  • Added textDocument/semanticTokens support. JETLS now emits parameter, typeParameter, and variable token types (with declaration / definition modifiers) so that themes can distinguish function arguments, type parameters, and local variables from generic identifiers. Global identifiers are also reported under a custom jetls.unspecified token type, which leaves the editor's syntactic color intact while still letting themes apply modifier styling to declaration/definition sites. Both full and range requests are supported. Because JETLS only emits identifier classifications and relies on the editor's syntactic highlighter for everything else, semantic tokens are only registered when the client advertises augmentsSyntaxTokens = true. See https://aviatesk.github.io/JETLS.jl/release/features/#features/semantic-tokens for details.
semantic tokens demo

Changed

  • Significantly reduced latency on large files across most LSP features (hover, completion, diagnostics, inlay hint, code lens, …). For example, code lens generation on a file with 1000 @testset blocks dropped from ~590ms to ~1.4ms.

Fixed

  • Fixed textDocument/inlayHint for notebook cells, which previously misplaced hints (or rendered none at all) by treating the requested viewport and emitted hint positions as notebook-global coordinates rather than cell-local.

2026-05-02

  • Commit: 28972ef
  • Diff: e784de8...28972ef
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-05-02")'

Added

  • lowering/error now reports @goto references that don't resolve to any @label in the same function body. For example:

    function f()
        @goto nonexist  # label `nonexist` referenced but not defined (JETLS lowering/error)
        println("foo")
    end
  • Added the lowering/unused-label diagnostic, reported when a @label is declared but never referenced by any @goto in the same function body. The label is marked with the Unnecessary tag, so editors typically display it as faded/grayed out. A "Remove unused label" code action is also offered to drop the entire @label statement. For example:

    function f()
        @label spare  # Unused label `spare` (JETLS lowering/unused-label)
        return 1
    end

Changed

  • The reference count code lens is no longer shown for inner constructors of a struct.

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest, improving the performance of lowering-based LSP features (JuliaLang/julia#61597).

Fixed

  • lowering/unreachable-code now uses control-flow reachability instead of syntactic block-walking, fixing several false positives and missed cases:

    • Code reachable via @goto nested inside an expression (e.g. return cnd ? @goto(fallback) : println("Return"); @label fallback; ...) is no longer reported as unreachable.
    • Code after try ... finally ... end whose try body always terminates is now correctly flagged as unreachable.
  • Fixed lowering/captured-box related-information ("Captured by closure") highlighting the entire enclosing macrocall (e.g. a whole @testset begin ... end block) instead of the captured identifier when the captured reference lived inside a macro expansion.

  • Fixed an "Unsupported URI" error that could occur when an unsaved (untitled:) buffer was edited and then closed in quick succession. Closing an unsaved buffer now also clears any analysis state associated with it, so previously analyzed top-level overloads no longer linger as ghost entries in completions or signature help.

  • Fixed textDocument/documentHighlight, textDoscument/references, and textDocument/rename incorrectly treating same-named local arguments in disjoint scopes (e.g. two separate do h ... end blocks within the same let or function body) as the same binding.

  • Fixed unused positional arguments with a default value (e.g. bar in function f(x, bar="bar")) being incorrectly treated as keyword arguments, suppressing the "Prefix with '_' to indicate intentionally unused" code action and skipping the unused-argument warning when the default's type annotation referenced a where-clause static parameter.

2026-04-28

  • Commit: e784de8
  • Diff: d1ebbb2...e784de8
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-04-28")'

Breaking

  • Clients that previously handled the JETLS-defined jetls.showReferences command should switch to handling editor.action.showReferences instead. The new arguments are [uriString, position, locations], where locations is the pre-resolved LSP Location[], so clients no longer need to issue a textDocument/references request themselves. See the Neovim setup section for an example handler.

Added

  • Added a Features overview page to the documentation, providing a visual showcase of every LSP feature JETLS provides.

  • Added textDocument/declaration ("go to declaration"). It jumps to the import site on an imported name (e.g. using Base: sin) and to the local line on a local declaration. When the symbol has no dedicated declaration site, the request falls back to the same logic as textDocument/definition.

  • Added textDocument/documentLink support for include("path") and include_dependency("path") calls. The path string becomes a clickable link that opens the referenced file. Only non-interpolated string arguments whose path resolves to an existing file (relative to the current file's directory) are surfaced.

Changed

  • The reference-count code lens now emits editor.action.showReferences (a VSCode convention command) directly, instead of the JETLS-defined jetls.showReferences. Editors that follow the VSCode convention (e.g. Zed) now dispatch the lens out of the box; editors that do not (e.g. Neovim) need to register a client-side handler.

  • When a reference-count code lens is clicked on a file whose full analysis has not yet run, a warning notification (via window/showMessage) is now shown instead of an empty references peek.

  • The reference-count code lens is no longer shown on closures and inner functions defined inside another function body (e.g. f = x -> ..., nested functions).

  • Diagnostic messages are now sent as MarkupContent when the client advertises the textDocument.diagnostic.markupMessageSupport capability (LSP 3.18), so Markdown formatting such as inline code renders properly in supporting clients (e.g. recent Sublime LSP). (aviatesk/JETLS.jl#633)

Fixed

  • Fixed textDocument/references so that includeDeclaration=false now correctly excludes method definitions and declarations of the target binding. As a side benefit, the reference-count code lens now reports accurate counts.

  • Fixed the reference-count code lens, textDocument/references, textDocument/documentHighlight, and textDocument/rename silently dropping results after a full analysis completes.

  • Names listed in export and public statements are now treated as references to the surrounding module's global bindings, so textDocument/documentHighlight, textDocument/references, textDocument/definition, and textDocument/rename all work when the cursor is placed on an exported/public name.

  • Locally-introduced names from import/using statements are now treated as local declarations. This covers every binding form, including using A / import A, using A, B, dotted paths (using A.B), relative paths (using .Inner), and explicit names (using A: x, y / using A: x as y).

  • textDocument/rename on imported names now preserves the source-module name by introducing or updating an as alias. For example, renaming sin in using Base: sin produces using Base: sin as newsin plus newsin at use sites. Renaming an alias back to its source name drops the as … suffix. In forms where Julia does not accept as (using M, using M, N, using M.Sub), rename falls back to a bare replacement.

  • Fixed textDocument/references, textDocument/documentHighlight, textDocument/definition, textDocument/declaration, and textDocument/rename silently returning no results inside top-level definitions that combine a compound-assignment operator with a macro call (e.g. x += @elapsed foo()).

  • By providing new-style macro definitions for JuliaLowering, LSP features (textDocument/references, textDocument/rename, textDocument/documentHighlight, textDocument/definition, textDocument/declaration) and diagnostics (lowering/undef-global-var, lowering/unused-assignment) now perform correct scope resolution on identifiers used inside @__FUNCTION__, @ccall, @cfunction, @goto, @isdefined, @locals, @label, and Threads.@spawn macrocalls, which previously could yield incorrect results in edge cases.

  • Fixed false-positive lowering/unused-assignment reports for the assign-then-@goto-to-@label pattern, where the goto edge from @goto done to @label done was not modeled in the CFG so assignments before the @goto were incorrectly treated as overwritten by assignments after the @label. For example:

    function f(cond)
        local reports
        if cond
            reports = compute_cached()
            @goto done
        end
        reports = compute_default()
        @label done
        use(reports)
    end
  • Fixed lowering/unused-import going stale in workspace/diagnostic when an explicit import in one file is consumed (or stops being consumed) by a sibling file in the same analysis unit. Closed files now refresh the diagnostic when a sibling edit could affect it.

  • Fixed textDocument/documentSymbol and the reference-count code lens on the Jupyter notebook view in VSCode.

2026-04-14

  • Commit: d1ebbb2
  • Diff: c954d83...d1ebbb2
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-04-14")'

Added

  • Added inference/non-boolean-cond diagnostic that detects non-boolean values used in boolean context (e.g. if, while, ternary ?:, &&, ||).
    function find_zero(xs::Vector{Union{Missing,Int}})
        for i in eachindex(xs)
            xs[i] == 0 && return i  # non-boolean `Missing` found in boolean context
        end
    end

Changed

  • The release script now sets Project.toml version to YYYY.MM.DD (converted from the YYYY-MM-DD release date), so pkg> app status displays a meaningful version (aviatesk/JETLS.jl#629).

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependencies.

Fixed

  • Unreachable code after assignment with noreturn RHS (e.g. y = error(x)) is now correctly detected.

  • Fixed errors when opening unsaved buffers in Sublime Text, which uses the buffer: URI scheme instead of VSCode's untitled: scheme convention (aviatesk/JETLS.jl#626).

  • Fixed false "macro name not found" diagnostics on macros like @enumx that internally generate baremodules (Closed aviatesk/JETLS.jl#628).

2026-04-06

  • Commit: c954d83
  • Diff: 8deefa8...c954d83
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-04-06")'

Added

  • Extended noreturn optimization to recognize error, rethrow, and exit in addition to throw. These calls are now treated as block terminators for unreachable code detection and undef variable analysis, reducing false positives when these functions are used as guards. For example, the following code no longer produces a false "possibly undefined" warning on y:

    function f(x)
        if x > 0
            y = x
        else
            error("x must be positive")
        end
        return sin(y)  # no warning: error() guarantees y is defined
    end
  • Noreturn detection now works for nested calls (e.g. println(error(x))) where a noreturn function appears in argument position.

Changed

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest.

Fixed

  • Fixed scope resolution for notebook cells to use soft scope semantics, so that assignments inside loops correctly resolve to existing globals instead of creating ambiguous locals.

  • Fixed a crash during signature analysis (AssertionError: invalid cache_argtypes) that occurred when constant propagation encountered methods using @nospecializeinfer with varying varargs arities. Updated the bundled Compiler.jl revision with the upstream fix (https://github.com/JuliaLang/julia#61502) (Closed aviatesk/JETLS.jl#618).

2026-04-04

  • Commit: 8deefa8
  • Diff: d14efce...8deefa8
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-04-04")'

Added

  • Added lowering/unreachable-code diagnostic that detects code after block terminators (return, throw, break, continue), including cases where all branches of if/elseif/else or try/catch contain a terminator. Unreachable code is displayed as faded/grayed out with the Unnecessary tag. A "Delete unreachable code" quick fix code action is also available.

  • Added lowering/ambiguous-soft-scope diagnostic that warns when a variable assignment inside a for/while/try block at the top level shadows an existing global variable. This matches the warning Julia itself emits at runtime for this pattern. Two code actions are offered: "Insert global declaration" (preferred) and "Insert local declaration". This diagnostic is suppressed for notebook cells, where soft scope semantics are enabled.

Changed

  • lowering/undef-local-var now recognizes correlated conditions to reduce false positives. When a variable is assigned under a condition (e.g. if x; y = 42; end) and later used under the same condition (if x; println(y); end), the diagnostic is no longer emitted. This also works with && chains (if x && z), nested if blocks that are equivalent to &&, and combinations of both.

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest. The updated JuliaLowering pipeline is faster overall (JuliaLang/julia#61425), improving performance of LSP features that rely on lowering such as diagnostics and document highlight.

  • The JETLS's own def-use analysis (analyze_def_use_all_lambdas) is now ~5x faster (684ms → 127ms). Combined with the JuliaSyntax/JuliaLowering pipeline improvements above, the overall analysis pipeline time is reduced by ~2x (3649ms → 1772ms) on a large file (test/test_lowering_diagnostic.jl, ~1600 lines) (aviatesk/JETLS.jl#612).

  • The "Prefix with _" code action is no longer offered for unused keyword arguments, since renaming a keyword argument changes the function's calling convention.

Fixed

  • Fixed world age warnings (WARNING: Detected access to binding 'xxx' in a world prior to its definition world. ...) that could occur when the language server interacts with user-defined methods or types at a newer world age. This affected diagnostic printing, documentation lookup (hover, completions), and signature help display. (Closed aviatesk/JETLS.jl#485)

  • Fixed full analysis not working on unsaved (untitled:) buffers. Unlike saved files where analysis runs on save, unsaved buffers trigger analysis on each content change with a fixed 3-second debounce.

  • Fixed lowering-based LSP features (document highlight, go-to-definition, find references, rename, hover) not working for functions with docstrings.

  • Fixed go-to-definition, find references, rename, and code actions not working correctly in notebooks.

2026-03-20

  • Commit: d14efce
  • Diff: ea73622...d14efce
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-03-20")'

Added

  • Added process title setting so that jetls serve processes are distinguishable in ps/htop when multiple projects are open. The title includes JETLS version, workspace path, transport mode, and client process ID.

Fixed

  • Fixed false positive lowering/unused-assignment diagnostic for variables reassigned inside while loops with break/continue.

2026-03-19

  • Commit: ea73622
  • Diff: 4280097...ea73622
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-03-19")'

Added

  • Added @main function support across LSP features (document-symbol, document-highlight, references, rename, completions, diagnostic).

  • Added lowering/unused-assignment diagnostic that detects assignments whose values are never read (dead stores). This complements the existing lowering/unused-local diagnostic: lowering/unused-local reports variables that are never used at all, while lowering/unused-assignment reports specific assignments to variables that are used elsewhere. For example:

    function f(x::Bool)
        if x
            z = "Hi"
            println(z)  # z is used, so no `unused-local`
        end
        if x
            z = "Hey"   # but this value is never read → `unused-assignment`
        end
    end

Changed

  • lowering/undef-local-var now reports a diagnostic for each use site on an undef path individually, rather than only reporting the first one.
  • lowering/undef-local-var @isdefined propagation now recognizes @isdefined(var) within && chains (e.g., if cond && @isdefined(y)), suppressing false positive diagnostics in the guarded branch.
  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest

Fixed

  • Fixed false positive lowering/unused-binding warning for keyword arguments that are only used in computing other keyword arguments' default values (Closed aviatesk/JETLS.jl#592).
  • Fixed false positive lowering/unused-import warning for imports used inside quoted expressions in macro bodies or helper functions (Closed aviatesk/JETLS.jl#594).
  • Fixed lowering/undef-local-var diagnostic being reported at the wrong location: when a variable had both defined and potentially-undefined uses, the diagnostic pointed to the first use in source order rather than the use that is actually on the undef path.
  • Fixed signature-help error when displaying signatures for operator-like methods (e.g. Base.:(==)).
  • Fixed "Delete assignment" code action removing the opening delimiter of string literals (e.g., z = "Hey" became Hey" instead of "Hey").

2026-03-13

  • Commit: 4280097
  • Diff: d32f1cf...4280097
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-03-13")'

Changed

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest

Fixed

  • Fixed crash in diagnostics when @generated functions use old-style macros (Closed aviatesk/JETLS.jl#583).

  • Fixed false "Invalid type signature for @kwdef" error when using @kwdef with subtype declarations (e.g. @kwdef struct A <: B) (Closed aviatesk/JETLS.jl#587).

  • Fixed false unused-import warnings for modules with docstrings (Closed aviatesk/JETLS.jl#586).

  • Fixed server hang when the client terminates abnormaly without sending an exit notification (e.g. Neovim) (Fixed aviatesk/JETLS.jl#580).

2026-03-08

  • Commit: d32f1cf
  • Diff: 5e1f0bb...d32f1cf
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-03-08")'

Changed

Fixed

  • Fixed highlight range in jetls check (aviatesk/JETLS.jl#574).
  • Fixed false "unused argument" warnings for @generated functions. Arguments used inside quoted expressions (:(...)) are now correctly recognized. Document highlight, find references, and rename also work for these arguments (Closed aviatesk/JETLS.jl#480).

2026-02-27

  • Commit: 5e1f0bb
  • Diff: ebcbd60...5e1f0bb
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-02-27")'

Added

  • Added a GitHub composite action (.github/actions/check/) for running jetls check in CI pipelines. External packages can use it as:
    - uses: aviatesk/JETLS.jl/.github/actions/check@release
      with:
        files: src/SomePkg.jl
    All jetls check command-line options are available as action inputs.

Changes

  • The previously deprecated behavior of running jetls without a subcommand to start the language server has been removed. Running jetls without a subcommand or with unrecognized arguments now shows the help message and exits. Use jetls serve instead (Closed aviatesk/JETLS.jl#565).

2026-02-26

  • Commit: ebcbd60
  • Diff: e141508...ebcbd60
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-02-26")'

Added

  • Added inference/method-error diagnostic that detects function calls where no matching method exists for the inferred argument types. This catches potential MethodErrors that would occur at runtime. For union-split calls, the diagnostic reports only the failing branches with their count (e.g., "1/2 union split").

  • Added jetls schema CLI command that prints the JSON Schema for JETLS configuration. Supports --settings, --init-options, and --config-toml options.

  • Added schema generation infrastructure under scripts/schema/ and committed generated schema files under schemas/. CI now checks that the schema files and jetls-client/package.json stay in sync with src/types.jl.

Changed

  • textDocument/documentSymbol now shows for, let, while, and try/catch/else/finally blocks inside functions as hierarchical Namespace symbols. Previously, all local bindings within a function were shown as flat children; now, bindings inside scope constructs are nested under the scope construct, matching the existing behavior for top-level scope constructs.

  • textDocument/documentSymbol now strips redundant name prefixes from symbol details. (e.g., a symbol named foo with detail foo = func(args...) now shows = func(args...) as the detail.

Fixed

  • Fixed textDocument/rename for macro bindings.

  • Fixed bindings in let/for/while blocks inside nested functions not appearing as children of those functions in the document outline.

2026-02-16

  • Commit: e141508
  • Diff: 150f880...e141508
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-02-16")'

Added

  • Anonymous function assignments (f = (x) -> x + 1 and clos = function (y) ... end) are now analyzed as Function symbols for textDocument/documentSymbol, with their arguments as children.

Changed

  • Enabled signature analysis for all analysis modes. Previously, signature analysis was only active in the package source analysis, meaning some potential errors within standalone scripts can be missed. This change ensures that diagnostics like inference/field-error can be detected from methods within standalone scripts. (Fixed aviatesk/JETLS.jl#479).

Fixed

  • Fixed jetls check failing to correctly activate user package environments during full analysis.

  • Fixed jetls check resolving file path arguments relative to the current working directory instead of the --root directory when --root is specified. For example, jetls check --root=/path/to/Pkg src/Pkg.jl now correctly resolves to /path/to/Pkg/src/Pkg.jl.

  • Fixed false positive lowering/unused-import diagnostics for symbols in a package file but used in included files (Fixed aviatesk/JETLS.jl#547).

  • Fixed rename/document-highlight/references failing for @kwdef structs with default values (Fixed aviatesk/JETLS.jl#540).

  • Fixed duplicate syntax error diagnostics by skipping ParseErrorReport from full-analysis, since syntax errors are already reported via textDocument/diagnostic or workspace/diagnostic (Fixed aviatesk/JETLS.jl#535).

  • Fixed false positive unused argument diagnostic for keyword arguments whose type annotation constrains a where-clause static parameter that is used in the function body (e.g., f(; dtype::Type{T}=Float32) where {T} = T.(xs)) (Fixed aviatesk/JETLS.jl#481).

  • Fixed various type instabilities across the codebase caught by the new inference/method-error diagnostic running on JETLS itself.

Other

  • Added GitHub issue templates for bug reports and feature requests.

2026-02-11

  • Commit: 150f880
  • Diff: 9c00dfe...150f880
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-02-11")'

Added

  • Added jetls check command for running JETLS diagnostics from the command line. This enables CI integration and command-line workflows without requiring an editor. Features include --exit-severity for controlling exit codes, --show-severity for filtering output, --context-lines for output formatting, and --root for configuration lookup. The CLI now uses a subcommand structure: jetls serve starts the language server (default), while jetls check runs diagnostics.

  • Added lowering/unused-import diagnostic that reports explicitly imported names that are never used within the same module space. The "Remove unused import" code action removes the unused name from the import statement.

  • Added reference count code lens for top-level symbols (functions, structs, constants, abstract types, primitive types, modules). When enabled, a code lens showing "N references" appears above each symbol definition. Clicking it opens the references panel. This feature is opt-in and can be enabled via code_lens.references configuration.

  • Added code_lens.testrunner configuration option to enable or disable TestRunner code lenses. Some editors (e.g., Zed) display code lenses as code actions, causing duplication. The aviatesk/zed-julia extension automatically defaults this to false.

  • Added document symbol support for if and @static if blocks. These blocks now appear in the document outline as SymbolKind.Namespace symbols, with all definitions from if/elseif/else branches flattened as children.

  • Added document symbol support for @testset and @test macros. @testset blocks appear in the document outline with the test name, and @test expressions appear as children showing the test expression.

  • Added inlay hints for block end keywords. For long blocks (module, function, macro, struct, if/@static if, let, for, while, @testset), an inlay hint is displayed at the end keyword showing what construct is ending, such as module Foo or function bar. The minimum block length can be configured via inlay_hint.block_end_min_lines (default: 25 lines).

Deprecated

  • Running jetls without a subcommand (e.g., jetls --stdio) is deprecated. Use jetls serve instead. The support for jetls without a subcommand will be removed in a future release.

Changed

  • Namespace symbols (if/let/for/while/@static if blocks) are now excluded from workspace symbol search. These symbols exist only to provide hierarchical structure in the document outline, not to represent actual definitions.

  • textDocument/diagnostic now supports cancellation, avoiding to compute staled diagnostics (aviatesk/JETLS.jl#524)

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest, fixing the root causes of aviatesk/JETLS.jl#492, and aviatesk/JETLS.jl#508.

Fixed

  • Lowering diagnostics no longer report issues in macro-generated code that users cannot control. User-written identifiers processed by new-style macros are still reported, but old-style macros are not yet supported due to JuliaLowering limitations.

  • Fixed false positive lowering/unused-argument and lowering/unused-local diagnostics that could appear before full-analysis completes when macros cannot be expanded. Fixed aviatesk/JETLS.jl#522.

  • Fixed diagnostic configuration pattern merging to use composite keys. Previously, patterns with the same pattern value but different path would overwrite each other. Now patterns are identified by (match_by, match_type, path, pattern), allowing multiple rules for the same pattern with different paths.

  • Fixed potential segfault on server exit by implementing graceful shutdown of worker tasks. All Threads.@spawned tasks are now properly terminated before the server exits. (xref: JuliaLang/julia#32983, aviatesk/JETLS.jl#523)

  • Fixed thread-safety issue with cached syntax trees. Multiple threads accessing the same cached tree during lowering could cause data races and segfaults. Cached trees are now copied before use. (aviatesk/JETLS.jl#525)

  • Fixed cache not being generated in some cases in the experimental incremental analysis mode. The cache is now always created when CodeInstance is available, ensuring cache reuse works reliably.

  • Fixed auto-instantiate creating unwanted versioned manifest files (e.g., Manifest-v1.12.toml) via touch. A manifest is now only created when Pkg.instantiate() needs one. (aviatesk/JETLS.jl#511, aviatesk/JETLS.jl#536; thanks visr)

2026-01-23

  • Commit: 9c00dfe
  • Diff: c8e2012...9c00dfe
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-23")'

Added

  • Added workspace/diagnostic support to provide JETLS/live diagnostics (syntax errors and lowering-based analysis) for unopened files in the workspace.

  • Added diagnostic.all_files configuration option to control whether diagnostics are reported for unopened files. Disabling this can be useful to reduce noise when there are many warnings across the workspace.

  • Added lowering/unsorted-import-names diagnostic that reports when names in import, using, export, or public statements are not sorted alphabetically. The "Sort import names" code action is available to automatically fix the ordering.

  • textDocument/documentHighlight now supports macro bindings. Highlighting a macro name (either in the definition or at a call site) shows all occurrences of that macro within the document.

  • textDocument/references now supports macro bindings. Finding references on a macro name (either in the definition or at a call site) shows all occurrences of that macro across the package.

Changed

  • Updated TestRunner.jl installation instructions to use the #release branch for vendored dependencies. TestRunner.jl should now be installed via

    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/TestRunner.jl", rev="release")'

    (aviatesk/TestRunner.jl#14).

  • Replaced inference/undef-local-var with new lowering/undef-local-var diagnostic. The new diagnostic uses CFG-aware analysis on lowered code, providing faster feedback via textDocument/diagnostic without waiting for full analysis, and offers precise source location information. See the diagnostic reference for details and workarounds.

  • textDocument/documentSymbol now uses SymbolKind.Object for function arguments instead of SymbolKind.Variable. This visually distinguishes arguments from local variables in the document outline. Since LSP does not provide a dedicated SymbolKind.Argument, Object is used as a workaround.

  • workspace/symbol now shows the parent function signature or struct name as the container name for arguments or fields respectively, making it clearer which function or struct they belong to during workspace symbol search.

  • Diagnostic source field now uses distinct values to indicate which channel delivers the diagnostic: JETLS/live for on-change diagnostics, JETLS/save for on-save full analysis, and JETLS/extra for external sources like the TestRunner.jl integration. This helps users understand when diagnostics update and enables filtering by source in editors that support it. See the Sources documentation for details.

  • Yet more improved performance of workspace/symbol, textDocument/references,

textDocument/rename, and textDocument/definition by avoiding re-parsing of already analyzed files not opened in the editor.

  • workspace/configuration requests now expect settings to be found under the top-level "jetls" key, such that a request with section = "jetls" produces the full configuration. This is to ensure compatibility with generic clients, e.g., the neovim client, which may not conform to JETLS's previous expectations about how requests with no section are handled. (aviatesk/JETLS.jl#483; thanks danielwe)

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest.

Fixed

  • Fixed LSP features not working inside @main functions.

  • Fixed false positive lowering/captured-boxed-variable diagnostic when a struct's inner constructor defines a local variable with the same name as a type parameter (e.g., struct Foo{T} with T = typeof(x) in the constructor). (aviatesk/JETLS.jl#508)

  • Fixed severe performance issue when analyzing test files containing many @test and @testset macros. The underlying JuliaLowering issue caused macro expansion to be 40-300x slower for test files compared to regular source files. (JuliaLang/julia#60756)

2026-01-17

  • Commit: c8e2012
  • Diff: 4cf9994...c8e2012
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-17")'

Added

  • textDocument/definition now supports global bindings. Previously, go-to-definition for global variables couldn't find their definition sites since runtime reflection doesn't provide binding location information. Now it uses binding occurrence analysis to find definition sites across the package, benefiting from the binding occurrences cache.

Changed

  • Improved workspace/symbol performance by enabling document symbol caching for files not currently open in the editor. Previously, only synced files (opened in editor) used the cache, causing repeated parsing for every workspace symbol search. The cache is now invalidated via workspace/didChangeWatchedFiles when unsynced files change on disk.

  • Improved textDocument/references, textDocument/rename, and textDocument/documentHighlight performance for global bindings by caching binding occurrence analysis results per top-level expression. The cache persists across requests within the same package, so consecutive find-references, rename, or document highlight operations avoid redundant lowering.

2026-01-15

  • Commit: 4cf9994
  • Diff: 54b3058...4cf9994
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-15")'

Added

  • Implemented textDocument/documentSymbol for structured outline view in editors. Provides hierarchical symbol information including modules, functions, structs, and local variables with rich detail context.
textDocument/documentSymbol
  • Implemented workspace/symbol for workspace-wide symbol search, allowing quickly jumping to any function, type, or variable across the workspace. Results include rich context like function signatures for easier identification.
workspace/symbol

Changed

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest.

2026-01-11

  • Commit: 54b3058
  • Diff: 8b3c9db...54b3058
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-11")'

Fixed

  • Fixed cancellation not working properly for formatting requests (Fixed aviatesk/JETLS.jl#465)

  • Fixed diagnostic relatedInformation range not being localized for notebook cells

2026-01-10

  • Commit: 8b3c9db
  • Diff: cbcdc3c...8b3c9db
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-10")'

Added

  • Added lowering/captured-boxed-variable diagnostic that reports variables captured by closures requiring boxing. E.g.:
    function abmult1(r::Int)  # `r` is captured and boxed (JETLS lowering/captured-boxed-variable)
        if r < 0
            r = -r
        end
        f = x -> x * r        # RelatedInformation: Closure at L5:9 captures `r`
        return f
    end
    (aviatesk/JETLS.jl#452)

Changed

  • Keyword argument name completion items are now sorted according to their order in the method definition.

Fixed

  • Fixed textDocument/diagnostic for notebook cells.

  • Fixed textDocument/formatting and textDocument/rangeFormatting for notebook cells (Fixed the first issue of aviatesk/JETLS.jl#442).

  • Return empty results instead of errors for LSP requests on documents that haven't been synchronized via textDocument/didOpen (Fixed the second issue of aviatesk/JETLS.jl#442).

  • Fixed lowering/undef-global-var diagnostic incorrectly reporting non-constant but defined symbols as undefined in the file-analysis mode.

  • Fixed cancellation not working for requests that use server-initiated progress (e.g., textDocument/formatting, textDocument/rename, textDocument/references). Previously, these requests were marked as handled immediately when the handler returned, causing $/cancelRequest to be ignored.

  • Fixed progress UI cancel button not being displayed for textDocument/formatting, textDocument/rangeFormatting, textDocument/references, and textDocument/rename requests. The server now properly handles both $/cancelRequest and window/workDoneProgress/cancel to abort these requests.

2026-01-09

  • Commit: cbcdc3c
  • Diff: 368e0a1...cbcdc3c
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-09")'

Fixed

  • Fixed lowering/undef-global-var diagnostic incorrectly reporting imported symbols from dependency packages as undefined. when !JETLS_DEV_MODE. (aviatesk/JETLS.jl#457)

  • Fixed false positive lowering/undef-global-var diagnostic for keyword slurp arguments with dependent defaults (e.g., f(; a=1, b=a, kws...)). (JuliaLang/julia#60600)

2026-01-08

  • Commit: 368e0a1
  • Diff: c5f3c0d...368e0a1
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-08")'

Added

  • Added lowering/undef-global-var diagnostic that reports undefined global variable references on document change (as you type). This provides faster feedback compared to inference/undef-global-var, which runs on save. The on-change diagnostic detects simple undefined references with accurate position information, while the on-save version detects a superset of undefined global binding references, including qualified references like Base.undefvar. (aviatesk/JETLS.jl#450)
  • Method signature completion for function calls. When typing inside a function call (triggered by (, ,, or ), compatible method signatures are suggested based on already-provided arguments. Selecting a completion inserts remaining positional arguments as snippet placeholders with type annotations. When you select a completion item in the list, additional details such as inferred return type and documentation are displayed (resolved lazily for performance). (aviatesk/JETLS.jl#428)
  • Keyword argument name completion for function calls. When typing inside a function call (e.g., func(; |) or func(k|)), available keyword arguments are suggested with = appended. Already-specified keywords are excluded from suggestions, and the spacing around = follows the existing style in the call. (aviatesk/JETLS.jl#427)
  • Added completion.latex_emoji.strip_prefix configuration option to control prefix stripping in LaTeX/emoji completions. Some editors (e.g., Zed) don't handle backslash characters in the LSP sortText field, causing incorrect completion order. Set to true to strip prefixes, false to keep them. If not set, JETLS auto-detects based on client. The auto-detection covers only a limited set of known clients, so users experiencing sorting issues should explicitly set this option.

  • Added completion.method_signature.prepend_inference_result configuration option to control whether to prepend inferred return type information to the documentation of method signature completion items. In some editors (e.g., Zed), additional information like inferred return type displayed when an item is selected may be cut off in the UI when method signature text is long. Set to true to show return type in documentation. If not set, JETLS auto-detects based on client. The auto-detection covers only a limited set of known clients, so users experiencing visibility issues should explicitly set this option.

Tip

Help improve auto-detection:

Some completion configuration options (e.g., completion.latex_emoji.strip_prefix, completion.method_signature.prepend_inference_result) use client-based auto-detection for default behavior. If explicitly setting these options clearly improves behavior for your client, consider submitting a PR to add your client to the auto-detection logic.

  • Added code actions to delete unused variable assignments. For unused local bindings like y = println(x), two new quick fix actions are now available:
    • "Delete assignment": removes y =, leaving just println(x)
    • "Delete statement": removes the entire assignment statement
    These actions are not shown for (named)tuple destructuring patterns like x, y, z = func() where deletion would change semantics.

Changed

  • Enhanced global completion items with detailed kind information ([function], [type], [module], etc.). When you select a completion item, these details are displayed (resolved lazily for performance). The visibility of these enhancements varies by client: VSCode updates only the CompletionItem.detail field (shown above documentation), while Zed is able to update all fields including CompletionItem.kind for richer presentation with label highlighting (combined with aviatesk/zed-julia#1). (aviatesk/JETLS.jl#425)

    Demo with aviatesk/zed-julia

  • Improved signature help filtering when a semicolon is present in function calls. Methods that require more positional arguments than provided are now filtered out once the user enters the keyword argument region (e.g., g(42;│) no longer shows g(x, y) which requires 2 positional arguments). (aviatesk/JETLS.jl#426)

  • Signature help and method completion now use type-based filtering. Method candidates are filtered based on the inferred types of already-provided arguments. For example, signature help and method completions triggered by typing sin(1,│ now shows only sin(::Real) instead of all sin methods. Global constants are also resolved (e.g., sin(gx,│) with const gx = 42 correctly infers Int). Note that local variable types are not yet resolved, (e.g., let x = 1; sin(x,│); end would still show all sin methods). (aviatesk/JETLS.jl#436)

  • Signature help now displays the inferred argument type for the active parameter. The parameter documentation shows the passed argument expression and its type (e.g., p ← (arg) :: Int64).

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependency versions to latest.

  • Updated Revise.jl dependency version to v3.13.

Fixed

  • Improved type resolver robustness, eliminating UndefVarError messages that could appear in server logs during signature help. Fixed aviatesk/JETLS.jl#391. (aviatesk/JETLS.jl#435)

  • Fixed signature help parameter highlighting when cursor is not inside any argument. For positional arguments exceeding the parameter count, the last (vararg) parameter is now highlighted (e.g. println(stdout,"foo","bar",│)). For keyword arguments after a semicolon, the next unspecified keyword parameter is highlighted (e.g., printstyled("foo"; bold=true,│) highlights italic).

2026-01-01

  • Commit: c5f3c0d
  • Diff: b61b6fa...c5f3c0d
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2026-01-01")'

Fixed

  • Fixed method overwrite detection to handle both Core.CodeInfo and Expr source types, making the analysis more robust. (aviatesk/JETLS.jl#421)
  • Fixed toplevel/abstract-field diagnostic to report correct field locations for structs with <: subtyping syntax and const field modifiers. (aviatesk/JETLS.jl#422)

2025-12-31

  • Commit: b61b6fa
  • Diff: afc5137...b61b6fa
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-31")'

Added

  • Added diagnostic.allow_unused_underscore configuration option (default: true). When enabled, unused variable diagnostics (lowering/unused-argument and lowering/unused-local) are suppressed for names starting with _. (aviatesk/JETLS.jl#415)
  • Added code action to prefix unused variables with _. When triggered on an unused variable diagnostic, this quickfix inserts _ at the beginning of the variable name to suppress the warning. (aviatesk/JETLS.jl#416)
  • Added warning diagnostic for method overwrites (toplevel/method-overwrite). When a method with the same signature is defined multiple times within a package, a warning is reported at the overwriting definition with a link to the original definition. Addresses aviatesk/JETLS.jl#387. (aviatesk/JETLS.jl#417)
toplevel/method-overwrite showcase
  • Added information diagnostic for abstract field types (toplevel/abstract-field). Reports when a struct field has an abstract type (e.g., Vector{Integer} or Pair{Int}), which often causes performance issues such as dynamic dispatch. (aviatesk/JETLS.jl#418, aviatesk/JETLS.jl#419)
toplevel/abstract-field showcase

Fixed

  • Added patch to vendored JuliaLowering to support @. macro expansion. This was addressed with a specific patch for the @. case, but many of these JuliaLowering macro compatibility issues are planned to be resolved generically in the future. Fixed aviatesk/JETLS.jl#409.

2025-12-19

  • Commit: afc5137
  • Diff: c9c5729...afc5137
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-19")'

Added

  • Added CHANGELOG page to the documentation.

Fixed

  • Fixed inference/undef-global-var diagnostic being unintentially reported for undefined global bindings in dependency packages.
  • Fixed syntax/lowering diagnostics not being refreshed when diagnostic configuration change via .JETLSConfig.toml or LSP configuration. The server now sends workspace/diagnostic/refresh request to prompt clients to re-pull diagnostics. Note that client support varies; e.g. VSCode refreshes textDocument/diagnostic in response, but Zed does not.

2025-12-18

  • Commit: c9c5729
  • Diff: 048d9a5...c9c5729
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-18")'

Added

  • Added inference/field-error diagnostic for detecting access to non-existent struct fields (e.g., x.propert when the field is property). Closed aviatesk/JETLS.jl#392.
  • Added inference/bounds-error diagnostic for detecting out-of-bounds field access by index (e.g., tpl[2] on a tpl::Tuple{Int}). Note that this diagnostic is for struct/tuple field access, not array indexing.
  • Added completion support for Julia keywords. Closed aviatesk/JETLS.jl#386.
  • Added hover documentation for Julia keywords.
  • Initialization options can now be configured via .JETLSConfig.toml using the [initialization_options] section. See the documentation for details.
  • Added file rename support. When renaming a string literal that refers to a valid file path (e.g., in include("foo.jl")), JETLS now renames both the file on disk and updates the string reference in the source code. Note that this feature only works when initiating rename from within the Julia source code; renaming files externally (e.g., via editor file explorer) will not automatically update code references.

Fixed

  • Small adjustments for using JETLS with Julia v1.12.3
  • Fixed false negative unused argument diagnostics for functions with keyword arguments. For example, func(a; kw=nothing) = kw now correctly reports a as unused. Fixed aviatesk/JETLS.jl#390.
  • Fixed stale diagnostics not being cleared when a file is closed or when test structure changes remove all diagnostics for a URI.
  • Fixed wrong message for diagnostic with multiple stack frames. The diagnostic message could be incorrectly overwritten when there are multiple stack frames, causing "message must be set" errors in VSCode. Fixed aviatesk/JETLS.jl#393.

Changed

  • Completions now return no results when the prefix type is unknown. Previously, irrelevant completions were shown for expressions like obj.x where obj's type could not be resolved. Fixed aviatesk/JETLS.jl#389.
  • Invalid initialization options are now reported to the user via editor notifications instead of only being logged to the server.

2025-12-12

  • Commit: 048d9a5
  • Diff: 9b39829...048d9a5
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-12")'

Added

  • Added textDocument/references support for bindings. Both local and global bindings are supported, although currently the support for global references is experimental and has some notable limitations:
    • References can only be found within the same analysis unit. For example, when finding references to somebinding defined in PkgA/src/somefile.jl, usages in PkgA/src/ can be found, but usages in PkgA/test/ cannot be detected because test files are in a separate analysis unit.
    • Aliasing is not considered. Usages via using ..PkgA: somebinding as otherbinding or module-qualified access like PkgA.somebinding are not detected.
  • Added textDocument/rename support for global bindings. Similar to global references, this feature is experimental and has the same limitations regarding analysis unit boundaries and aliasing.

Fixed

  • Fixed false positive unused variable diagnostics in comprehensions with filter conditions. For example, [x for (i, x) in enumerate(xs) if isodd(i)] no longer incorrectly reports i as unused. Fixes aviatesk/JETLS.jl#360.

Changed

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependencies to the latest development versions, which fixes spurious lowering diagnostics that occurred in edge cases such as JuliaLang/julia#60309.

2025-12-08

  • Commit: 9b39829
  • Diff: fd5f113...9b39829
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-08")'

Added

  • Jupyter notebook support: JETLS now provides language features for Julia code cells in Jupyter notebooks. As shown in the demo below, all code cells are analyzed together as a single source, as if the notebook were a single Julia script. JETLS is aware of all cells, so features like go-to-definition, completions, and diagnostics work across cells just as they would in a regular Julia script.

    JETLS × notebook LSP demo

Fixed

  • Fixed UndefVarError during full analysis by updating the vendored JuliaInterpreter.jl to v0.10.9.
  • Fixed source location links in hover content to use comma-delimited format (#L<line>,<character>) instead of #L<line>C<character>. The previous format was not correctly parsed by VS Code - the column position was ignored. The new format follows VS Code's implementation and works with other LSP clients like Sublime Text's LSP plugin. Fixes aviatesk/JETLS.jl#281.

2025-12-06

  • Commit: fd5f113
  • Diff: c23409d...fd5f113
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-06")'

Fixed

  • TestRunner code lenses and code actions now properly wait for file cache population before being computed.

Changed

  • Updated JuliaSyntax.jl and JuliaLowering to the latest development versions.

2025-12-05

  • Commit: c23409d
  • Diff: aae52f5...c23409d
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-05")'

Changed

  • diagnostic.patterns from LSP config and file config are now merged instead of file config completely overriding LSP config. For patterns with the same pattern value, file config wins. Patterns unique to either source are preserved.

Fixed

  • Request handlers now wait for file cache to be populated instead of immediately returning errors. This fixes "file cache not found" errors that occurred when requests arrived before the cache was ready, particularly after opening files. (aviatesk/JETLS.jl#273, aviatesk/JETLS.jl#274, aviatesk/JETLS.jl#327)
  • Fixed glob pattern matching for diagnostic.patterns[].path: ** now correctly matches zero or more directory levels (e.g., test/**/*.jl matches test/testfile.jl), and wildcards no longer match hidden files/directories. (aviatesk/JETLS.jl#359)
  • .JETLSConfig.toml is now only recognized at the workspace root. Previously, config files in subdirectories were also loaded, which was inconsistent with the documentation.
  • Clean up methods from previous analysis modules after re-analysis to prevent stale overload methods from appearing in signature help or completions.

Internal

  • Added heap snapshot profiling support. Create a .JETLSProfile file in the workspace root to trigger a heap snapshot. The snapshot is saved as JETLS_YYYYMMDD_HHMMSS.heapsnapshot and can be analyzed using Chrome DevTools. See DEVELOPMENT.md's Profiling section for details.

2025-12-02

  • Commit: aae52f5
  • Diff: f9b2c2f...aae52f5
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-12-02")'

Added

  • Added support for LSP initializationOptions with the experimental n_analysis_workers option for configuring concurrent analysis worker tasks. See Initialization options for details.

Changed

  • Parallelized signature analysis phase using Threads.@spawn, leveraging the thread-safe inference pipeline introduced in Julia v1.12. This parallelization happens automatically when Julia is started with multiple threads, independent of the newly added n_analysis_workers initialization option. With 4 threads (--threads=4,2 specifically), first-time analysis of CSV.jl improved from 30s to 18s (~1.7x faster), and JETLS.jl itself from 154s to 36s (~4.3x faster).

Fixed

  • Fixed handling of messages received before the initialize request per LSP 3.17 specification.
  • Fixed progress indicator not being cleaned up when analysis throws an error.

2025-11-30

  • Commit: f9b2c2f
  • Diff: eda08b5...f9b2c2f
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-11-30")'

Added

  • JETLS now automatically runs Pkg.resolve() and Pkg.instantiate() for packages that have not been instantiated yet (e.g., freshly cloned repositories). This allows full analysis to work immediately upon opening such packages. When no manifest file exists, JETLS first creates a versioned manifest (e.g., Manifest-v1.12.toml). This behavior is controlled by the full_analysis.auto_instantiate configuration option (default: true). Set it to false to disable.
  • When full_analysis.auto_instantiate is disabled, JETLS now checks if the environment is instantiated and warns the user if not.

Fixed

  • Fixed error when receiving notifications after shutdown request. The server now silently ignores notifications instead of causing errors from invalid property access (which is not possible for notifications).
  • Fixed race condition in package environment detection when multiple files are opened simultaneously. Added global lock to activate_do to serialize environment switching operations. This fixes spurious "Failed to identify package environment" warnings.
  • Fixed document highlight and rename not working for function parameters annotated with @nospecialize or @specialize.

Internal

  • Fixed Revise integration in development mode. The previous approach of dynamically loading Revise via Base.require didn't work properly because Revise assumes it's loaded from a REPL session. Revise is now a direct dependency that's conditionally loaded at compile time based on the JETLS_DEV_MODE flag.
  • Significantly refactored the full-analysis pipeline implementation. Modified the full-analysis pipeline behavior to output more detailed logs when JETLS_DEV_MODE is enabled.

2025-11-28

  • Commit: eda08b5
  • Diff: 6ec51e1...eda08b5
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-11-28")'

Changed

  • Pinned installation now uses release tags (rev="YYYY-MM-DD") instead of branch names (rev="releases/YYYY-MM-DD"). The releases/YYYY-MM-DD branches will be deleted after merging since [sources] entries reference commit SHAs directly. Existing release branches (releases/2025-11-24 through releases/2025-11-27) will be kept until the end of December 2025 for backward compatibility.

Fixed

Removed

  • Removed the deprecated runserver.jl script. Users should use the jetls executable app instead. See the 2025-11-24 release notes for migration details.

2025-11-27

  • Commit: 6ec51e1
  • Diff: 6bc34f1...6ec51e1
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-11-27")'

Added

  • Added --version (-v) option to the jetls CLI to display version information. The --help output now also includes the version. Version is stored in the JETLS_VERSION file and automatically updated during releases.
  • Automatic GitHub Release creation when release PRs are merged. You can view releases at https://github.com/aviatesk/JETLS.jl/releases. The contents are and will be extracted from this CHANGELOG.md.

Changed

  • Updated CodeTracking.jl, LoweredCodeUtils and JET.jl dependencies to the latest development versions.

Internal

  • Automation for release process: scripts/prepare-release.sh automates release branch creation, dependency vendoring, and PR creation.
  • Automatic CHANGELOG.md updates via CI when release PRs are merged.

2025-11-26

  • Commit: 6bc34f1
  • Diff: 2be0cff...6bc34f1
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-11-26")'

Changed

  • Updated JuliaSyntax.jl and JuliaLowering.jl dependencies to the latest development versions.
  • Updated documentation deployment to use release as the default version. The documentation now has two versions in the selector: release (stable) and dev (development). The root URL redirects to /release/ by default. The release documentation index page shows the release date extracted from commit messages.

2025-11-25

  • Commit: 2be0cff
  • Diff: fac4eaf...2be0cff
  • Installation:
    julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="2025-11-25")'

Added

Fixed

  • Fixed vendoring script to remove unused weakdeps and extensions from vendored packages. These could interact with user's package environment unexpectedly. Extensions that are actually used by JETLS are preserved with updated UUIDs. Fixes aviatesk/JETLS.jl#312. (aviatesk/JETLS.jl#320)

2025-11-24

Changed / Breaking

  • Implemented environment isolation via dependency vendoring to prevent conflicts between JETLS dependencies and packages being analyzed. All JETLS dependencies are now vendored with rewritten UUIDs in the release branch, allowing JETLS to maintain its own isolated copies of dependencies. This resolves issues where version conflicts between JETLS and analyzed packages would prevent analysis. Users should install JETLS from the release branch using Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release"). (aviatesk/JETLS.jl#314)
  • Migrated the JETLS entry point from the runserver.jl script to the jetls executable app defined by JETLS.jl itself. This significantly changes how JETLS is installed and launched, while the new methods are generally simpler: (aviatesk/JETLS.jl#314)
    • Installation: Install the jetls executable app using:
      julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release")'
      This installs the executable to ~/.julia/bin/jetls. Make sure ~/.julia/bin is in your PATH.
    • Updating: Update JETLS to the latest version by re-running the installation command:
      julia -e 'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release")'
    • Launching: Language clients should launch JETLS using the jetls executable with appropriate options. See https://aviatesk.github.io/JETLS.jl/release/launching/ for detailed launch options.
    • The VSCode language client jetls-client and Zed extension aviatesk/zed-julia has been updated accordingly.
  • Changed diagnostic configuration schema from [diagnostic.codes] to [[diagnostic.patterns]] for more flexible pattern matching. (aviatesk/JETLS.jl#299)
  • Renamed configuration section from [diagnostics] to [diagnostic] for consistency. (aviatesk/JETLS.jl#299)

Added

  • Added configurable diagnostic serveirty support with hierarchical diagnostic codes in "category/kind" format. Users can now control which diagnostics are displayed and their severity levels through fine-grained configuration. (aviatesk/JETLS.jl#298)
  • Added pattern-based diagnostic configuration supporting message-based matching in addition to code-based matching. Supports both literal and regex patterns with a four-tier priority system. (aviatesk/JETLS.jl#299)
  • Added file path-based filtering for diagnostic patterns. Users can specify glob patterns (e.g., "test/**/*.jl") to apply diagnostic configurations to specific files or directories. (aviatesk/JETLS.jl#313)
  • Added LSP codeDescription implementation with clickable documentation links for diagnostics. (aviatesk/JETLS.jl#298)
  • Added this change log. (aviatesk/JETLS.jl#316)

Fixed

  • Fixed UTF-8 position encoding to use byte offsets instead of character counts. This resolves misalignment issues in UTF-8-based editors like Helix while maintaining compatibility with UTF-16 editors like VS Code. (aviatesk/JETLS.jl#306)