effekt-lang / effekt

A language with lexical effect handlers and lightweight effect polymorphism
https://effekt-lang.org
MIT License
327 stars 23 forks source link

LSP inlay hints #524

Open jiribenes opened 3 months ago

jiribenes commented 3 months ago

We could use inlay hints from LSP v3.17 for:

  1. showing the inferred capabilities in a principled way ([{io}] def ...)
  2. showing the inferred return types and effects of functions (def bar(x: Int) [: Int / Log] = ...)
  3. showing the inferred types of bindings (val foo [: Int] = ...)
  4. showing the expected & actual type of a typed hole ("answer is: " ++ <{ 42 [: Int] }> [: String])
  5. showing the inferred boxes/unboxes? (val boxed = [box ] function)
  6. showing the chosen overloads?
  7. showing the argument names for functions with many arguments of the same type bank.transfer([from =] person1, [to =] person2)
  8. showing the unique identifier for a typed hole? ([?1] <{ ... }>)

(where [...] means an inlay hint)

Note that these would probably need to be highly configurable so that the code is still somewhat navigable. :)

As far as I can tell, we're already doing 1. in a somewhat ad-hoc way: https://github.com/effekt-lang/effekt/blob/7b7629c942e2809cab08b0122e244ba3bcbb9410/effekt/js/src/main/scala/effekt/LanguageServer.scala#L138-L143 but it would be nice to use the LSP protocol instead.

There are also a lot of other quality of life related features like "if we already have an inlay, we can just double-click it to apply" like in rust-analyzer (see first video there for a demo).

jiribenes commented 3 months ago

How to start with this PR (rough draft)

  1. bump LSP4J in Kiama (here: https://github.com/effekt-lang/kiama/blob/ab6aef78fc4ce99a9ad2db8555718d00b03f7b8a/build.sbt#L11)
  2. in the Server trait, add some getInlayHints: Range => Option[Vector[InlayHint]] method
  3. when initialising in the Services class, register inlay hints as server capabilities (docs)
  4. in Services catch the textDocument/inlayHint event (similarly to https://github.com/effekt-lang/kiama/blob/ab6aef78fc4ce99a9ad2db8555718d00b03f7b8a/jvm/src/main/scala/kiama/util/Server.scala#L518-L519)
  5. and call server.getInlayHints on the serverRange and create a new InlayHint, setting the position, label, etc. (docs)
  6. in the LanguageService trait, define some basic case class for InlayHints, let's say for types and parameters for now?
  7. override the getInlayHints in LSPServer here in this repo
  8. ???
  9. profit