How can I use ctags with multiple Elm projects?

262 Views Asked by At

I use vim, and I'd like to be able to navigate to function and type definitions spread across multiple Elm projects. My understanding is that the easiest way to go about this is to use ctags.

There is an existing open issue from January 2016 with various suggestions, including a link to ctags-elm which provides:

--langdef=Elm
--langmap=Elm:.elm
--regex-Elm=/^ *([[:lower:]][[:alnum:]_]+)[[:blank:]]*:[^:].*->.*/\1/f,function,functions/
--regex-Elm=/^ *([[:lower:]][[:alnum:]_]+)[[:blank:]]*:[^:][^-]+$/\1/c,constant,constants/
--regex-Elm=/^port +([[:lower:]][[:alnum:]_]+)[[:blank:]]*:[^:]/\1/p,port,ports/
--regex-Elm=/^type +([[:upper:]][[:alnum:]_]+)/\1/t,type,types/
--regex-Elm=/^type[[:blank:]]+alias[[:blank:]]+([[:upper:]][[:alnum:]_]+)/\1/a,type-alias,type-aliases/

If you install this in ~/.ctags, you can scan all your sources:

$ ctags -R --languages=-all,+Elm

However this approach still has problems:

  • It ignores qualified names, so an attempt to navigate to the definition of List.map will offer all the definitions of Dict.map, Set.map, Random.map etc.
  • It scans all the *.elm files in all my directories, including tests and old dependencies.

Basically I'd like a solution that:

  • Can follow qualified names☨ to their definition: navigating to List.map should prefer definitions of map in files named List.elm.
  • Scans all the *.elm files in each project's source-directories
  • Ignores everything in each project's tests directory
  • Ignores all the built *.js files
  • Optionally scans the latest versions☨ of library sources in each project's elm-stuff/packages directory

Is this possible with ctags, or with a ctags wrapper that parses each project's elm-packages.json file?


[☨] Regarding qualified names: I'm aware that some people abbreviate qualifiers, like:

import Math.Vector3 as V3

and I wouldn't expect a ctags regex to look for V3.add in Math/Vector3. The longer-term solution would be a tool that understands Elm modules and imports, like hasktags does for Haskell. For now I could live with ctags not understanding abbreviated qualifiers.


[☨] Regarding latest versions: Sources of dependencies are downloaded into elm-stuff/packages/GITHUB-USERNAME/GITHUB-PROJECTNAME/VERSION-TAG, and over time it is possible to accumulate multiple versions, eg:

elm-stuff/packages/kfish/elm-gamepad/3.0.0
elm-stuff/packages/kfish/elm-gamepad/3.1.0
elm-stuff/packages/kfish/elm-gamepad/3.2.0
elm-stuff/packages/kfish/elm-gamepad/3.4.0
1

There are 1 best solutions below

1
On BEST ANSWER

I can't answer on the Elm-specific points but…

Ignores everything in each project's tests directory

Add this to ~/.ctags:

--exclude=tests

Ignores all the built *.js files

Add this to ~/.ctags if they are not compiled in a specific directory:

--exclude=\*.js

or exclude the directory/directories in which they are compiled.

Optionally scans the latest versions of library sources in each project's elm-stuff/packages directory

How do you define "latest"?

The only way I could think of to reach that goal would be to pre-compile the list of places to look in and feed it to ctags via the -L flag:

$ ctags -R -L list-of-files.txt .

Actually, writing a shell script to generate a proper list-of-files.txt could probably fix all your pain points. Maybe someone already thought about that…

See $ man ctags.