# Integrating JET.jl with neovim

**URL:** https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989
**Category:** Tooling
**Tags:** neovim
**Created:** [September 30, 2021, 11:18am UTC](https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989 "2021-09-30T11:18:20Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![kdheepak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdheepak/32/10881_2.png) [@kdheepak](https://discourse.julialang.org/u/kdheepak)
#### Post date: [September 30, 2021, 11:18am UTC](https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989/1 "2021-09-30T11:18:20Z")

</div>

JET.jl is an experimental code analyzer for Julia: [https://github.com/aviatesk/JET.jl](https://github.com/aviatesk/JET.jl).

**Edit** : I’ve made the following into a plugin for neovim: [https://github.com/kdheepak/JET.nvim](https://github.com/kdheepak/JET.nvim)

The following post shows how to integrate JET.jl with [null-ls.nvim](https://github.com/jose-elias-alvarez/null-ls.nvim).

My current version of neovim:

```bash
$ nvim --version | head -1
NVIM v0.6.0-dev+366-g270cc1d70

```

Add the following `lua` block to your neovim configuration:

```plaintext
local null_ls = require("null-ls")
local helpers = require("null-ls.helpers")

local jet_julia = {
  method = null_ls.methods.DIAGNOSTICS,
  filetypes = { "julia" },
  generator = null_ls.generator({
    command = "jet",
    to_stdin = true,
    from_stderr = true,
    timeout = 15000, -- arbitrary large number. Depending on how long JET takes, you may need to increase this number
    format = "line",
    check_exit_code = function(code)
      return code <= 1
    end,
    args = function(params)
      local filename = params.bufname
      return { filename }
    end,
    on_output = helpers.diagnostics.from_patterns({
      {
        pattern = [[(%d+):(.*)]],
        groups = { "row", "message" },
      },
    }),
  }),
}

null_ls.register(jet_julia)

```

This will set up `null-ls` to launch a command line process called `jet`.

Next, create the following script called `jet`. I store this in `~/local/bin/jet`:

```julia
#!/usr/bin/env julia --project=~/.julia/environments/nvim-null-ls

using JET

filename = ARGS[1]

function print_reports(io, result)

    reports = JET.get_reports(result)
    postprocess = JET.gen_postprocess(result.res.actual2virtual)

    JET.with_bufferring(:color => get(io, :color, false)) do io
        toplevel_linfo_hash = hash(:dummy)
        wrote_linfos = Set{UInt64}()
        for report in reports
            new_toplevel_linfo_hash = hash(first(report.vst))
            if toplevel_linfo_hash != new_toplevel_linfo_hash
                toplevel_linfo_hash = new_toplevel_linfo_hash
                wrote_linfos = Set{UInt64}()
            end
            print_report(io, report)
        end
    end |> postprocess |> (x->print(io::IO,x))

end

function print_report(io, report::JET.InferenceErrorReport, depth = 1)
    if length(report.vst) == depth # error here
        return print_error_report(io, report)
    end
    print_report(io, report, depth + 1)
end

function print_error_report(io, report::JET.InferenceErrorReport)
    frame = report.vst[1]
    printstyled(io, string(frame.line), ": ")
    printstyled(io, report.msg, ": "; color = JET.ERROR_COLOR)
    JET.print_signature(io, report.sig,
                    (; annotate_types = true); # always annotate types for errored signatures
                    bold = true,
                    )
end

function print_error_report(io, report)
    printstyled(io, report.msg, "\n"; color = JET.ERROR_COLOR)
end

r = report_file(filename)
print_reports(stderr, r)

```

This must be available in your PATH. You will also have to make it executable, i.e. `chmod +x ~/local/bin/jet`.

This script uses a shebang to run Julia with a project environment. You can create this environment anywhere and modify the project path in the script above to the appropriate location. Make sure you install JET.jl in that environment.

 ![Screen Shot 2021-09-30 at 5.16.51 AM](https://global.discourse-cdn.com/julialang/original/3X/e/e/ee409ffef7727b1ce770a867c4c9a57be813ebb9.jpeg)

Finally, open any Julia file. The following is a couple of screenshots from the `demo.jl` file in the JET repository.

 ![Screen Shot 2021-09-30 at 5.10.29 AM](https://global.discourse-cdn.com/julialang/original/3X/b/4/b47f035733d3f3fab9dd9c13f0e5446e60f59d3c.jpeg)  
 ![Screen Shot 2021-09-30 at 5.10.49 AM](https://global.discourse-cdn.com/julialang/original/3X/e/7/e7c6f7aedfee1bf204958a13c79d15e35f02b9d2.png)

---

<div class="post-metadata">

### Author: ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)
#### Post date: [September 30, 2021, 11:28am UTC](https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989/2 "2021-09-30T11:28:20Z")

</div>

See [this FAQ for Linux](https://docs.julialang.org/en/v1/manual/faq/#How-do-I-pass-options-to-julia-using-#!/usr/bin/env?). I have to use that modify version at least.

---

<div class="post-metadata">

### Author: ![kdheepak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdheepak/32/10881_2.png) [@kdheepak](https://discourse.julialang.org/u/kdheepak)
#### Post date: [September 30, 2021, 11:41am UTC](https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989/3 "2021-09-30T11:41:00Z")

</div>

Ah, thanks for sharing, I didn’t know about that. I’ve made a git repository over here:

[https://github.com/kdheepak/JET.nvim](https://github.com/kdheepak/JET.nvim)

I’ll update this going forward.

---

<div class="post-metadata">

### Author: ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)
#### Post date: [September 30, 2021, 12:42pm UTC](https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989/4 "2021-09-30T12:42:16Z")

</div>

If I make many quick (well, not that quick, just quick enough for JET not to terminate before the next edit) this deadlocks somehow. I see multiple idle JET processes in top, and no messages in nvim.

---

<div class="post-metadata">

### Author: ![kdheepak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdheepak/32/10881_2.png) [@kdheepak](https://discourse.julialang.org/u/kdheepak)
#### Post date: [September 30, 2021, 12:52pm UTC](https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989/5 "2021-09-30T12:52:44Z")

</div>

That’s annoying. Maybe the timeout is too large for it to work this way? I’ll try to reproduce. We might have to open an issue on the null-ls repo for suggestions.

---

<div class="post-metadata">

### Author: ![kdheepak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdheepak/32/10881_2.png) [@kdheepak](https://discourse.julialang.org/u/kdheepak)
#### Post date: [September 30, 2021, 7:23pm UTC](https://discourse.julialang.org/t/integrating-jet-jl-with-neovim/68989/6 "2021-09-30T19:23:32Z")

</div>

@fredrikekre I changed the plugin to make it work using a infinite while loop. JET uses Revise to reload the file, so this works on save.

This is still not ideal though. I believe Neovim sends publishDiagnostics on every change, and that is forwarded to the script. However, since the file is not saved, the script just sends back the last known errors back to neovim. On save, once Revise does its thing, JET reruns and the script sends back updated diagnostics to neovim. So at least right now only one Julia process is spawned. I’m sure there are better ways to do this.

Ideally, I’d like the script to know if the file has changed or not before running `report_file` from JET. Perhaps there is a function in `Revise` that can help here.
