-
Notifications
You must be signed in to change notification settings - Fork 206
Implement case slitting through ghc-mod #530
Conversation
Thanks¸ this looks good. However, the way ghc-mods splits function works, it forces reparsing and retypechecking of the module. But HIE has a module cache with the TypecheckedModule already on hand. If Also, it would eliminate the need for parsing as you would get the SplitInfo data structure directly. |
Thanks, good point. Seems doable so I'll see if I can get something going there. |
I am about to merge this, there is a minor fixup required for master, the name of one of the tests changed. |
@txsmith I am getting the following when testing with GHC 8.4.2 (the default stack.yaml), in my branch https://github.com/alanz/haskell-ide-engine/tree/case-split-259
So I am going to hand this back, please fix it. Sorry. |
I'll take a look. I was also still updating this to use the new |
Ok, thanks. I felt bad about forcing you to rebase the whole time, thought I would try a quick fixup and land. |
I probably made a mistake somewhere. Will investigate more tomorrow. |
See alanz/ghc-mod#10 |
Did alanz/ghc-mod#11 fix the issue? |
I have not really paid attention to what this PR does, so I do not know. I did see a trivial error, which was fixed in ghc-mod, but it seems there may be other issues too? |
Right, I meant @txsmith, sorry. |
I believe I fixed the issue in alanz/ghc-mod#10. The problem was that case splitting never worked in ghc-mod for newer GHC versions in the first place. |
Ok, So I will merge alanz/ghc-mod#10 and we can see about getting this in. Sorry to mess you around so much. |
@txsmith Current hie uses ghc-mod with your patch, so you can get this one finished, |
I think this is ready for another review now! |
@@ -290,6 +293,66 @@ cmp a b | |||
isSubRangeOf :: Range -> Range -> Bool | |||
isSubRangeOf (Range sa ea) (Range sb eb) = sb <= sa && eb >= ea | |||
|
|||
|
|||
|
|||
data DocumentPosition = |
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.
Shouldn't this be an instance of TextDocumentPositionParams
interface TextDocumentPositionParams {
/**
* The text document.
*/
textDocument: TextDocumentIdentifier;
/**
* The position inside the text document.
*/
position: Position;
}
as per https://microsoft.github.io/language-server-protocol/specification
This is made available via haskell-lsp-types
, see https://github.com/alanz/haskell-lsp/blob/406b9e0e795b5e9c2ae4a2ab29b2339c29fa0354/haskell-lsp-types/src/Language/Haskell/LSP/TH/DataTypesJSON.hs#L1008
splitCaseCmd' :: Uri -> Position -> IdeGhcM (IdeResult WorkspaceEdit) | ||
splitCaseCmd' uri position = | ||
pluginGetFile "splitCaseCmd: " uri $ \path -> do | ||
origText <- GM.withMappedFile path $ liftIO . T.readFile |
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.
This version of the file may differ from the version we have a TypecheckedModule for. Use newPosToOld
and oldPosToNew
to correlate positions across versions of the file.
cachedMod <- getCachedModule path | ||
case cachedMod of | ||
ModuleCached checkedModule _ -> runGhcModCommand $ do | ||
Just splitResult <- GM.splits' path (tcMod checkedModule) line column |
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.
A pattern match failure may cause HIE to crash
Just splitResult <- GM.splits' path (tcMod checkedModule) line column | ||
return $ splitResultToWorkspaceEdit origText splitResult | ||
ModuleFailed errText -> return $ IdeResultFail $ IdeError PluginError (T.append "hie-ghc-mod: " errText) Null | ||
ModuleLoading -> return $ IdeResultOk mempty |
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.
You should use withCachedModule
, as that will automatically defer the action if the module is still loading.
Alternatively, you can defer it manually over here.
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.
I've looked at this but could not find a nice way to defer the action while keeping it in IdeGhcM
. To defer an IdeGhcM
action we'd need to use IdeResponse'
, both of which do not work with withCachedModule
. Furthermore, in the end all plugins seem to use CommandFunc
which expects to return an IdeResult
. I can't really find a sensible way to make these work together without creating a mess. Also note that other plugins like typeCmd
don't defer either. Am I missing something?
Thanks for your feedback! Finally had some time to get it fixed. Please take a look :) |
Looks good. Thanks a lot. |
This implements a command that calls ghc-mod's splits and parses the output into a
WorkspaceEdit
.There's quite some code involved in parsing the output from ghc-mod. An example of the ouput:
11 0 11 13 "f (Just x) = \"Hello\"\NULf Nothing = \"Bye\""
This indicates the range of text (start line, start column, end line and end column) to replace and the new text to replace it with. Newlines are indicated by
\NUL
as per the default ghc-mod settings.If there's a better way to parse this and turn it into a
WorkspaceEdit
with less code I'd love to know!Now uses the new ghc-mod api!
I've added tests similar to those for "insert type". I'll also open a PR on vscode-hie-server so you can try it there for real.
Let me know what you think! I'm happy to follow up with improvements if needed.
Fixes #259