Skip to content
This repository was archived by the owner on Jan 2, 2021. It is now read-only.

Support extending constructors #916

Merged
merged 9 commits into from
Dec 6, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions src/Development/IDE/Plugin/CodeAction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import Development.IDE.Core.RuleTypes
import Development.IDE.Core.Service
import Development.IDE.Core.Shake
import Development.IDE.GHC.Error
import Development.IDE.GHC.Util
import Development.IDE.LSP.Server
import Development.IDE.Plugin.CodeAction.PositionIndexed
import Development.IDE.Plugin.CodeAction.RuleTypes
Expand All @@ -50,8 +49,6 @@ import Data.Maybe
import Data.List.Extra
import qualified Data.Text as T
import Data.Tuple.Extra ((&&&))
import HscTypes
import Parser
import Text.Regex.TDFA (mrAfter, (=~), (=~~))
import Outputable (ppr, showSDocUnsafe)
import GHC.LanguageExtensions.Type (Extension)
Expand Down Expand Up @@ -98,10 +95,9 @@ codeAction lsp state (TextDocumentIdentifier uri) _range CodeActionContext{_diag
pkgExports <- runAction "CodeAction:PackageExports" state $ (useNoFile_ . PackageExports) `traverse` env
localExports <- readVar (exportsMap $ shakeExtras state)
let exportsMap = localExports <> fromMaybe mempty pkgExports
let dflags = hsc_dflags . hscEnv <$> env
pure . Right $
[ CACodeAction $ CodeAction title (Just CodeActionQuickFix) (Just $ List [x]) (Just edit) Nothing
| x <- xs, (title, tedit) <- suggestAction dflags exportsMap ideOptions parsedModule text x
| x <- xs, (title, tedit) <- suggestAction exportsMap ideOptions parsedModule text x
, let edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
] <> caRemoveRedundantImports parsedModule text diag xs uri

Expand Down Expand Up @@ -152,18 +148,17 @@ commandHandler lsp _ideState ExecuteCommandParams{..}
= return (Right Null, Nothing)

suggestAction
:: Maybe DynFlags
-> ExportsMap
:: ExportsMap
-> IdeOptions
-> Maybe ParsedModule
-> Maybe T.Text
-> Diagnostic
-> [(T.Text, [TextEdit])]
suggestAction dflags packageExports ideOptions parsedModule text diag = concat
suggestAction packageExports ideOptions parsedModule text diag = concat
-- Order these suggestions by priority
[ suggestAddExtension diag -- Highest priority
, suggestSignature True diag
, suggestExtendImport dflags text diag
, suggestExtendImport packageExports text diag
, suggestFillTypeWildcard diag
, suggestFixConstructorImport text diag
, suggestModuleTypo diag
Expand Down Expand Up @@ -642,22 +637,25 @@ getIndentedGroupsBy pred inp = case dropWhile (not.pred) inp of
indentation :: T.Text -> Int
indentation = T.length . T.takeWhile isSpace

suggestExtendImport :: Maybe DynFlags -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
suggestExtendImport (Just dflags) contents Diagnostic{_range=_range,..}
suggestExtendImport :: ExportsMap -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
suggestExtendImport exportsMap contents Diagnostic{_range=_range,..}
| Just [binding, mod, srcspan] <-
matchRegexUnifySpaces _message
"Perhaps you want to add ‘([^’]*)’ to the import list in the import of ‘([^’]*)’ *\\((.*)\\).$"
, Just c <- contents
, POk _ (L _ name) <- runParser dflags (T.unpack binding) parseIdentifier
, [(renderImport -> renderedBinding, _)] <- filter (\(_,m) -> mod == m) $ maybe [] Set.toList $ Map.lookup binding (getExportsMap exportsMap)
= let range = case [ x | (x,"") <- readSrcSpan (T.unpack srcspan)] of
[s] -> let x = realSrcSpanToRange s
in x{_end = (_end x){_character = succ (_character (_end x))}}
_ -> error "bug in srcspan parser"
importLine = textInRange range c
in [("Add " <> binding <> " to the import list of " <> mod
, [TextEdit range (addBindingToImportList (T.pack $ printRdrName name) importLine)])]
in [("Add " <> renderedBinding <> " to the import list of " <> mod
, [TextEdit range (addBindingToImportList renderedBinding importLine)])]
| otherwise = []
suggestExtendImport Nothing _ _ = []
where
renderImport IdentInfo {parent, rendered}
| Just p <- parent = p <> "(" <> rendered <> ")"
| otherwise = rendered

suggestFixConstructorImport :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
suggestFixConstructorImport _ Diagnostic{_range=_range,..}
Expand Down
6 changes: 3 additions & 3 deletions test/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,7 @@ extendImportTests = testGroup "extend import actions"
, "main = print (stuffB .* stuffB)"
])
(Range (Position 3 17) (Position 3 18))
"Add .* to the import list of ModuleA"
"Add (.*) to the import list of ModuleA"
(T.unlines
[ "module ModuleB where"
, "import ModuleA as A ((.*), stuffB)"
Expand All @@ -1012,7 +1012,7 @@ extendImportTests = testGroup "extend import actions"
, "b :: A"
, "b = 0"
])
, (`xfail` "known broken") $ testSession "extend single line import with constructor" $ template
, testSession "extend single line import with constructor" $ template
(T.unlines
[ "module ModuleA where"
, "data A = Constructor"
Expand All @@ -1024,7 +1024,7 @@ extendImportTests = testGroup "extend import actions"
, "b = Constructor"
])
(Range (Position 2 5) (Position 2 5))
"Add Constructor to the import list of ModuleA"
"Add A(Constructor) to the import list of ModuleA"
(T.unlines
[ "module ModuleB where"
, "import ModuleA (A(Constructor))"
Expand Down