Skip to content
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

Display instances on hover for type and data constructors #3963

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

DeviousStoat
Copy link

An attempt to implement the requested enhancement in #3098

It displays the list of typeclass instances a type has when requesting hover information.
It should work on type constructors as well as the data constructors, using the related type.

It is added as a new section at the end of the hover information.

Here is an example of how it looks when hovering on Maybe or Just or Nothing
maybe_instances

It seems to also be scope aware, if I import new instances then they will be added to the list. For example if I install hashable and import Data.Hashable with the Hashable instance for Int and hover on Int I get an additional
hashable_int
which is pretty cool.

@soulomoon
Copy link
Collaborator

soulomoon commented Jan 16, 2024

It looks cool, 🤔 how is the result sorted, should we sort the result?

Copy link
Collaborator

@soulomoon soulomoon left a comment

Choose a reason for hiding this comment

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

look good, some questions

@@ -59,6 +60,7 @@ import Data.List.Extra (dropEnd1, nubOrd)

import Data.Version (showVersion)
import Development.IDE.Types.Shake (WithHieDb)
import GHC (getInstancesForType)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we get it from Compat?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Since in general we import ghc stuff from Development.IDE.GHC.Compat

Copy link
Author

Choose a reason for hiding this comment

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

so I should just export it in Development.IDE.GHC.Compat? Why is this needed? It seems to be available in this module in all the ghc versions supported by hls

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm unsure of our policy here, wdyt @wz1000 ?

Copy link
Collaborator

@michaelpj michaelpj left a comment

Choose a reason for hiding this comment

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

Looks plausible to me, I'd like a review from @wz1000 . And it needs some tests.

I note that we have a problem in our hovers in that there are no explanations for what the various sections of the hover mean. In this case I think it's obvious, but perhaps we could take the opportunity to add titles to the sections? For this bit I think it could just be Instances in scope for <name>?

ghcide/src/Development/IDE/Spans/AtPoint.hs Outdated Show resolved Hide resolved
where
instancesForName :: IO (Maybe [ClsInst])
instancesForName = runMaybeT $ do
typ <- MaybeT . pure $ lookupNameEnv km n >>= tyThingToType
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like we look things up repeatedly in km. Should we do this once and then just pass in the TyThing to all the places that need it?

Copy link
Author

Choose a reason for hiding this comment

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

I am not sure what you mean. I think the lookup only happens once per Name and we need to look it up for each Name

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean in the other functions we call around here. Probably not a huge deal

@@ -308,6 +311,24 @@ atPoint IdeOptions{} (HAR _ hf _ _ (kind :: HieKind hietype)) (DKMap dm km) env
UnhelpfulLoc {} | isInternalName name || isSystemName name -> Nothing
_ -> Just $ "*Defined " <> printOutputable (pprNameDefnLoc name) <> "*"

prettyInstances :: (Either ModuleName Name, IdentifierDetails hietype) -> IO (Maybe T.Text)
prettyInstances (Right n, _) =
Copy link
Collaborator

Choose a reason for hiding this comment

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

In cases like this I'd usually just make the function take what it needs (just a Name) and get the caller to worry about massaging the list into the right form.

Copy link
Author

Choose a reason for hiding this comment

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

Sounds better, I switched it up

@@ -59,6 +60,7 @@ import Data.List.Extra (dropEnd1, nubOrd)

import Data.Version (showVersion)
import Development.IDE.Types.Shake (WithHieDb)
import GHC (getInstancesForType)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm unsure of our policy here, wdyt @wz1000 ?

@DeviousStoat
Copy link
Author

About the titles, I personally don't think it is too useful, imo it would just add unecessary clutter in the hover text.
You say In this case I think it's obvious but I don't really see any other section that is not obvious.
But of course if you all think it is a good idea I am willing to add them (I am kind of starting in the haskell world so I am a sucker for some small not too tricky tasks to improve :D) but maybe in another PR afterwards as it would be awkward to have only one title here. And adding them all in this PR is a bit out of scope.

@DeviousStoat
Copy link
Author

hum, I used it a bit more and there are a few issues with this feature as it is currently implemented actually.
Hovering on some imported datatypes that are supposed to have instances don't show anything on hover. And it also doesn't show anything for datatypes defined in the current module with instances. I am not sure what's going on yet. I will be looking into it but I guess this PR is still WIP then.

@michaelpj
Copy link
Collaborator

Yes fine, we can leave the title thing for later

@soulomoon soulomoon added the WIP label Jan 23, 2024
@DeviousStoat
Copy link
Author

DeviousStoat commented Feb 7, 2024

I looked a bit into it and I might need some guidance, there are some things I don't really understand.
So the issue I have is that the instances coming from external libraries (apart from GHC base libraries) and from the current file are not shown at all.

I believe the issue comes from there

clsInst <- liftIO $ evalGhcEnv env $ getInstancesForType typ

It seems that the env doesn't have the required modules loaded at this point.

Doesn't the GHCSession action takes care of this? I tried using GHCSessionDeps but it didn't change anything. Do you know what the difference is between the 2?

I found this function in the hls-eval-plugin. It seems to have to manually load the modules in the session. Is it something I would probably have to do to execute interactive functions like the getInstancesForType? If so I don't exactly understand what this env is all about, is it just an empty ghc execution context?

I am guessing there are some things like types and docstrings that are cheap to reload but instances is not part of these.

@soulomoon
Copy link
Collaborator

Doesn't the GHCSession action takes care of this?

Perhaps we are not taking care of things that is not used yet, you can dig deeper to see how do we manage to include the information in the session.

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.

None yet

3 participants