@@ -116,7 +116,7 @@ codeAction lsp state (TextDocumentIdentifier uri) _range CodeActionContext{_diag
116116 | x <- xs
117117 , Just ps <- [annotatedPS]
118118 , Just dynflags <- [df]
119- , (title, graft) <- suggestExactAction dynflags ps x
119+ , (title, graft) <- suggestExactAction exportsMap dynflags ps x
120120 , let edit = either error id $
121121 rewriteToEdit dynflags uri (annsA ps) graft
122122 ]
@@ -173,14 +173,16 @@ commandHandler lsp _ideState ExecuteCommandParams{..}
173173 = return (Right Null , Nothing )
174174
175175suggestExactAction ::
176+ ExportsMap ->
176177 DynFlags ->
177178 Annotated ParsedSource ->
178179 Diagnostic ->
179180 [(T. Text , Rewrite )]
180- suggestExactAction df ps x =
181+ suggestExactAction exportsMap df ps x =
181182 concat
182183 [ suggestConstraint df (astA ps) x
183184 , suggestImplicitParameter (astA ps) x
185+ , suggestExtendImport exportsMap (astA ps) x
184186 ]
185187
186188suggestAction
@@ -193,7 +195,6 @@ suggestAction
193195suggestAction packageExports ideOptions parsedModule text diag = concat
194196 -- Order these suggestions by priority
195197 [ suggestSignature True diag
196- , suggestExtendImport packageExports text diag
197198 , suggestFillTypeWildcard diag
198199 , suggestFixConstructorImport text diag
199200 , suggestModuleTypo diag
@@ -725,32 +726,31 @@ getIndentedGroupsBy pred inp = case dropWhile (not.pred) inp of
725726indentation :: T. Text -> Int
726727indentation = T. length . T. takeWhile isSpace
727728
728- suggestExtendImport :: ExportsMap -> Maybe T. Text -> Diagnostic -> [(T. Text , [ TextEdit ] )]
729- suggestExtendImport exportsMap contents Diagnostic {_range= _range,.. }
729+ suggestExtendImport :: ExportsMap -> ParsedSource -> Diagnostic -> [(T. Text , Rewrite )]
730+ suggestExtendImport exportsMap ( L _ HsModule {hsmodImports}) Diagnostic {_range= _range,.. }
730731 | Just [binding, mod , srcspan] <-
731732 matchRegexUnifySpaces _message
732733 " Perhaps you want to add ‘([^’]*)’ to the import list in the import of ‘([^’]*)’ *\\ ((.*)\\ ).$"
733- , Just c <- contents
734- = suggestions c binding mod srcspan
734+ = suggestions hsmodImports binding mod srcspan
735735 | Just (binding, mod_srcspan) <-
736736 matchRegExMultipleImports _message
737- , Just c <- contents
738- = mod_srcspan >>= (\ (x, y) -> suggestions c binding x y)
737+ = mod_srcspan >>= uncurry (suggestions hsmodImports binding)
739738 | otherwise = []
740739 where
741- suggestions c binding mod srcspan
740+ unImportStyle (ImportTopLevel x) = (Nothing , T. unpack x)
741+ unImportStyle (ImportViaParent x y) = (Just $ T. unpack y, T. unpack x)
742+ suggestions decls binding mod srcspan
742743 | range <- case [ x | (x," " ) <- readSrcSpan (T. unpack srcspan)] of
743744 [s] -> let x = realSrcSpanToRange s
744745 in x{_end = (_end x){_character = succ (_character (_end x))}}
745746 _ -> error " bug in srcspan parser" ,
746- importLine <- textInRange range c ,
747+ Just decl <- findImportDeclByRange decls range ,
747748 Just ident <- lookupExportMap binding mod
748- = [ ( " Add " <> rendered <> " to the import list of " <> mod
749- , [ TextEdit range result]
749+ = [ ( " Add " <> renderImportStyle importStyle <> " to the import list of " <> mod
750+ , uncurry extendImport (unImportStyle importStyle) decl
750751 )
751752 | importStyle <- NE. toList $ importStyles ident
752- , let rendered = renderImportStyle importStyle
753- , result <- maybeToList $ addBindingToImportList importStyle importLine]
753+ ]
754754 | otherwise = []
755755 lookupExportMap binding mod
756756 | Just match <- Map. lookup binding (getExportsMap exportsMap)
@@ -765,6 +765,9 @@ suggestExtendImport exportsMap contents Diagnostic{_range=_range,..}
765765 , parent = Nothing
766766 , isDatacon = False }
767767
768+ findImportDeclByRange :: [LImportDecl GhcPs ] -> Range -> Maybe (LImportDecl GhcPs )
769+ findImportDeclByRange xs range = find (\ (L l _)-> srcSpanToRange l == Just range) xs
770+
768771suggestFixConstructorImport :: Maybe T. Text -> Diagnostic -> [(T. Text , [TextEdit ])]
769772suggestFixConstructorImport _ Diagnostic {_range= _range,.. }
770773 -- ‘Success’ is a data constructor of ‘Result’
@@ -1187,49 +1190,6 @@ rangesForBinding' b (L l (IEThingWith _ thing _ inners labels))
11871190 [ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b]
11881191rangesForBinding' _ _ = []
11891192
1190- -- | Extends an import list with a new binding.
1191- -- Assumes an import statement of the form:
1192- -- import (qualified) A (..) ..
1193- -- Places the new binding first, preserving whitespace.
1194- -- Copes with multi-line import lists
1195- addBindingToImportList :: ImportStyle -> T. Text -> Maybe T. Text
1196- addBindingToImportList importStyle importLine =
1197- case T. breakOn " (" importLine of
1198- (pre, T. uncons -> Just (_, rest)) ->
1199- case importStyle of
1200- ImportTopLevel rendered ->
1201- -- the binding has no parent, add it to the head of import list
1202- Just $ T. concat [pre, " (" , rendered, addCommaIfNeeds rest]
1203- ImportViaParent rendered parent -> case T. breakOn parent rest of
1204- -- the binding has a parent, and the current import list contains the
1205- -- parent
1206- --
1207- -- `rest'` could be 1. `,...)`
1208- -- or 2. `(),...)`
1209- -- or 3. `(ConsA),...)`
1210- -- or 4. `)`
1211- (leading, T. stripPrefix parent -> Just rest') -> case T. uncons (T. stripStart rest') of
1212- -- case 1: no children and parentheses, e.g. `import A(Foo,...)` --> `import A(Foo(Cons), ...)`
1213- Just (' ,' , rest'') -> Just $ T. concat [pre, " (" , leading, parent, " (" , rendered, " )" , addCommaIfNeeds rest'']
1214- -- case 2: no children but parentheses, e.g. `import A(Foo(),...)` --> `import A(Foo(Cons), ...)`
1215- Just (' (' , T. uncons -> Just (' )' , rest'')) -> Just $ T. concat [pre, " (" , leading, parent, " (" , rendered, " )" , rest'']
1216- -- case 3: children with parentheses, e.g. `import A(Foo(ConsA),...)` --> `import A(Foo(Cons, ConsA), ...)`
1217- Just (' (' , T. breakOn " )" -> (children, rest''))
1218- | not (T. null children),
1219- -- ignore A(Foo({-...-}), ...)
1220- not $ " {-" `T.isPrefixOf` T. stripStart children
1221- -> Just $ T. concat [pre, " (" , leading, parent, " (" , rendered, " , " , children, rest'']
1222- -- case 4: no trailing, e.g. `import A(..., Foo)` --> `import A(..., Foo(Cons))`
1223- Just (' )' , _) -> Just $ T. concat [pre, " (" , leading, parent, " (" , rendered, " )" , rest']
1224- _ -> Nothing
1225- -- current import list does not contain the parent, e.g. `import A(...)` --> `import A(Foo(Cons), ...)`
1226- _ -> Just $ T. concat [pre, " (" , parent, " (" , rendered, " )" , addCommaIfNeeds rest]
1227- _ -> Nothing
1228- where
1229- addCommaIfNeeds r = case T. uncons (T. stripStart r) of
1230- Just (' )' , _) -> r
1231- _ -> " , " <> r
1232-
12331193-- | 'matchRegex' combined with 'unifySpaces'
12341194matchRegexUnifySpaces :: T. Text -> T. Text -> Maybe [T. Text ]
12351195matchRegexUnifySpaces message = matchRegex (unifySpaces message)
@@ -1321,6 +1281,7 @@ data ImportStyle
13211281 --
13221282 -- @P@ and @?@ can be a data type and a constructor, a class and a method,
13231283 -- a class and an associated type/data family, etc.
1284+ deriving Show
13241285
13251286importStyles :: IdentInfo -> NonEmpty ImportStyle
13261287importStyles IdentInfo {parent, rendered, isDatacon}
0 commit comments