Skip to content

Show documentation on hover #1025

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 16, 2025
Merged

Conversation

marvinborner
Copy link
Member

Closes #1006, blocked by #930.

@jiribenes jiribenes added blocked Blocked on other issues / PRs area:lsp labels May 26, 2025
@marvinborner marvinborner requested a review from Copilot May 26, 2025 15:00
Copilot

This comment was marked as off-topic.

@marvinborner marvinborner requested a review from b-studios May 26, 2025 15:03
@marvinborner
Copy link
Member Author

marvinborner commented Jun 1, 2025

Essentially this works now, except that the getDefinitionOf function not always links to the parent tree of the definition, but to its IdDef itself (e.g. for operations or constructors). Not sure if there's an easy fix for that, the way we lookup symbols is very mysterious.

Anyway, here's a demo:

hover.mp4

Btw, why can't I hover on emit in the signature? I don't think this ever worked and I don't understand why.

@jiribenes jiribenes removed the blocked Blocked on other issues / PRs label Jun 4, 2025
@jiribenes
Copy link
Contributor

It seems like this needs rebasing on #930, @marvinborner. 👀

@timsueberkrueb
Copy link
Contributor

Yes, otherwise it's a bit hard to review :) Please ping me once it's rebased!

@marvinborner marvinborner force-pushed the feature/documentation-on-hover branch from 7fe591d to a304fb2 Compare June 5, 2025 14:30
@marvinborner
Copy link
Member Author

@jiribenes @timsueberkrueb rebased!

@marvinborner
Copy link
Member Author

Another mysterious CI error in acme: https://github.com/effekt-lang/effekt/actions/runs/15469750869/job/43550747148 can not reproduce!

Copy link
Contributor

@timsueberkrueb timsueberkrueb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation.flatten
.map('\n' +: _)
.getOrElse("")
.replace("\\n", "\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is .flatten.map f the same as .flatMap f?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems we have:

But then, why do we pass an Option[Doc] (see other comment)?

Also, maybe instead of .map(...).getOrElse(...), a match would be clearer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late response.

Why is this needed?

We only want to add a newline delimiter if the symbol actually has a doc comment, therefore we map on it and then .getOrElse. We need to unescape the newlines in order to show them in VS code as literal newlines (we build the string with escaped newlines in RecursiveDescent)

Is .flatten.map f the same as .flatMap f

No, as it turns out. Also, I have changed the types from Option[Doc] to Doc, so this is not required anymore (see other comment)

Also, maybe instead of .map(...).getOrElse(...), a match would be clearer?

It's of course a stylistic choice, but I think it is clear enough as is.

case Some(p: Product) =>
p.productElementNames.zip(p.productIterator)
.collectFirst {
case ("doc", Some(s: String)) => Some(s)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's a way to get rid of the magic string literal here somehow 🤔?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, I am not aware of it. I also do not really have a problem with this implementation, I think it is precisely the solution which our way of annotating Docs requires us to use.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the Trees that (potentially) have doc comments inherit from some Documented trait like:

trait Documented {
  def doc: Doc
}
// ...
enum Def extends Definition with Documented {...}
// ...
case class Constructor(..., doc: Doc, ...) extends ... with Documented

?
Then this could be a

case Some(d: Documented) => d.doc

Then we will probably get better compiler support.
Or am I misunderstanding something?

Copy link
Contributor

@timsueberkrueb timsueberkrueb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with it if you add a test case so we notice if it breaks!

@marvinborner
Copy link
Member Author

The test case did indeed reveal a problem in the parsing of doc comments, where the initial doc comment was always ignored because of empty/implicit ModuleDecls always parsing a doc comment. The solution is a bit ugly again and may (?) violate an invariant again, let me know if you find a better solution for only parsing doc comments in explicit ModuleDecls.

Other than that, this should be mergeable now.

@marvinborner marvinborner merged commit bb2c2c1 into master Jun 16, 2025
2 checks passed
@marvinborner marvinborner deleted the feature/documentation-on-hover branch June 16, 2025 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Show documentation on hover
4 participants