favicon here hometagsblogmicrobio cvtech cvgpg keys

Setting up Julia LSP for Helix

#setup #editor #helix #julia #lsp

Soc Virnyl Estela | 2023-05-19 | reading time: ~4min

The Julia programming language is a popular general programming language where the community leans more on scientific computing. And like most programming languages, Julia code can be written on most text editors such as IDEs.

Most editors today contain a set of tools such as git integration, built-in terminal, and a file picker and finder. Some editors that I tried are of the following:

Setting up Julia LSP for Helix§

Helix is a new editor I daily drive since a year ago. It follows a different style of editing than Vim/Neovim. It's model and keymaps are influenced from Kakoune which follows a select-action-execute model unlike the usual Vim action-select-execute model. I've been liking it so far!

As this post is about setting up LSP for Helix, setting up LSPs on other editors are pretty straight-forward e.g. Julia plugin on VSCode.

With helix, you have to write a simple configuration, specifically at languages.toml.

Writing the Julia LSP script for the LSP§

As helix does not have the option to pass the value of the current working directory of the file or buffer (maybe I am wrong, do correct me though!) unlike neovim's %:p:h, our script is like so:

import Pkg
project_path = let
    dirname(something(
        Base.load_path_expand((
            p = get(ENV, "JULIA_PROJECT", nothing);
            isnothing(p) ? nothing : isempty(p) ? nothing : p
        )),
        Base.current_project(pwd()),
        Pkg.Types.Context().env.project_file,
        Base.active_project(),
    ))
end

ls_install_path = joinpath(get(DEPOT_PATH, 1, joinpath(homedir(), ".julia")), "environments", "helix-lsp");
pushfirst!(LOAD_PATH, ls_install_path);
using LanguageServer;
popfirst!(LOAD_PATH);
depot_path = get(ENV, "JULIA_DEPOT_PATH", "")
symbol_server_path = joinpath(homedir(), ".cache", "helix", "julia_lsp_symbol_server")
mkpath(symbol_server_path)
server = LanguageServer.LanguageServerInstance(stdin, stdout, project_path, depot_path, nothing, symbol_server_path, true)
server.runlinter = true
run(server)

To understand what it's doing, the main focus of this script is actually the project_path variable. We first check if there is a JULIA_PROJECT environmental variable, explicitly set by the user. Base.load_path_expand achieves this. If there is none or if it is empty e.g. empty string, return nothing.

If the previous returns nothing, we use the Base.current_project(pwd()). And if it does not detect a Project.toml file from the current directory, we will fallback to Pkg.Types.Context().env.project_file and Base.active_project().

The project_path variable is very important as this will help us check which project you are in and where to run the LSP.

Julia's LSP is provided by LanguageServer.jl. But I don't like installing it on the global environment, hence, we have the ls_install_path variable. This ls_install_path variable assumes that you have installed the language server on one of the many DEPOT_PATH. Here, I assumed it has to be at ~/.julia/environments/helix-lsp. We need this variable because we need to add that path to the LOAD_PATH. You can check what LOAD_PATH is in the Julia REPL. Basically, it's just an array of paths where we load our environment for using and import statements. By default, it has a path to the global environment. This is why I have to add the popfirst! function since I don't want to use that one.

depot_path and symbol_server_path are optional but I like to make sure that JULIA_DEPOT_PATH exists.

Lastly, we then initialize the server by setting the LanguageServerInstance and setting the linter to true. We then run the run function with the server.

Adding it to language.toml§

Once we are done, we can finally either add it to a script file that can be executed within your PATH or just plain execute it like julia --project=@helix-lsp path/to/scriptfile.jl.

Here is a sample:

[[language]]
name = "julia"
scope = "source.julia"
injection-regex = "julia"
file-types = ["jl"]
roots = ["Project.toml", "Manifest.toml", "JuliaProject.toml"]
comment-token = "#"
language-server = { command = "julia", args = [
    "--project=@helix-lsp",
    "--sysimage=/home/uncomfy/.julia/environments/helix-lsp/languageserver.so",
    "--startup-file=no",
    "--history-file=no",
    "--quiet",
    "--sysimage-native-code=yes",
    "/home/uncomfy/.local/bin/julia-lsp.jl"
    ] }
indent = { tab-width = 4, unit = "    " }

It is up to you if you want to use PackageCompiler.jl to create a sysimage and make the LSP faster. Fortunately, you don't really need it since version 1.9.0 is very fast now.

There is runserver, why not use that?§

There are some gotchas with using runserver. If I can recall correctly, my issue was it cannot detect the correct paths inside helix and my script for neovim and kakoune is to detect where the file is located and if the location contains Project.toml or Manifest.toml and set it as the env_path. This can be seen with my kak-lsp julia config at line 168-170 on the default kak-lsp.toml

As you may noticed, it's not in the script we have discussed before this section. So I probably must have forgotten why I wrote that script only to end up that there is no way to check the path to the buffer or file. Therefore, I recommend to run helix within the root of your Julia project.

Let me know if you are not experiencing any issues with runserver since someone suggested that it works perfectly fine now. See https://github.com/helix-editor/helix/issues/669#issuecomment-1207489723

