@@ -14,6 +14,7 @@ module Development.IDE.LSP.CodeAction
1414import Language.Haskell.LSP.Types
1515import Development.IDE.GHC.Compat
1616import Development.IDE.Core.Rules
17+import Development.IDE.Core.RuleTypes
1718import Development.IDE.Core.Shake
1819import Development.IDE.LSP.Server
1920import Development.IDE.Types.Location
@@ -24,6 +25,7 @@ import Language.Haskell.LSP.VFS
2425import Language.Haskell.LSP.Messages
2526import qualified Data.Rope.UTF16 as Rope
2627import Data.Aeson.Types (toJSON, fromJSON, Value(..), Result(..))
28+import Control.Monad.Trans.Maybe
2729import Data.Char
2830import Data.Maybe
2931import Data.List.Extra
@@ -53,19 +55,20 @@ codeLens
5355 -> CodeLensParams
5456 -> IO (List CodeLens)
5557codeLens _lsp ideState CodeLensParams{_textDocument=TextDocumentIdentifier uri} = do
56− diag <- getDiagnostics ideState
5758 case uriToFilePath' uri of
5859 Just (toNormalizedFilePath -> filePath) -> do
60+ _ <- runAction ideState $ runMaybeT $ useE TypeCheck filePath
61+ diag <- getDiagnostics ideState
5962 pure $ List
6063 [ CodeLens _range (Just (Command title "typesignature.add" (Just $ List [toJSON edit]))) Nothing
6164 | (dFile, dDiag@Diagnostic{_range=_range@Range{..},..}) <- diag
6265 , dFile == filePath
63− , (title, tedit) <- suggestTopLevelBinding False dDiag
66+ , (title, tedit) <- suggestSignature False dDiag
6467 , let edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
6568 ]
6669 Nothing -> pure $ List []
6770
68−-- | Generate code lenses.
71+-- | Execute the "typesignature.add" command.
6972executeAddSignatureCommand
7073 :: LSP.LspFuncs ()
7174 -> IdeState
@@ -177,12 +180,12 @@ suggestAction contents diag@Diagnostic{_range=_range@Range{..},..}
177180 extractFitNames = map (T.strip . head . T.splitOn " :: ")
178181 in map proposeHoleFit $ nubOrd $ findSuggestedHoleFits _message
179182
180− | tlb@[_] <- suggestTopLevelBinding True diag = tlb
183+ | tlb@[_] <- suggestSignature True diag = tlb
181184
182185suggestAction _ _ = []
183186
184−suggestTopLevelBinding :: Bool -> Diagnostic -> [(T.Text, [TextEdit])]
185−suggestTopLevelBinding isQuickFix Diagnostic{_range=_range@Range{..},..}
187+suggestSignature :: Bool -> Diagnostic -> [(T.Text, [TextEdit])]
188+suggestSignature isQuickFix Diagnostic{_range=_range@Range{..},..}
186189 | "Top-level binding with no type signature" `T.isInfixOf` _message = let
187190 filterNewlines = T.concat . T.lines
188191 unifySpaces = T.unwords . T.words
@@ -192,7 +195,23 @@ suggestTopLevelBinding isQuickFix Diagnostic{_range=_range@Range{..},..}
192195 title = if isQuickFix then "add signature: " <> signature else signature
193196 action = TextEdit beforeLine $ signature <> "\n"
194197 in [(title, [action])]
195−suggestTopLevelBinding _ _ = []
198+suggestSignature isQuickFix Diagnostic{_range=_range@Range{..},..}
199+ | "Polymorphic local binding with no type signature" `T.isInfixOf` _message = let
200+ filterNewlines = T.concat . T.lines
201+ unifySpaces = T.unwords . T.words
202+ signature = removeInitialForAll
203+ $ T.takeWhile (\x -> x/='*' && x/='•')
204+ $ T.strip $ unifySpaces $ last $ T.splitOn "type signature: " $ filterNewlines _message
205+ startOfLine = Position (_line _start) (_character _start)
206+ beforeLine = Range startOfLine startOfLine
207+ title = if isQuickFix then "add signature: " <> signature else signature
208+ action = TextEdit beforeLine $ signature <> "\n" <> T.replicate (_character _start) " "
209+ in [(title, [action])]
210+ where removeInitialForAll :: T.Text -> T.Text
211+ removeInitialForAll (T.breakOnEnd " :: " -> (nm, ty))
212+ | "forall" `T.isPrefixOf` ty = nm <> T.drop 2 (snd (T.breakOn "." ty))
213+ | otherwise = nm <> ty
214+suggestSignature _ _ = []
196215
197216topOfHoleFitsMarker :: T.Text
198217topOfHoleFitsMarker =