@@ -38,7 +38,6 @@ import Data.Ord (comparing)
3838import qualified Data.Set as S
3939import qualified Data.Text as T
4040import qualified Data.Text.Utf16.Rope as Rope
41- import Data.Tuple.Extra (first )
4241import Development.IDE.Core.Rules
4342import Development.IDE.Core.RuleTypes
4443import Development.IDE.Core.Service
@@ -57,6 +56,7 @@ import Development.IDE.Plugin.CodeAction.ExactPrint
5756import Development.IDE.Plugin.CodeAction.PositionIndexed
5857import Development.IDE.Plugin.CodeAction.Util
5958import Development.IDE.Plugin.Completions.Types
59+ import qualified Development.IDE.Plugin.Plugins.AddArgument
6060import Development.IDE.Plugin.TypeLenses (suggestSignature )
6161import Development.IDE.Types.Exports
6262import Development.IDE.Types.Location
@@ -65,8 +65,7 @@ import Development.IDE.Types.Logger hiding
6565import Development.IDE.Types.Options
6666import GHC.Exts (fromList )
6767import qualified GHC.LanguageExtensions as Lang
68- import Ide.PluginUtils (makeDiffTextEdit ,
69- subRange )
68+ import Ide.PluginUtils (subRange )
7069import Ide.Types
7170import qualified Language.LSP.Server as LSP
7271import Language.LSP.Types (ApplyWorkspaceEditParams (.. ),
@@ -92,15 +91,8 @@ import Language.LSP.VFS (VirtualFile,
9291import qualified Text.Fuzzy.Parallel as TFP
9392import Text.Regex.TDFA (mrAfter ,
9493 (=~) , (=~~) )
95- #if MIN_VERSION_ghc(9,2,1)
96- import Data.Either.Extra (maybeToEither )
97- import GHC.Types.SrcLoc (generatedSrcSpan )
98- import Language.Haskell.GHC.ExactPrint (noAnnSrcSpanDP1 ,
99- runTransformT )
100- #endif
10194#if MIN_VERSION_ghc(9,2,0)
102- import Control.Monad.Except (lift )
103- import Debug.Trace
95+ import Development.IDE.Plugin.Plugins.Diagnostic
10496import GHC (AddEpAnn (AddEpAnn ),
10597 Anchor (anchor_op ),
10698 AnchorOperation (.. ),
@@ -109,17 +101,7 @@ import GHC (AddEpAnn (Ad
109101 EpAnn (.. ),
110102 EpaLocation (.. ),
111103 LEpaComment ,
112- LocatedA ,
113- SrcSpanAnn' (SrcSpanAnn ),
114- SrcSpanAnnA ,
115- SrcSpanAnnN ,
116- TrailingAnn (.. ),
117- addTrailingAnnToA ,
118- emptyComments ,
119- noAnn )
120- import GHC.Hs (IsUnicodeSyntax (.. ))
121- import Language.Haskell.GHC.ExactPrint.Transform (d1 )
122-
104+ LocatedA )
123105#else
124106import Language.Haskell.GHC.ExactPrint.Types (Annotation (annsDP ),
125107 DeltaPos ,
@@ -190,7 +172,7 @@ bindingsPluginDescriptor recorder plId = mkExactprintPluginDescriptor recorder $
190172#endif
191173 , wrap suggestNewDefinition
192174#if MIN_VERSION_ghc(9,2,1)
193- , wrap suggestAddArgument
175+ , wrap Development.IDE.Plugin.Plugins.AddArgument. plugin
194176#endif
195177 , wrap suggestDeleteUnusedBinding
196178 ]
@@ -905,34 +887,6 @@ suggestReplaceIdentifier contents Diagnostic{_range=_range,..}
905887 = [ (" Replace with ‘" <> name <> " ’" , [mkRenameEdit contents _range name]) | name <- renameSuggestions ]
906888 | otherwise = []
907889
908- matchVariableNotInScope :: T. Text -> Maybe (T. Text , Maybe T. Text )
909- matchVariableNotInScope message
910- -- * Variable not in scope:
911- -- suggestAcion :: Maybe T.Text -> Range -> Range
912- -- * Variable not in scope:
913- -- suggestAcion
914- | Just (name, typ) <- matchVariableNotInScopeTyped message = Just (name, Just typ)
915- | Just name <- matchVariableNotInScopeUntyped message = Just (name, Nothing )
916- | otherwise = Nothing
917- where
918- matchVariableNotInScopeTyped message
919- | Just [name, typ] <- matchRegexUnifySpaces message " Variable not in scope: ([^ ]+) :: ([^*•]+)" =
920- Just (name, typ)
921- | otherwise = Nothing
922- matchVariableNotInScopeUntyped message
923- | Just [name] <- matchRegexUnifySpaces message " Variable not in scope: ([^ ]+)" =
924- Just name
925- | otherwise = Nothing
926-
927- matchFoundHole :: T. Text -> Maybe (T. Text , T. Text )
928- matchFoundHole message
929- | Just [name, typ] <- matchRegexUnifySpaces message " Found hole: _([^ ]+) :: ([^*•]+) Or perhaps" =
930- Just (name, typ)
931- | otherwise = Nothing
932-
933- matchFoundHoleIncludeUnderscore :: T. Text -> Maybe (T. Text , T. Text )
934- matchFoundHoleIncludeUnderscore message = first (" _" <> ) <$> matchFoundHole message
935-
936890suggestNewDefinition :: IdeOptions -> ParsedModule -> Maybe T. Text -> Diagnostic -> [(T. Text , [TextEdit ])]
937891suggestNewDefinition ideOptions parsedModule contents Diagnostic {_message, _range}
938892 | Just (name, typ) <- matchVariableNotInScope message =
@@ -962,121 +916,6 @@ newDefinitionAction IdeOptions {..} parsedModule Range {_start} name typ
962916 sig = name <> colon <> T. dropWhileEnd isSpace (fromMaybe " _" typ)
963917 ParsedModule {pm_parsed_source = L _ HsModule {hsmodDecls}} = parsedModule
964918
965- #if MIN_VERSION_ghc(9,2,1)
966- -- When GHC tells us that a variable is not bound, it will tell us either:
967- -- - there is an unbound variable with a given type
968- -- - there is an unbound variable (GHC provides no type suggestion)
969- --
970- -- When we receive either of these errors, we produce a text edit that will add a new argument (as a new pattern in the
971- -- last position of each LHS of the top-level bindings for this HsDecl).
972- --
973- -- NOTE When adding a new argument to a declaration, the corresponding argument's type in declaration's signature might
974- -- not be the last type in the signature, such as:
975- -- foo :: a -> b -> c -> d
976- -- foo a b = \c -> ...
977- -- In this case a new argument would have to add its type between b and c in the signature.
978- suggestAddArgument :: ParsedModule -> Diagnostic -> Either ResponseError [(T. Text , [TextEdit ])]
979- suggestAddArgument parsedModule Diagnostic {_message, _range}
980- | Just (name, typ) <- matchVariableNotInScope message = addArgumentAction parsedModule _range name typ
981- | Just (name, typ) <- matchFoundHoleIncludeUnderscore message = addArgumentAction parsedModule _range name (Just typ)
982- | otherwise = pure []
983- where
984- message = unifySpaces _message
985-
986- -- Given a name for the new binding, add a new pattern to the match in the last position,
987- -- returning how many patterns there were in this match prior to the transformation:
988- -- addArgToMatch "foo" `bar arg1 arg2 = ...`
989- -- => (`bar arg1 arg2 foo = ...`, 2)
990- addArgToMatch :: T. Text -> GenLocated l (Match GhcPs body ) -> (GenLocated l (Match GhcPs body ), Int )
991- addArgToMatch name (L locMatch (Match xMatch ctxMatch pats rhs)) =
992- let unqualName = mkRdrUnqual $ mkVarOcc $ T. unpack name
993- newPat = L (noAnnSrcSpanDP1 generatedSrcSpan) $ VarPat NoExtField (noLocA unqualName)
994- in (L locMatch (Match xMatch ctxMatch (pats <> [newPat]) rhs), length pats)
995-
996- -- Attempt to insert a binding pattern into each match for the given LHsDecl; succeeds only if the function is a FunBind.
997- -- Also return:
998- -- - the declaration's name
999- -- - the number of bound patterns in the declaration's matches prior to the transformation
1000- --
1001- -- For example:
1002- -- insertArg "new_pat" `foo bar baz = 1`
1003- -- => (`foo bar baz new_pat = 1`, Just ("foo", 2))
1004- appendFinalPatToMatches :: T. Text -> LHsDecl GhcPs -> TransformT (Either ResponseError ) (LHsDecl GhcPs , Maybe (GenLocated SrcSpanAnnN RdrName , Int ))
1005- appendFinalPatToMatches name = \ case
1006- (L locDecl (ValD xVal (FunBind xFunBind idFunBind mg coreFunBind))) -> do
1007- (mg', numPatsMay) <- modifyMgMatchesT' mg (pure . second Just . addArgToMatch name) Nothing combineMatchNumPats
1008- numPats <- lift $ maybeToEither (responseError " Unexpected empty match group in HsDecl" ) numPatsMay
1009- let decl' = L locDecl (ValD xVal (FunBind xFunBind idFunBind mg' coreFunBind))
1010- pure (decl', Just (idFunBind, numPats))
1011- decl -> pure (decl, Nothing )
1012- where
1013- combineMatchNumPats Nothing other = pure other
1014- combineMatchNumPats other Nothing = pure other
1015- combineMatchNumPats (Just l) (Just r)
1016- | l == r = pure (Just l)
1017- | otherwise = Left $ responseError " Unexpected different numbers of patterns in HsDecl MatchGroup"
1018-
1019- -- The add argument works as follows:
1020- -- 1. Attempt to add the given name as the last pattern of the declaration that contains `range`.
1021- -- 2. If such a declaration exists, use that declaration's name to modify the signature of said declaration, if it
1022- -- has a type signature.
1023- --
1024- -- NOTE For the following situation, the type signature is not updated (it's unclear what should happen):
1025- -- type FunctionTySyn = () -> Int
1026- -- foo :: FunctionTySyn
1027- -- foo () = new_def
1028- --
1029- -- TODO instead of inserting a typed hole; use GHC's suggested type from the error
1030- addArgumentAction :: ParsedModule -> Range -> T. Text -> Maybe T. Text -> Either ResponseError [(T. Text , [TextEdit ])]
1031- addArgumentAction (ParsedModule _ moduleSrc _ _) range name _typ = do
1032- (newSource, _, _) <- runTransformT $ do
1033- (moduleSrc', join -> matchedDeclNameMay) <- addNameAsLastArgOfMatchingDecl (makeDeltaAst moduleSrc)
1034- case matchedDeclNameMay of
1035- Just (matchedDeclName, numPats) -> modifySigWithM (unLoc matchedDeclName) (addTyHoleToTySigArg numPats) moduleSrc'
1036- Nothing -> pure moduleSrc'
1037- let diff = makeDiffTextEdit (T. pack $ exactPrint moduleSrc) (T. pack $ exactPrint newSource)
1038- pure [(" Add argument ‘" <> name <> " ’ to function" , fromLspList diff)]
1039- where
1040- addNameAsLastArgOfMatchingDecl = modifySmallestDeclWithM spanContainsRangeOrErr addNameAsLastArg
1041- addNameAsLastArg = fmap (first (: [] )) . appendFinalPatToMatches name
1042-
1043- spanContainsRangeOrErr = maybeToEither (responseError " SrcSpan was not valid range" ) . (`spanContainsRange` range)
1044-
1045- -- Transform an LHsType into a list of arguments and return type, to make transformations easier.
1046- hsTypeToFunTypeAsList :: LHsType GhcPs -> ([(SrcSpanAnnA , XFunTy GhcPs , HsArrow GhcPs , LHsType GhcPs )], LHsType GhcPs )
1047- hsTypeToFunTypeAsList = \ case
1048- L spanAnnA (HsFunTy xFunTy arrow lhs rhs) ->
1049- let (rhsArgs, rhsRes) = hsTypeToFunTypeAsList rhs
1050- in ((spanAnnA, xFunTy, arrow, lhs): rhsArgs, rhsRes)
1051- ty -> ([] , ty)
1052-
1053- -- The inverse of `hsTypeToFunTypeAsList`
1054- hsTypeFromFunTypeAsList :: ([(SrcSpanAnnA , XFunTy GhcPs , HsArrow GhcPs , LHsType GhcPs )], LHsType GhcPs ) -> LHsType GhcPs
1055- hsTypeFromFunTypeAsList (args, res) =
1056- foldr (\ (spanAnnA, xFunTy, arrow, argTy) res -> L spanAnnA $ HsFunTy xFunTy arrow argTy res) res args
1057-
1058- -- Add a typed hole to a type signature in the given argument position:
1059- -- 0 `foo :: ()` => foo :: _ -> ()
1060- -- 2 `foo :: FunctionTySyn` => foo :: FunctionTySyn
1061- -- 1 `foo :: () -> () -> Int` => foo :: () -> _ -> () -> Int
1062- addTyHoleToTySigArg :: Int -> LHsSigType GhcPs -> (LHsSigType GhcPs )
1063- addTyHoleToTySigArg loc (L annHsSig (HsSig xHsSig tyVarBndrs lsigTy)) =
1064- let (args, res) = hsTypeToFunTypeAsList lsigTy
1065- wildCardAnn = SrcSpanAnn (EpAnn genAnchor1 (AnnListItem [AddRarrowAnn d1]) emptyComments) generatedSrcSpan
1066- newArg = (SrcSpanAnn mempty generatedSrcSpan, noAnn, HsUnrestrictedArrow NormalSyntax , L wildCardAnn $ HsWildCardTy noExtField)
1067- -- NOTE if the location that the argument wants to be placed at is not one more than the number of arguments
1068- -- in the signature, then we return the original type signature.
1069- -- This situation most likely occurs due to a function type synonym in the signature
1070- insertArg n _ | n < 0 = error " Not possible"
1071- insertArg 0 as = newArg: as
1072- insertArg _ [] = []
1073- insertArg n (a: as) = a : insertArg (n - 1 ) as
1074- lsigTy' = hsTypeFromFunTypeAsList (insertArg loc args, res)
1075- in L annHsSig (HsSig xHsSig tyVarBndrs lsigTy')
1076-
1077- fromLspList :: List a -> [a ]
1078- fromLspList (List a) = a
1079- #endif
1080919
1081920suggestFillTypeWildcard :: Diagnostic -> [(T. Text , TextEdit )]
1082921suggestFillTypeWildcard Diagnostic {_range= _range,.. }
@@ -2169,29 +2008,16 @@ rangesForBinding' b (L (locA -> l) (IEThingWith _ thing _ inners))
21692008#endif
21702009rangesForBinding' _ _ = []
21712010
2172- -- | 'matchRegex' combined with 'unifySpaces'
2173- matchRegexUnifySpaces :: T. Text -> T. Text -> Maybe [T. Text ]
2174- matchRegexUnifySpaces message = matchRegex (unifySpaces message)
2175-
21762011-- | 'allMatchRegex' combined with 'unifySpaces'
21772012allMatchRegexUnifySpaces :: T. Text -> T. Text -> Maybe [[T. Text ]]
21782013allMatchRegexUnifySpaces message =
21792014 allMatchRegex (unifySpaces message)
21802015
2181- -- | Returns Just (the submatches) for the first capture, or Nothing.
2182- matchRegex :: T. Text -> T. Text -> Maybe [T. Text ]
2183- matchRegex message regex = case message =~~ regex of
2184- Just (_ :: T. Text , _ :: T. Text , _ :: T. Text , bindings ) -> Just bindings
2185- Nothing -> Nothing
2186-
21872016-- | Returns Just (all matches) for the first capture, or Nothing.
21882017allMatchRegex :: T. Text -> T. Text -> Maybe [[T. Text ]]
21892018allMatchRegex message regex = message =~~ regex
21902019
21912020
2192- unifySpaces :: T. Text -> T. Text
2193- unifySpaces = T. unwords . T. words
2194-
21952021-- functions to help parse multiple import suggestions
21962022
21972023-- | Returns the first match if found
0 commit comments