From 2fece7f7e26621de98afeaef31ea94450a035e80 Mon Sep 17 00:00:00 2001 From: Pepe Iborra Date: Wed, 2 Sep 2020 19:41:41 +0100 Subject: [PATCH] Suggest open imports (#740) Also fixes two bugs with qualified imports Fixes #480 --- src/Development/IDE/Plugin/CodeAction.hs | 15 ++++++++++----- test/exe/Main.hs | 5 +++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Development/IDE/Plugin/CodeAction.hs b/src/Development/IDE/Plugin/CodeAction.hs index 65245a0c..658d5789 100644 --- a/src/Development/IDE/Plugin/CodeAction.hs +++ b/src/Development/IDE/Plugin/CodeAction.hs @@ -311,7 +311,7 @@ suggestExportUnusedTopBinding srcOpt ParsedModule{pm_parsed_source = L _ HsModul $ hsmodDecls , Just pos <- _end . getLocatedRange <$> hsmodExports , Just needComma <- needsComma source <$> hsmodExports - , let exportName = (if needComma then "," else "") <> printExport exportType name + , let exportName = (if needComma then "," else "") <> printExport exportType name insertPos = pos {_character = pred $ _character pos} = [("Export ‘" <> name <> "’", [TextEdit (Range insertPos insertPos) exportName])] | otherwise = [] @@ -833,19 +833,24 @@ suggestNewImport _ _ _ = [] constructNewImportSuggestions :: PackageExportsMap -> NotInScope -> Maybe [T.Text] -> [T.Text] constructNewImportSuggestions exportsMap thingMissing notTheseModules = nubOrd - [ renderNewImport identInfo m + [ suggestion | (identInfo, m) <- fromMaybe [] $ Map.lookup name exportsMap , canUseIdent thingMissing identInfo , m `notElem` fromMaybe [] notTheseModules + , suggestion <- renderNewImport identInfo m ] where renderNewImport identInfo m - | Just q <- qual = "import qualified " <> m <> " as " <> q - | otherwise = "import " <> m <> " (" <> importWhat identInfo <> ")" + | Just q <- qual + , asQ <- if q == m then "" else " as " <> q + = ["import qualified " <> m <> asQ] + | otherwise + = ["import " <> m <> " (" <> importWhat identInfo <> ")" + ,"import " <> m ] (qual, name) = case T.splitOn "." (notInScope thingMissing) of [n] -> (Nothing, n) - segments -> (Just (T.concat $ init segments), last segments) + segments -> (Just (T.intercalate "." $ init segments), last segments) importWhat IdentInfo {parent, rendered} | Just p <- parent = p <> "(" <> rendered <> ")" | otherwise = rendered diff --git a/test/exe/Main.hs b/test/exe/Main.hs index 3b443b78..f67f2b38 100644 --- a/test/exe/Main.hs +++ b/test/exe/Main.hs @@ -1038,7 +1038,9 @@ suggestImportTests = testGroup "suggest import actions" [ test True [] "f = nonEmpty" [] "import Data.List.NonEmpty (nonEmpty)" , test True [] "f = (:|)" [] "import Data.List.NonEmpty (NonEmpty((:|)))" , test True [] "f :: Natural" ["f = undefined"] "import Numeric.Natural (Natural)" + , test True [] "f :: Natural" ["f = undefined"] "import Numeric.Natural" , test True [] "f :: NonEmpty ()" ["f = () :| []"] "import Data.List.NonEmpty (NonEmpty)" + , test True [] "f :: NonEmpty ()" ["f = () :| []"] "import Data.List.NonEmpty" , test True [] "f = First" [] "import Data.Monoid (First(First))" , test True [] "f = Endo" [] "import Data.Monoid (Endo(Endo))" , test True [] "f = Version" [] "import Data.Version (Version(Version))" @@ -1046,9 +1048,12 @@ suggestImportTests = testGroup "suggest import actions" , test True [] "f = AssertionFailed" [] "import Control.Exception (AssertionFailed(AssertionFailed))" , test True ["Prelude"] "f = nonEmpty" [] "import Data.List.NonEmpty (nonEmpty)" , test True [] "f :: Alternative f => f ()" ["f = undefined"] "import Control.Applicative (Alternative)" + , test True [] "f :: Alternative f => f ()" ["f = undefined"] "import Control.Applicative" , test True [] "f = empty" [] "import Control.Applicative (Alternative(empty))" + , test True [] "f = empty" [] "import Control.Applicative" , test True [] "f = (&)" [] "import Data.Function ((&))" , test True [] "f = NE.nonEmpty" [] "import qualified Data.List.NonEmpty as NE" + , test True [] "f = Data.List.NonEmpty.nonEmpty" [] "import qualified Data.List.NonEmpty" , test True [] "f :: Typeable a => a" ["f = undefined"] "import Data.Typeable (Typeable)" , test True [] "f = pack" [] "import Data.Text (pack)" , test True [] "f :: Text" ["f = undefined"] "import Data.Text (Text)"