Articles from blogs I follow around the net

Session Round 2

Last week, I wrote a blog post succinctly titled, Don’t Use Session. Two interesting things have happened since I published that blog: A few people expressed uncertainty about what I wrote about using Pollard’s rho to attack Session’s design (for which, I …

via Dhole MomentsJanuary 20, 2025

Status update, January 2025

Hi all! FOSDEM is approaching rapidly! I’ll be there and will give a talk about modern IRC. In wlroots land, we’ve finally merged support for the next-generation screen capture protocols, ext-image-capture-source-v1 and ext-image-copy-capture-v1! Compared …

via emersionJanuary 18, 2025

The tech-industrial complex

I moved this blog off AWS to a local VPS outfit. I'm no longer giving any money to Jeff Bezos. Directly any way. I'm sure it finds its way to him via taxes & other things, but directly: No more. It's a small step, but one of many, & something I wanted to g…

via Mike KreuzerJanuary 18, 2025

No billionaires at FOSDEM

Jack Dorsey, former CEO of Twitter, ousted board member of BlueSky, and grifter extraordinaire to the tune of a $5.6B net worth, is giving a keynote at FOSDEM. The FOSDEM keynote stage is one of the biggest platforms in the free software community. Janson …

via Drew DeVault's blogJanuary 16, 2025

2024 in review

I want to go through some highlights of the year. Thanks for coming along for the ride!1 A year of being independent This was my first entire year of my being an independent open source maintainer. I’m very happy with how it turned out! I highly appreci…

via seanmonstarJanuary 15, 2025

Brainwash An Executive Today!

I. A few years ago, I had an annual one-on-one with the Chief Technology Officer of an employer with more than ten thousand staff. Senior management absolutely fawned over this person — extremely politically savvy, they would say. Amazing at acquiring fund…

via LudicityJanuary 13, 2025

2025 Predictions

I was just enjoying Simon Willison’s predictions and, heck, why not. 1: The web becomes adversarial to AI The history of search engines is sort of an arms race between websites and search engines. Back in the early 2000s, juicing your ranking on search e…

via macwright.comJanuary 11, 2025

A journey into File Transfer Protocols in Rust

How it started I can for sure affirm that you've used File transfer protocols before. Let's exclude HTTP from here, because, of course it is currently used also to transfer files, but it's not bi-directional and it mostly a workaround added at a certain…

via Christian Visintin BlogJanuary 06, 2025

The Adrian Dittmann Story

the evidence, from A to Z, and righting the wrongs

via maia blogJanuary 05, 2025

Bloat

Common questions we see in the OpenSUSE community are "which distro is the least bloated", "how can I remove bloat", "package X is bloat" etc. For the longest time this has confused me - Linux while sometimes slow, isn't "bloated". So where are all these q…

via Firstyear's blog-a-logJanuary 04, 2025

Awesome Fish functions

Some awesome fish functions that I have accumalated over the years.

via Ishan WritesJanuary 03, 2025

Styling HTML details and summary with modern CSS

Use CSS to style and manage disclosure widgets, which are the HTML details and summary elements.

via Rob O'Leary | BlogDecember 26, 2024

Yer a Wizard! Tagging Hard-coded Credentials Can Lead to Finding Magic (Numbers)

As GreyNoise researcher, you always have things to write detection rules for. Some of them aren’t always exciting, but they become more interesting as you dive deeper. Let’s jump right in and take a look at CVE-2024-6633: The default credentials for the s…

via GreyNoise LabsDecember 03, 2024

OpenGL is not Right-Handed

The original Twitter thread: https://x.com/TheGingerBill/status/1508833104567414785 I have a huge gripe when I read articles/tutorials on OpenGL: most people have no idea what they are talking about when it comes to coordinate systems and matrices. Specifi…

via Articles on gingerBillNovember 10, 2024

Physics Simulations in Bevy

Bevy is the most popular and powerful game engine in Rust. Because of its flexibility, it can be used not only for games but also for (scientific) physics simulations. In this blog post, I will share my experience using Bevy for physics simulations from sc…

via mo8it.comJuly 19, 2024

Defending myself against defensive writing

I write this blog because I enjoy writing. Some people enjoy reading what I write, which makes me feel really great! Recently, I took down a post and stopped writing for a few months because I didn't love the reaction I was getting on social media sites li…

via pcloadletterMay 27, 2024

The Elegiac Hindsight of Intelligent Machines

This essay was edited out of a chapter of my book, The Intelligence Illusion: a practical guide to the business risks of Generative AI, with minor alterations. “See the choice of dreams”, and then worry about it Very well. This book – this side, Dream …

via Out of the Software Crisis (Newsletter)October 13, 2023

Regex engine internals as a library

Over the last several years, I’ve rewritten Rust’s regex crate to enable better internal composition, and to make it easier to add optimizations while maintaining correctness. In the course of this rewrite I created a new crate, regex-automata, which expos…

via Andrew Gallant's Blog on Andrew Gallant's BlogJuly 05, 2023

Generated by openring-rs

favicon here hometagsblogmicrobio cvtech cvgpg keys