[ANN] Project wide occurrences in Merlin and LSP

I am very excited to announce the first release of Merlin and Ocaml-LSP with support for project-wide occurrences :partying_face:. More precisely, it is now possible to query for every usage of any value (and type, modules, etc.) anywhere in a project built with Dune. This is a very handy tool for code navigation !

Requirements

  • OCaml 5.2
  • Latest Dune (>= 3.16.0)
  • Latest Merlin (>= 5.1-502)
  • Latest OCaml-LSP preview (1.18.0~5.2preview)

You can uprgade by running opam update followed by opam upgrade.

Usage

  • Build the new @ocaml-index alias.

We recommend running the indexation in watch mode along with your usual targets: dune build @ocaml-index --watch so that the index is always up to date.

  • Use the Find/Peek all references feature of LSP-based plugins
    • or merlin-project-occurrences in emacs
    • or OccurrencesProjectWide in vim.
  • Enjoy jumping around :kangaroo:

ScreenRecording2024-06-11at15.29.40-ezgif.com-otimize

More information and bug reports

Bug reports and feature requests should be submitted to the Merlin issue tracker. There are already some known issues like the absence of declarations in the results and the impossibility to query from a declaration (and thus mli files). Progress on occurrences can be tracked in a pinned meta-issue. If you are interested in contributing and learning more about the feature do not hesitate to join the first public dev-meeting on Thursday !

43 Likes

Where should we get ocaml-index executable? In the preview it was in indexing-tools package, but right now this package seems to be absent in default opam repo.

have you tried ocaml-index 1.0 (latest) · OCaml Package ?

2 Likes

You can opam install ocaml-index, but it should be done automatically when you upgrade since it is a dependency of the merlin and ocaml-lsp-server packages. Don’t forget to opam update before !

2 Likes

Impressive! As I understand, it unlocks project wide rename refactoring?

2 Likes

Cool! Does this support jumping to a ref in a transitive dependency?

1 Like

Not sure what you mean excatly, but jump-to-definition has always been able to jump to a transitive dependency. There was an issue, however, when using dune’s (implicit transitive deps false). That behavior should be improved with the latest release too.

1 Like

It is a wide step into that direction! We did not enable it in the lsp server for renaming yet, since it requires more work to be done cleanly (like looking at syntax tricks like punning before renaming).

Additionally, we need more than the currently returned set of “usages” to perform renaming: we need to know which declaration(s) correspond to the selected item and all the usages of all the definitions that share these declarations… But it is definitely coming :slight_smile:

7 Likes

Let’s say we’re working in our local project. And that project has a dependency on say Bigstringaf. If we start looking at Bigstringaf sources via the LSP and execute a search for references query on some function in Bigstringaf, will that work ?

In other words, does project wide occurences work on source code of the library dependencies ?

1 Like

You should get all the occurrences of Bigstringaf.something in the sources of your project.

You won’t get occurrences of Bigstringaf.something in bigstringaf sources or anywhere else in the installed (opam switch) world. (unless you use a monorepo).

2 Likes

I tried this out – it works but not totally as expected. (I’m using ocaml-lsp-server)

(I tried this out on the eio source code in case anybody would like to try this out themselves)

I used Atomic.set as an example.

If I search for all occurences of Atomic.set in my project it works when I place the cursor anywhere on set – I get occurences of Atomic.set – great !!

Now I’m interested in looking for all usage of the Atomic module. So I place my cursor anywhere on Atomic and try to get occurences – it doesn’t work – is this expected ?

2 Likes

Hi @sid, it great to see people play with this :slight_smile:

It is expected that occurrences of modules appearing in paths (such as Atomic in Atomic.set) are not returned. This is due to missing location information in longidents and is part of the roadmap.

Direct usages of the module, such as open Atomic should be found however.

4 Likes