Tooling for VSCode / LSP

One can find this information

at Julia in Visual Studio Code.

It sounds appealingly simple, but there are caveats. Multiple issues have been filed pointing to the difficulty of using LSP in VSCode. For instance LanguageServer does not index active project/package · Issue #988 · julia-vscode/LanguageServer.jl · GitHub.

I have composed ideas found in this forum to produce a “system” for using VSCode with the LSP. It is described in this [document]
(LSP_in_VSCode/ at main · PetrKryslUCSD/LSP_in_VSCode · GitHub).

I would appreciate feedback:

  1. Is this a good way to go? If you have a better approach, I would appreciate hearing about it.
  2. If this is in fact something that would make sends to newbies, perhaps this should be part of the documentation. What would be a good place for it?
1 Like

You know, I tried the “fake include” trick out of curiousity, since my setup doesn’t get IntelliSense inside tests, and it didn’t work. No idea what I was doing wrong, but it wasn’t a showstopper (I had literally not noticed that my test files don’t have IntelliSense), so I didn’t bother debugging.

What I wanted to point out is that the techniques you’re describing can be fairly considered workarounds for bugs in the Julia LSP. There are probably issues tracking those bugs, and my suggestion is that you link to those issues at the top of your documentation.

Documentation like this tends to go stale (any documentation which isn’t carefully maintained will do this), and it would be good for someone stumbling across this sometime later to be able to check the status of these bugs, since the workarounds might no longer be necessary.

I think they might be the limitations of the model of the language at the client side, rather than bugs. In any case, what I proposed would still work if and when the VSCode client will somehow recognize that files like this (test, scripts, …) might be considered part of the sources, and hence the server should be made aware of them.

I didn’t mean to imply that it would stop working. But it’s a kludge, and it would be a pity if people came across this advice long after the reason for it was solved, and started putting fake include statements in their code when they don’t need to.

I would say the language server being unable to find symbols which Julia has no problem finding (obviously, or using inside the test wouldn’t work) is clearly a bug. In fact, it appears to be tracked by this issue, which you could link to at the top of your README, along with this one which you pointed out in your post.

That way, if those get closed, someone who comes across your guide (for whatever reason) will know that they don’t have to do that anymore, because the tooling is working correctly.

1 Like

Well, Hover help doesn't show for own modules · Issue #2719 · julia-vscode/julia-vscode · GitHub has not been tagged as a bug by the maintainers…

But, it general I agree with you concerning the docs getting out of date. But in the meantime a solution is needed. The problem has been known for years, and no fix is in sight.

It’s a reasonable workaround! I wasn’t able to get it to work locally, but that’s a me problem. My only suggestion is to lead with the GitHub issues, so that people who find your guide can easily check if the problem remains current. Not to be a broken record about it, just clarifying that I support you documenting a workaround for the problem.

I’m even more supportive of someone actually fixing the bug, whether it’s been tagged as one or not, it clearly is. But beggars can’t be choosers, and I don’t care enough to wade into the weeds of TypeScript or whatever to try and fix it, so meanwhile ¯\_(ツ)_/¯.

1 Like

Back to whether what I propose is a good solution: I am puzzled why it would not work for you. Could you try again, pretty please?

Is there a reason why you’re Pkg.adding the main project into the environment for examples and tutorials, but you’re Pkg.developing shared features in the environment for scripts?

I’d personally have a preference for Pkg.develop for both these use cases.

It is just that when working with scripts, the work tends to be more interactive, which means that functions can be added on the fly to the underlying package…

So, do I take it that you use the same recipe?

Yes, I tend to use an approach very similar to what you show for scripts / examples, but rather based on Pkg.develop.

If you’re looking for other precedents, AFAICT this is also one of the standard approaches for documentation: a “subproject” with its own dependencies (e.g Documenter.jl), in which the main project is developed.
(EDIT: to be clear, in the case of the documentation, this is used for standard dependency management, not just to make LSP happy.)

1 Like

No idea why it’s not working. I’ve had trouble getting it to recognize anything that isn’t in the same file actually. My packages use a fairly standard layout, one central module where the filename and the module have the same name, with the rest of the code as include statements, so it should all work, but, it doesn’t. If I’m in somefile.jl I can get definitions for functions in somefile but not for anything defined in someotherfile.jl even though they’re both included in MyModule.jl.

I haven’t put a lot of energy into diagnosing any of this, when I start tinkering with the environment it not-infrequently crashes the language server. I don’t have high expectations for these tools in general, C++ IntelliSense, which is a core Microsoft extension, was randomly crashing for a few days last week, some update fixed it but, yeah. The architecture is somewhat… rickety.

1 Like

Eh, I don’t think that’s necessarily an architectural issue, just one of software quality.

This is a reasonable workaround. IIRC the opposite approach should also work: putting a include("../src/MyPackage.jl") statement into your runtests.jl.

1 Like

Interesting. Thanks.

@pfitzseb : What I do not understand is: Let us say I make the package MyPack.jl my current environment; why can’t any file I open (such as runtests.jl) be added to the database of the LSP server? Or a new script opened anywhere at all? Is there a technical reason?

It’s difficult to separate these things, and I’d say that the architectural issues are responsible for the software quality. Async protocol-driven servers are inherently challenging to work into a real-time system like a text editor. Raph Levien has a good retrospective on the difficulties he encountered trying to make this work.


is what ended up working for me, but what drove me to comment about it is how this worked. Adding the include statement didn’t do it. Re-indexing the language server cache also didn’t do it. What did the job was doing all those things, and then doing something else for awhile, when I got back to the editor, I had symbol references in my tests.

Maybe the original fake include would have worked also, if I’d just waited around for the system to reach a consistent state, who knows. I prefer this solution because I find fake code aesthetically dissatisfying (YMMV), and including the module manually before using it is an acceptable thing to do in this context.

1 Like

I am no sure if the fake include still works, haven’t touched Julia code in a while. I think writing it inside the file you want intellisense is better than writing it inside the package main file. But, what i have done to get around this problem without using fake include is to create a dummy environment, and dev’ing the package into that environment. This worked fined the last time i tried, the problem is to have to change env in VSCode everytime you want intellisense to work.

So the way the LS works currently is that it looks up bindings in the currently active environment and the “include-tree”. Tests also use the package’s environment, which does not technically contain the package itself (for a very strict definition of “contains” – I’m using it in the sense of “is part of the dependencies section”).

So no, there’s not really a technical reason for this, just some missing logic. I’ll take another look at this later in the week.

Thanks for the explanation. That sounds promising!