-
Notifications
You must be signed in to change notification settings - Fork 97
Allow GHC plugins to be called with an updated StringBuffer #698
Allow GHC plugins to be called with an updated StringBuffer #698
Conversation
Thanks for the PR and the detailed description! I think that your diagnosis is spot on, and I am interested in figuring out why the Did you try populating the field in https://github.com/digital-asset/ghcide/blob/master/src/Development/IDE/Core/Compile.hs#L431 |
Hey @pepeiborra ! Thanks for getting back to me so quickly 😉
I haven't. In my rabbit hole exploration I came across another homemade But you make a good point, that |
9b6e1d3
to
80d5f53
Compare
The `getModSummaryFromBuffer` function constructs a `ModSummary` that will be included in the `ParsedModule` data structure ghcide will later on typecheck, calling any registred plugin in the process. There was a problem, though: such `ModSummary` didn't include the updated `StringBuffer` representing the in-memory content of a file being edited (inclusive of all its unsaved changes). This was causing plugins to not react in real time and emitting diagnostics only upon save. This commit fixes it.
80d5f53
to
b27b2e3
Compare
@pepeiborra Ah, success! You intuition was definitely correct. Properly setting the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, thank you!
…ghcide#698) * Ignore tags file * Pass an updated StringBuffer in ModSummary construction The `getModSummaryFromBuffer` function constructs a `ModSummary` that will be included in the `ParsedModule` data structure ghcide will later on typecheck, calling any registred plugin in the process. There was a problem, though: such `ModSummary` didn't include the updated `StringBuffer` representing the in-memory content of a file being edited (inclusive of all its unsaved changes). This was causing plugins to not react in real time and emitting diagnostics only upon save. This commit fixes it.
…ghcide#698) * Ignore tags file * Pass an updated StringBuffer in ModSummary construction The `getModSummaryFromBuffer` function constructs a `ModSummary` that will be included in the `ParsedModule` data structure ghcide will later on typecheck, calling any registred plugin in the process. There was a problem, though: such `ModSummary` didn't include the updated `StringBuffer` representing the in-memory content of a file being edited (inclusive of all its unsaved changes). This was causing plugins to not react in real time and emitting diagnostics only upon save. This commit fixes it.
…ghcide#698) * Ignore tags file * Pass an updated StringBuffer in ModSummary construction The `getModSummaryFromBuffer` function constructs a `ModSummary` that will be included in the `ParsedModule` data structure ghcide will later on typecheck, calling any registred plugin in the process. There was a problem, though: such `ModSummary` didn't include the updated `StringBuffer` representing the in-memory content of a file being edited (inclusive of all its unsaved changes). This was causing plugins to not react in real time and emitting diagnostics only upon save. This commit fixes it.
While converting LiquidHaskell into a plugin, we tried to integrate it with
ghcide
. It has been a journey with some lumps and bumps, but eventually we succeeded (with proviso). The plugin itself requires the minimum version of GHC to be8.10.1
(for technical reasons) and soon enough we discovered that plugins and8.10.1
don't get along too well, mostly due to https://gitlab.haskell.org/ghc/ghc/-/issues/18070 (which was originally discovered as part of #556).However, I've tried building a custom
ghc
version (via Hadrian, as Leon Schoorl mentioned in that GHC ticket) and indeed gotghcide
to sort of work with the LH plugin. I say "sort of" because we were observing some strange behaviour where diagnostics would be emitted only when saving the corresponding file, and not in real time, as usual. This happened (in short) for two reasons:ghcide
seems to not be calling any other plugin "hook" than thetypecheckResultAction
. It doesn't do it directly,but rather indirectly as part of the GHC API call to
typecheckModule
. This means that plugins have only "one single place"where they can intercept the normal
ghcide
workflow and do something else;Crucially speaking, when
ghcide
was calling thetypecheckResultAction
, it was doing it with a stale view of the filebeing checked. In other terms, plugins received an input
ModSummary
that virtually pointed to the on disk snapshot ofa file, and not the in memory one that the user was editing (via its editor of choice).
However, a point could be made that is
ghcide
's responsibility to call any registered plugin with the same view of the world thatghcide
also "sees", to ensure there is no mismatch between what users can do and that plugins can do.This patch fixes it:
While this works, it's also my first foray into
ghcide
hacking, so I have no clue whether or not this patch could add a severe overhead to the typechecking rule. If I understand correctlygetFileContents
caches the information, so in theory if the file doesn't change too often, this call is relatively cheap. Having said that, there might be better ways to achieve the same result I simply didn't think of.Other caveats
This fix relies, as most fixes in this space, on the delicate house of cards provided by the GHC API. It works for LH (that needs to re-parse the input module) because the
parseModule
function from the GHC API looks first at thems_hspp_buf
content, and only if that'sNothing
, it re-parses a module. On top of that, we have no guarantees (in the types, that is) that somebody else won't override thems_hspp_buf
downstream, before callingGHC.typecheckModule
.