Skip to content

Commit 60476ab

Browse files
authored
Merge branch 'master' into extend-import-list-exactprint
2 parents 1b5b9b4 + 759901f commit 60476ab

File tree

4 files changed

+316
-33
lines changed

4 files changed

+316
-33
lines changed

ghcide/src/Development/IDE/Plugin/CodeAction.hs

Lines changed: 94 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import Bag (isEmptyBag)
6464
import qualified Data.HashSet as Set
6565
import Control.Concurrent.Extra (threadDelay, readVar)
6666
import Development.IDE.GHC.Util (printRdrName)
67+
import Ide.PluginUtils (subRange)
6768

6869
plugin :: Plugin c
6970
plugin = codeActionPluginWithRules rules codeAction <> Plugin mempty setHandlersCodeLens
@@ -107,8 +108,9 @@ codeAction lsp state (TextDocumentIdentifier uri) _range CodeActionContext{_diag
107108
[ mkCA title [x] edit
108109
| x <- xs, (title, tedit) <- suggestAction exportsMap ideOptions parsedModule text x
109110
, let edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
110-
] <> caRemoveRedundantImports parsedModule text diag xs uri
111-
111+
] <> caRemoveInvalidExports parsedModule text diag xs uri
112+
<> caRemoveRedundantImports parsedModule text diag xs uri
113+
112114
actions' =
113115
[mkCA title [x] edit
114116
| x <- xs
@@ -243,8 +245,8 @@ suggestRemoveRedundantImport ParsedModule{pm_parsed_source = L _ HsModule{hsmod
243245
| Just [_, bindings] <- matchRegexUnifySpaces _message "The( qualified)? import of ‘([^’]*)’ from module [^ ]* is redundant"
244246
, Just (L _ impDecl) <- find (\(L l _) -> srcSpanToRange l == Just _range ) hsmodImports
245247
, Just c <- contents
246-
, ranges <- map (rangesForBinding impDecl . T.unpack) (T.splitOn ", " bindings)
247-
, ranges' <- extendAllToIncludeCommaIfPossible (indexedByPosition $ T.unpack c) (concat ranges)
248+
, ranges <- map (rangesForBindingImport impDecl . T.unpack) (T.splitOn ", " bindings)
249+
, ranges' <- extendAllToIncludeCommaIfPossible False (indexedByPosition $ T.unpack c) (concat ranges)
248250
, not (null ranges')
249251
= [( "Remove " <> bindings <> " from import" , [ TextEdit r "" | r <- ranges' ] )]
250252

@@ -280,6 +282,69 @@ caRemoveRedundantImports m contents digs ctxDigs uri
280282
_edit = Just WorkspaceEdit{..}
281283
_command = Nothing
282284

285+
caRemoveInvalidExports :: Maybe ParsedModule -> Maybe T.Text -> [Diagnostic] -> [Diagnostic] -> Uri -> [CAResult]
286+
caRemoveInvalidExports m contents digs ctxDigs uri
287+
| Just pm <- m,
288+
Just txt <- contents,
289+
txt' <- indexedByPosition $ T.unpack txt,
290+
r <- mapMaybe (groupDiag pm) digs,
291+
r' <- map (\(t,d,rs) -> (t,d,extend txt' rs)) r,
292+
caRemoveCtx <- mapMaybe removeSingle r',
293+
allRanges <- nubOrd $ [ range | (_,_,ranges) <- r, range <- ranges],
294+
allRanges' <- extend txt' allRanges,
295+
Just caRemoveAll <- removeAll allRanges',
296+
ctxEdits <- [ x | x@(_, d, _) <- r, d `elem` ctxDigs],
297+
not $ null ctxEdits
298+
= caRemoveCtx ++ [caRemoveAll]
299+
| otherwise = []
300+
where
301+
extend txt ranges = extendAllToIncludeCommaIfPossible True txt ranges
302+
303+
groupDiag pm dig
304+
| Just (title, ranges) <- suggestRemoveRedundantExport pm dig
305+
= Just (title, dig, ranges)
306+
| otherwise = Nothing
307+
308+
removeSingle (_, _, []) = Nothing
309+
removeSingle (title, diagnostic, ranges) = Just $ CACodeAction CodeAction{..} where
310+
tedit = concatMap (\r -> [TextEdit r ""]) $ nubOrd ranges
311+
_changes = Just $ Map.singleton uri $ List tedit
312+
_title = title
313+
_kind = Just CodeActionQuickFix
314+
_diagnostics = Just $ List [diagnostic]
315+
_documentChanges = Nothing
316+
_edit = Just WorkspaceEdit{..}
317+
_command = Nothing
318+
removeAll [] = Nothing
319+
removeAll ranges = Just $ CACodeAction CodeAction {..} where
320+
tedit = concatMap (\r -> [TextEdit r ""]) ranges
321+
_changes = Just $ Map.singleton uri $ List tedit
322+
_title = "Remove all redundant exports"
323+
_kind = Just CodeActionQuickFix
324+
_diagnostics = Nothing
325+
_documentChanges = Nothing
326+
_edit = Just WorkspaceEdit{..}
327+
_command = Nothing
328+
329+
suggestRemoveRedundantExport :: ParsedModule -> Diagnostic -> Maybe (T.Text, [Range])
330+
suggestRemoveRedundantExport ParsedModule{pm_parsed_source = L _ HsModule{..}} Diagnostic{..}
331+
| msg <- unifySpaces _message
332+
, Just export <- hsmodExports
333+
, Just exportRange <- getLocatedRange export
334+
, exports <- unLoc export
335+
, Just (removeFromExport, !ranges) <- fmap (getRanges exports . notInScope) (extractNotInScopeName msg)
336+
<|> (,[_range]) <$> matchExportItem msg
337+
<|> (,[_range]) <$> matchDupExport msg
338+
, subRange _range exportRange
339+
= Just ("Remove ‘" <> removeFromExport <> "’ from export", ranges)
340+
where
341+
matchExportItem msg = regexSingleMatch msg "The export item ‘([^’]+)’"
342+
matchDupExport msg = regexSingleMatch msg "Duplicate ‘([^’]+)’ in export list"
343+
getRanges exports txt = case smallerRangesForBindingExport exports (T.unpack txt) of
344+
[] -> (txt, [_range])
345+
ranges -> (txt, ranges)
346+
suggestRemoveRedundantExport _ _ = Nothing
347+
283348
suggestDeleteUnusedBinding :: ParsedModule -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
284349
suggestDeleteUnusedBinding
285350
ParsedModule{pm_parsed_source = L _ HsModule{hsmodDecls}}
@@ -396,6 +461,9 @@ suggestDeleteUnusedBinding
396461
data ExportsAs = ExportName | ExportPattern | ExportAll
397462
deriving (Eq)
398463

464+
getLocatedRange :: Located a -> Maybe Range
465+
getLocatedRange = srcSpanToRange . getLoc
466+
399467
suggestExportUnusedTopBinding :: Maybe T.Text -> ParsedModule -> Diagnostic -> [(T.Text, [TextEdit])]
400468
suggestExportUnusedTopBinding srcOpt ParsedModule{pm_parsed_source = L _ HsModule{..}} Diagnostic{..}
401469
-- Foo.hs:4:1: warning: [-Wunused-top-binds] Defined but not used: ‘f’
@@ -436,9 +504,6 @@ suggestExportUnusedTopBinding srcOpt ParsedModule{pm_parsed_source = L _ HsModul
436504
| T.head x `elem` opLetter = (if needsTypeKeyword then "type " else "") <> "(" <> x <>")"
437505
| otherwise = x
438506

439-
getLocatedRange :: Located a -> Maybe Range
440-
getLocatedRange = srcSpanToRange . getLoc
441-
442507
matchWithDiagnostic :: Range -> Located (IdP GhcPs) -> Bool
443508
matchWithDiagnostic Range{_start=l,_end=r} x =
444509
let loc = fmap _start . getLocatedRange $ x
@@ -795,7 +860,10 @@ suggestInstanceConstraint df (L _ HsModule {hsmodDecls}) Diagnostic {..} missing
795860
= Nothing
796861

797862
readPositionNumber :: T.Text -> Int
798-
readPositionNumber = T.unpack >>> read
863+
readPositionNumber = T.unpack
864+
865+
866+
read
799867

800868
actionTitle :: T.Text -> T.Text
801869
actionTitle constraint = "Add `" <> constraint
@@ -1089,17 +1157,30 @@ textInRange (Range (Position startRow startCol) (Position endRow endCol)) text =
10891157
linesBeginningWithStartLine = drop startRow (T.splitOn "\n" text)
10901158

10911159
-- | Returns the ranges for a binding in an import declaration
1092-
rangesForBinding :: ImportDecl GhcPs -> String -> [Range]
1093-
rangesForBinding ImportDecl{ideclHiding = Just (False, L _ lies)} b =
1160+
rangesForBindingImport :: ImportDecl GhcPs -> String -> [Range]
1161+
rangesForBindingImport ImportDecl{ideclHiding = Just (False, L _ lies)} b =
10941162
concatMap (mapMaybe srcSpanToRange . rangesForBinding' b') lies
10951163
where
1096-
b' = wrapOperatorInParens (unqualify b)
1164+
b' = modifyBinding b
1165+
rangesForBindingImport _ _ = []
10971166

1167+
modifyBinding :: String -> String
1168+
modifyBinding = wrapOperatorInParens . unqualify
1169+
where
10981170
wrapOperatorInParens x = if isAlpha (head x) then x else "(" <> x <> ")"
1099-
11001171
unqualify x = snd $ breakOnEnd "." x
11011172

1102-
rangesForBinding _ _ = []
1173+
smallerRangesForBindingExport :: [LIE GhcPs] -> String -> [Range]
1174+
smallerRangesForBindingExport lies b =
1175+
concatMap (mapMaybe srcSpanToRange . ranges') lies
1176+
where
1177+
b' = modifyBinding b
1178+
ranges' (L _ (IEThingWith _ thing _ inners labels))
1179+
| showSDocUnsafe (ppr thing) == b' = []
1180+
| otherwise =
1181+
[ l' | L l' x <- inners, showSDocUnsafe (ppr x) == b'] ++
1182+
[ l' | L l' x <- labels, showSDocUnsafe (ppr x) == b']
1183+
ranges' _ = []
11031184

11041185
rangesForBinding' :: String -> LIE GhcPs -> [SrcSpan]
11051186
rangesForBinding' b (L l x@IEVar{}) | showSDocUnsafe (ppr x) == b = [l]

ghcide/src/Development/IDE/Plugin/CodeAction/PositionIndexed.hs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,27 @@ mergeRanges other = other
8383
-- a, b, |c| ===> a, b|, c|
8484
-- a, |b|, |c| ===> a|, b||, c|
8585
-- @
86-
extendAllToIncludeCommaIfPossible :: PositionIndexedString -> [Range] -> [Range]
87-
extendAllToIncludeCommaIfPossible indexedString =
86+
--
87+
-- If 'acceptNoComma' is enabled, additional ranges are returned
88+
--
89+
-- @
90+
-- |a| ===> |a|
91+
-- |a|, |b| ===> |a,| |b|
92+
-- @
93+
extendAllToIncludeCommaIfPossible :: Bool -> PositionIndexedString -> [Range] -> [Range]
94+
extendAllToIncludeCommaIfPossible acceptNoComma indexedString =
8895
mergeRanges . go indexedString . sortOn _start
8996
where
9097
go _ [] = []
9198
go input (r : rr)
92-
| r' : _ <- extendToIncludeCommaIfPossible input r
99+
| r' : _ <- extendToIncludeCommaIfPossible acceptNoComma input r
93100
, Just input' <- stripRange r' input
94101
= r' : go input' rr
95102
| otherwise
96103
= go input rr
97104

98-
extendToIncludeCommaIfPossible :: PositionIndexedString -> Range -> [Range]
99-
extendToIncludeCommaIfPossible indexedString range
105+
extendToIncludeCommaIfPossible :: Bool -> PositionIndexedString -> Range -> [Range]
106+
extendToIncludeCommaIfPossible acceptNoComma indexedString range
100107
| Just (before, _, after) <- unconsRange range indexedString
101108
, after' <- dropWhile (isSpace . snd) after
102109
, before' <- dropWhile (isSpace . snd) (reverse before)
@@ -109,6 +116,8 @@ extendToIncludeCommaIfPossible indexedString range
109116
| (_, ',') : rest <- [after']
110117
, (end', _) : _ <- pure $ dropWhile (isSpace . snd) rest
111118
]
119+
++
120+
([range | acceptNoComma])
112121
| otherwise
113122
= [range]
114123

0 commit comments

Comments
 (0)