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

LSP window message log recorder #2750

Merged
merged 5 commits into from Mar 6, 2022
Merged

LSP window message log recorder #2750

merged 5 commits into from Mar 6, 2022

Conversation

pepeiborra
Copy link
Collaborator

@pepeiborra pepeiborra commented Mar 5, 2022

This PR adds a new Recorder that emits LSP WindowShowMessage notifications, and then uses it to surface errors to the user.

image

@pepeiborra pepeiborra requested a review from fendor as a code owner March 5, 2022 15:39
@pepeiborra pepeiborra requested review from drsooch, eddiemundo and michaelpj and removed request for drsooch March 5, 2022 16:26
Copy link
Collaborator

@eddiemundo eddiemundo left a comment

Choose a reason for hiding this comment

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

So this is what you meant by using a plugin to get the env... nice. Additionally, the issue of how to choose which specific messages to send to window is sidestepped by sending all the ones with Error.

The ghcide/exe version doesn't have the issue tracker url message but that's fine since most people will be using hls rather than ghcide.

There are a few other places that use SWindowMessage to add to the logging TODO list:
splice plugin
tactics plugin
fourmolu plugin
retrie plugin
extendImportHandler plugin in Completions.hs
displayTHWarning in Rules.hs

Sorry for not being too active, been distracted recently.

@pepeiborra
Copy link
Collaborator Author

There are a few other places that use SWindowMessage to add to the logging TODO list: splice plugin tactics plugin fourmolu plugin retrie plugin extendImportHandler plugin in Completions.hs displayTHWarning in Rules.hs

Thanks. I'll take a look at those and see if they can be changed to log errors meaningfully.

@pepeiborra
Copy link
Collaborator Author

pepeiborra commented Mar 5, 2022

Additionally, the issue of how to choose which specific messages to send to window is sidestepped by sending all the ones with Error.

Yes - this is just a coarse simple way of selecting what messages get shown.

The finer way to do this (and what we do in Sigma IDE where we have lots of telemetry) is to do a case analysis on the entire log type to filter exactly what things we want to record (and how).

@pepeiborra pepeiborra merged commit 5afb077 into master Mar 6, 2022
July541 pushed a commit to July541/haskell-language-server that referenced this pull request Mar 6, 2022
* failing to set the unsafe dynflags is an error

* makeLspRecorder

* include link to the issue tracker

* avoid double popup

* catch another ghc lib dir error
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.

I also have a branch that implements this, here's the commit: michaelpj@57ac4a1

The main difference is the way we get the LanguageContextEnv to the Recorder. I'm really not a fan of the plugin trick, I think we should just pass it in. I don't mind the IORef way, but I think we could just pass it down as an ordinary parameter instead of smuggling it in like this.

I also want to include a recorder that sends window/logMessage notifications, but I'll do that separately.


renderDoc :: Doc a -> Text
renderDoc d = renderStrict $ layoutPretty defaultLayoutOptions $ vcat
["Unhandled exception, please check your setup and/or the [issue tracker](" <> issueTrackerUrl <> "): "
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not necessarily an exception, right? It could be any other error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

True, I copied this message over from an earlier exception site - will change to error

Copy link
Collaborator

@michaelpj michaelpj Mar 6, 2022

Choose a reason for hiding this comment

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

And indeed, since we send it as an error message, we don't need to tell the user again that it's an error. Including the issue link is maybe still helpful.

case mbenv of
Nothing -> liftIO $ atomicModifyIORef'_ backLogRef (it :)
Just env -> sendMsg env it
-- the plugin captures the language context, so it can be used to send messages
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't really like this approach. It's extremely indirect. My branch just has a function LanguageContextEnv config -> Recorder ... and then we have to pass it along until we reach initialize.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we could relatively easily adapt this to just pass the IORef to be filled in rather than going via a plugin...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Please send a PR! I suspect that the plugin solution is more modular, as it abstracts away the passing of the mutable state around.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, but it does so by using a mechanism that really isn't designed for that. Now the recorder mechanism is intertwined with the plugin mechanism, which it should have nothing to do with that. We shouldn't have to fix the loggers if we change how plugins work; that seems anti-modular to me.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'll take a look.

IO (Recorder (WithPriority Text), PluginDescriptor c)
makeLspShowMessageRecorder = do
envRef <- newIORef Nothing
-- messages logged before the LSP stream is initialized will be sent when it is
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is neat, my version just didn't record until it gets setup when the LSP server is ready.

}
return (recorder, plugin)

sendMsg :: MonadUnliftIO m => LanguageContextEnv config -> WithPriority Text -> m ()
Copy link
Collaborator

Choose a reason for hiding this comment

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

You don't actually need the MonadUnliftIO constraint: just declare this function to run in IO, and call liftIO at the use site. Then you can get rid of all the other stuff.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch - I'll drop the instance before @wz1000 gets a chance to abuse it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants