{-# LANGUAGE MultiWayIf        #-}
{-# LANGUAGE NamedFieldPuns    #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms   #-}
{-# LANGUAGE RecordWildCards   #-}
{-# LANGUAGE ViewPatterns      #-}

module Ide.Plugin.QualifyImportedNames (descriptor) where

import           Control.Lens                     ((^.))
import           Control.Monad                    (foldM)
import           Control.Monad.IO.Class           (MonadIO (liftIO))
import           Control.Monad.Trans.State.Strict (State)
import qualified Control.Monad.Trans.State.Strict as State
import           Data.DList                       (DList)
import qualified Data.DList                       as DList
import           Data.Foldable                    (Foldable (foldl'), find)
import qualified Data.HashMap.Strict              as HashMap
import           Data.List                        (sortOn)
import qualified Data.List                        as List
import qualified Data.Map.Strict                  as Map
import           Data.Maybe                       (fromMaybe, isJust, mapMaybe)
import           Data.Text                        (Text)
import qualified Data.Text                        as Text
import           Development.IDE                  (spanContainsRange)
import           Development.IDE.Core.PluginUtils
import           Development.IDE.Core.RuleTypes   (GetFileContents (GetFileContents),
                                                   GetHieAst (GetHieAst),
                                                   HieAstResult (HAR, refMap),
                                                   TcModuleResult (TcModuleResult, tmrParsed, tmrTypechecked),
                                                   TypeCheck (TypeCheck))
import           Development.IDE.Core.Service     (runAction)
import           Development.IDE.Core.Shake       (IdeState, use)
import           Development.IDE.GHC.Compat       (ContextInfo (Use),
                                                   GenLocated (..), GhcPs,
                                                   GlobalRdrElt, GlobalRdrEnv,
                                                   HsModule (hsmodImports),
                                                   Identifier,
                                                   IdentifierDetails (IdentifierDetails, identInfo),
                                                   ImpDeclSpec (ImpDeclSpec, is_as, is_dloc, is_qual),
                                                   ImportSpec (ImpSpec),
                                                   LImportDecl, ModuleName,
                                                   Name, NameEnv, OccName,
                                                   ParsedModule, RefMap, Span,
                                                   SrcSpan,
                                                   TcGblEnv (tcg_rdr_env),
                                                   emptyUFM, globalRdrEnvElts,
                                                   gre_imp, gre_name, locA,
                                                   lookupNameEnv,
                                                   moduleNameString,
                                                   nameOccName, occNameString,
                                                   pattern GRE,
                                                   pattern ParsedModule,
                                                   plusUFM_C, pm_parsed_source,
                                                   srcSpanEndCol,
                                                   srcSpanEndLine,
                                                   srcSpanStartCol,
                                                   srcSpanStartLine, unitUFM)
import           Development.IDE.GHC.Error        (isInsideSrcSpan)
import           Development.IDE.Types.Location   (NormalizedFilePath,
                                                   Position (Position),
                                                   Range (Range), Uri,
                                                   toNormalizedUri)
import           Ide.Plugin.Error                 (PluginError (PluginRuleFailed),
                                                   getNormalizedFilePathE,
                                                   handleMaybe, handleMaybeM)
import           Ide.Types                        (PluginDescriptor (pluginHandlers),
                                                   PluginId,
                                                   PluginMethodHandler,
                                                   defaultPluginDescriptor,
                                                   mkPluginHandler)
import qualified Language.LSP.Protocol.Lens       as L
import           Language.LSP.Protocol.Message    (Method (Method_TextDocumentCodeAction),
                                                   SMethod (SMethod_TextDocumentCodeAction))
import           Language.LSP.Protocol.Types      (CodeAction (CodeAction, _command, _data_, _diagnostics, _disabled, _edit, _isPreferred, _kind, _title),
                                                   CodeActionKind (CodeActionKind_QuickFix),
                                                   CodeActionParams (CodeActionParams),
                                                   TextDocumentIdentifier (TextDocumentIdentifier),
                                                   TextEdit (TextEdit),
                                                   WorkspaceEdit (WorkspaceEdit, _changeAnnotations, _changes, _documentChanges),
                                                   type (|?) (InL, InR),
                                                   uriToNormalizedFilePath)

thenCmp :: Ordering -> Ordering -> Ordering
{-# INLINE thenCmp #-}
thenCmp :: Ordering -> Ordering -> Ordering
thenCmp Ordering
EQ       Ordering
ordering = Ordering
ordering
thenCmp Ordering
ordering Ordering
_        = Ordering
ordering

descriptor :: PluginId -> PluginDescriptor IdeState
descriptor :: PluginId -> PluginDescriptor IdeState
descriptor PluginId
pluginId = (forall ideState. PluginId -> PluginDescriptor ideState
defaultPluginDescriptor PluginId
pluginId) {
  pluginHandlers :: PluginHandlers IdeState
pluginHandlers = forall a. Monoid a => [a] -> a
mconcat
    [ forall ideState (m :: Method 'ClientToServer 'Request).
PluginRequestMethod m =>
SClientMethod m
-> PluginMethodHandler ideState m -> PluginHandlers ideState
mkPluginHandler SMethod 'Method_TextDocumentCodeAction
SMethod_TextDocumentCodeAction PluginMethodHandler IdeState 'Method_TextDocumentCodeAction
codeActionProvider
    ]
}

findLImportDeclAt :: Range -> ParsedModule -> Maybe (LImportDecl GhcPs)
findLImportDeclAt :: Range -> ParsedModule -> Maybe (LImportDecl GhcPs)
findLImportDeclAt Range
range ParsedModule
parsedModule
  | ParsedModule {ParsedSource
pm_parsed_source :: ParsedSource
pm_parsed_source :: ParsedModule -> ParsedSource
..} <- ParsedModule
parsedModule
  , L SrcSpan
_ HsModule
hsModule <- ParsedSource
pm_parsed_source
  , [LImportDecl GhcPs]
locatedImportDecls <- HsModule -> [LImportDecl GhcPs]
hsmodImports HsModule
hsModule =
      forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (\ (L (forall a. SrcSpanAnn' a -> SrcSpan
locA -> SrcSpan
srcSpan) ImportDecl GhcPs
_) -> forall a. a -> Maybe a -> a
fromMaybe Bool
False forall a b. (a -> b) -> a -> b
$ SrcSpan
srcSpan SrcSpan -> Range -> Maybe Bool
`spanContainsRange` Range
range) [LImportDecl GhcPs]
locatedImportDecls

makeCodeActions :: Uri -> [TextEdit] -> [a |? CodeAction]
makeCodeActions :: forall a. Uri -> [TextEdit] -> [a |? CodeAction]
makeCodeActions Uri
uri [TextEdit]
textEdits = [forall a b. b -> a |? b
InR CodeAction {Maybe WorkspaceEdit
Maybe CodeActionKind
Text
forall {a}. Maybe a
_data_ :: forall {a}. Maybe a
_disabled :: forall {a}. Maybe a
_isPreferred :: forall {a}. Maybe a
_diagnostics :: forall {a}. Maybe a
_edit :: Maybe WorkspaceEdit
_command :: forall {a}. Maybe a
_kind :: Maybe CodeActionKind
_title :: Text
$sel:_title:CodeAction :: Text
$sel:_kind:CodeAction :: Maybe CodeActionKind
$sel:_isPreferred:CodeAction :: Maybe Bool
$sel:_edit:CodeAction :: Maybe WorkspaceEdit
$sel:_disabled:CodeAction :: Maybe (Rec (("reason" .== Text) .+ Empty))
$sel:_diagnostics:CodeAction :: Maybe [Diagnostic]
$sel:_data_:CodeAction :: Maybe Value
$sel:_command:CodeAction :: Maybe Command
..} | Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [TextEdit]
textEdits)]
  where _title :: Text
_title = Text
"Qualify imported names"
        _kind :: Maybe CodeActionKind
_kind = forall a. a -> Maybe a
Just CodeActionKind
CodeActionKind_QuickFix
        _command :: Maybe a
_command = forall {a}. Maybe a
Nothing
        _edit :: Maybe WorkspaceEdit
_edit = forall a. a -> Maybe a
Just WorkspaceEdit {Maybe (Map Uri [TextEdit])
forall {a}. Maybe a
_changeAnnotations :: forall {a}. Maybe a
_documentChanges :: forall {a}. Maybe a
_changes :: Maybe (Map Uri [TextEdit])
$sel:_documentChanges:WorkspaceEdit :: Maybe
  [TextDocumentEdit |? (CreateFile |? (RenameFile |? DeleteFile))]
$sel:_changes:WorkspaceEdit :: Maybe (Map Uri [TextEdit])
$sel:_changeAnnotations:WorkspaceEdit :: Maybe (Map ChangeAnnotationIdentifier ChangeAnnotation)
..}
        _changes :: Maybe (Map Uri [TextEdit])
_changes = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall k a. k -> a -> Map k a
Map.singleton Uri
uri [TextEdit]
textEdits
        _documentChanges :: Maybe a
_documentChanges = forall {a}. Maybe a
Nothing
        _diagnostics :: Maybe a
_diagnostics = forall {a}. Maybe a
Nothing
        _isPreferred :: Maybe a
_isPreferred = forall {a}. Maybe a
Nothing
        _disabled :: Maybe a
_disabled = forall {a}. Maybe a
Nothing
        _data_ :: Maybe a
_data_ = forall {a}. Maybe a
Nothing
        _changeAnnotations :: Maybe a
_changeAnnotations = forall {a}. Maybe a
Nothing

data ImportedBy = ImportedBy {
  ImportedBy -> ModuleName
importedByAlias   :: !ModuleName,
  ImportedBy -> SrcSpan
importedBySrcSpan :: !SrcSpan
}

isRangeWithinImportedBy :: Range -> ImportedBy -> Bool
isRangeWithinImportedBy :: Range -> ImportedBy -> Bool
isRangeWithinImportedBy Range
range (ImportedBy ModuleName
_ SrcSpan
srcSpan) = forall a. a -> Maybe a -> a
fromMaybe Bool
False forall a b. (a -> b) -> a -> b
$ SrcSpan -> Range -> Maybe Bool
spanContainsRange SrcSpan
srcSpan Range
range

globalRdrEnvToNameToImportedByMap :: GlobalRdrEnv -> NameEnv [ImportedBy]
globalRdrEnvToNameToImportedByMap :: GlobalRdrEnv -> NameEnv [ImportedBy]
globalRdrEnvToNameToImportedByMap =
  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. DList a -> [a]
DList.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (forall elt key.
(elt -> elt -> elt)
-> UniqFM key elt -> UniqFM key elt -> UniqFM key elt
plusUFM_C forall a. Semigroup a => a -> a -> a
(<>)) forall key elt. UniqFM key elt
emptyUFM forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map GlobalRdrElt -> UniqFM Name (DList ImportedBy)
globalRdrEltToNameToImportedByMap forall b c a. (b -> c) -> (a -> b) -> a -> c
. GlobalRdrEnv -> [GlobalRdrElt]
globalRdrEnvElts
  where
    globalRdrEltToNameToImportedByMap :: GlobalRdrElt -> NameEnv (DList ImportedBy)
    globalRdrEltToNameToImportedByMap :: GlobalRdrElt -> UniqFM Name (DList ImportedBy)
globalRdrEltToNameToImportedByMap GRE {[ImportSpec]
Name
gre_imp :: [ImportSpec]
gre_name :: Name
gre_name :: GlobalRdrElt -> Name
gre_imp :: GlobalRdrElt -> [ImportSpec]
..} =
      forall key elt. Uniquable key => key -> elt -> UniqFM key elt
unitUFM Name
gre_name forall a b. (a -> b) -> a -> b
$ forall a. [a] -> DList a
DList.fromList forall a b. (a -> b) -> a -> b
$ forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ImportSpec -> Maybe ImportedBy
importSpecToImportedBy [ImportSpec]
gre_imp

    importSpecToImportedBy :: ImportSpec -> Maybe ImportedBy
    importSpecToImportedBy :: ImportSpec -> Maybe ImportedBy
importSpecToImportedBy (ImpSpec ImpDeclSpec {Bool
SrcSpan
ModuleName
is_dloc :: SrcSpan
is_qual :: Bool
is_as :: ModuleName
is_qual :: ImpDeclSpec -> Bool
is_dloc :: ImpDeclSpec -> SrcSpan
is_as :: ImpDeclSpec -> ModuleName
..} ImpItemSpec
_)
      | Bool
is_qual = forall {a}. Maybe a
Nothing
      | Bool
otherwise = forall a. a -> Maybe a
Just (ModuleName -> SrcSpan -> ImportedBy
ImportedBy ModuleName
is_as SrcSpan
is_dloc)

data IdentifierSpan = IdentifierSpan {
  IdentifierSpan -> Int
identifierSpanLine     :: !Int,
  IdentifierSpan -> Int
identifierSpanStartCol :: !Int,
  IdentifierSpan -> Int
identifierSpanEndCol   :: !Int
} deriving (Int -> IdentifierSpan -> ShowS
[IdentifierSpan] -> ShowS
IdentifierSpan -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IdentifierSpan] -> ShowS
$cshowList :: [IdentifierSpan] -> ShowS
show :: IdentifierSpan -> String
$cshow :: IdentifierSpan -> String
showsPrec :: Int -> IdentifierSpan -> ShowS
$cshowsPrec :: Int -> IdentifierSpan -> ShowS
Show, IdentifierSpan -> IdentifierSpan -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IdentifierSpan -> IdentifierSpan -> Bool
$c/= :: IdentifierSpan -> IdentifierSpan -> Bool
== :: IdentifierSpan -> IdentifierSpan -> Bool
$c== :: IdentifierSpan -> IdentifierSpan -> Bool
Eq)

instance Ord IdentifierSpan where
  compare :: IdentifierSpan -> IdentifierSpan -> Ordering
compare (IdentifierSpan Int
line1 Int
startCol1 Int
endCol1) (IdentifierSpan Int
line2 Int
startCol2 Int
endCol2) =
    (Int
line1 forall a. Ord a => a -> a -> Ordering
`compare` Int
line2) Ordering -> Ordering -> Ordering
`thenCmp` (Int
startCol1 forall a. Ord a => a -> a -> Ordering
`compare` Int
startCol2) Ordering -> Ordering -> Ordering
`thenCmp` (Int
endCol1 forall a. Ord a => a -> a -> Ordering
`compare` Int
endCol2)

realSrcSpanToIdentifierSpan :: Span -> Maybe IdentifierSpan
realSrcSpanToIdentifierSpan :: Span -> Maybe IdentifierSpan
realSrcSpanToIdentifierSpan Span
realSrcSpan
  | let startLine :: Int
startLine = Span -> Int
srcSpanStartLine Span
realSrcSpan forall a. Num a => a -> a -> a
- Int
1
  , let endLine :: Int
endLine = Span -> Int
srcSpanEndLine Span
realSrcSpan forall a. Num a => a -> a -> a
- Int
1
  , Int
startLine forall a. Eq a => a -> a -> Bool
== Int
endLine
  , let startCol :: Int
startCol = Span -> Int
srcSpanStartCol Span
realSrcSpan forall a. Num a => a -> a -> a
- Int
1
  , let endCol :: Int
endCol = Span -> Int
srcSpanEndCol Span
realSrcSpan forall a. Num a => a -> a -> a
- Int
1 =
      forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int -> IdentifierSpan
IdentifierSpan Int
startLine Int
startCol Int
endCol
  | Bool
otherwise = forall {a}. Maybe a
Nothing

identifierSpanToRange :: IdentifierSpan -> Range
identifierSpanToRange :: IdentifierSpan -> Range
identifierSpanToRange (IdentifierSpan Int
line Int
startCol Int
endCol) =
  Position -> Position -> Range
Range (UInt -> UInt -> Position
Position (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
line) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
startCol)) (UInt -> UInt -> Position
Position (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
line) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
endCol))

data UsedIdentifier = UsedIdentifier {
  UsedIdentifier -> Name
usedIdentifierName :: !Name,
  UsedIdentifier -> IdentifierSpan
usedIdentifierSpan :: !IdentifierSpan
}

refMapToUsedIdentifiers :: RefMap a -> [UsedIdentifier]
refMapToUsedIdentifiers :: forall a. RefMap a -> [UsedIdentifier]
refMapToUsedIdentifiers = forall a. DList a -> [a]
DList.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a k b. (a -> k -> b -> a) -> a -> Map k b -> a
Map.foldlWithKey' forall {a}.
DList UsedIdentifier
-> Identifier
-> [(Span, IdentifierDetails a)]
-> DList UsedIdentifier
folder forall a. DList a
DList.empty
  where
    folder :: DList UsedIdentifier
-> Identifier
-> [(Span, IdentifierDetails a)]
-> DList UsedIdentifier
folder DList UsedIdentifier
acc Identifier
identifier [(Span, IdentifierDetails a)]
spanIdentifierDetailsPairs =
      forall a. [a] -> DList a
DList.fromList (forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (forall a.
Identifier -> Span -> IdentifierDetails a -> Maybe UsedIdentifier
getUsedIdentifier Identifier
identifier)) [(Span, IdentifierDetails a)]
spanIdentifierDetailsPairs) forall a. Semigroup a => a -> a -> a
<> DList UsedIdentifier
acc

    getUsedIdentifier :: Identifier -> Span -> IdentifierDetails a -> Maybe UsedIdentifier
    getUsedIdentifier :: forall a.
Identifier -> Span -> IdentifierDetails a -> Maybe UsedIdentifier
getUsedIdentifier Identifier
identifier Span
span IdentifierDetails {Set ContextInfo
identInfo :: Set ContextInfo
identInfo :: forall a. IdentifierDetails a -> Set ContextInfo
..}
      | Just IdentifierSpan
identifierSpan <- Span -> Maybe IdentifierSpan
realSrcSpanToIdentifierSpan Span
span
      , Right Name
name <- Identifier
identifier
      , ContextInfo
Use forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Set ContextInfo
identInfo = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Name -> IdentifierSpan -> UsedIdentifier
UsedIdentifier Name
name IdentifierSpan
identifierSpan
      | Bool
otherwise = forall {a}. Maybe a
Nothing

occNameToText :: OccName -> Text
occNameToText :: OccName -> Text
occNameToText = String -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. OccName -> String
occNameString

updateColOffset :: Int -> Int -> Int -> Int
updateColOffset :: Int -> Int -> Int -> Int
updateColOffset Int
row Int
lineOffset Int
colOffset
  | Int
row forall a. Eq a => a -> a -> Bool
== Int
lineOffset = Int
colOffset
  | Bool
otherwise = Int
0

usedIdentifiersToTextEdits :: Range -> NameEnv [ImportedBy] -> Text -> [UsedIdentifier] -> [TextEdit]
usedIdentifiersToTextEdits :: Range
-> NameEnv [ImportedBy] -> Text -> [UsedIdentifier] -> [TextEdit]
usedIdentifiersToTextEdits Range
range NameEnv [ImportedBy]
nameToImportedByMap Text
sourceText [UsedIdentifier]
usedIdentifiers
  | let sortedUsedIdentifiers :: [UsedIdentifier]
sortedUsedIdentifiers = forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn UsedIdentifier -> IdentifierSpan
usedIdentifierSpan [UsedIdentifier]
usedIdentifiers =
      forall s a. State s a -> s -> a
State.evalState ([UsedIdentifier] -> State ([Text], Int, Int) [TextEdit]
makeStateComputation [UsedIdentifier]
sortedUsedIdentifiers) (Text -> [Text]
Text.lines Text
sourceText, Int
0, Int
0)
  where
    folder :: [TextEdit] -> UsedIdentifier -> State ([Text], Int, Int) [TextEdit]
    folder :: [TextEdit] -> UsedIdentifier -> State ([Text], Int, Int) [TextEdit]
folder [TextEdit]
prevTextEdits (UsedIdentifier Name
identifierName IdentifierSpan
identifierSpan)
      | Just [ImportedBy]
importedBys <- forall a. NameEnv a -> Name -> Maybe a
lookupNameEnv NameEnv [ImportedBy]
nameToImportedByMap Name
identifierName
      , Just (ImportedBy ModuleName
alias SrcSpan
_) <- forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (Range -> ImportedBy -> Bool
isRangeWithinImportedBy Range
range) [ImportedBy]
importedBys
      , let IdentifierSpan Int
row Int
startCol Int
endCol = IdentifierSpan
identifierSpan
      , let identifierRange :: Range
identifierRange = IdentifierSpan -> Range
identifierSpanToRange IdentifierSpan
identifierSpan
      , let aliasText :: Text
aliasText = String -> Text
Text.pack forall a b. (a -> b) -> a -> b
$ ModuleName -> String
moduleNameString ModuleName
alias
      , let identifierText :: Text
identifierText = String -> Text
Text.pack forall a b. (a -> b) -> a -> b
$ OccName -> String
occNameString forall a b. (a -> b) -> a -> b
$ Name -> OccName
nameOccName Name
identifierName
      , let qualifiedIdentifierText :: Text
qualifiedIdentifierText = Text
aliasText forall a. Semigroup a => a -> a -> a
<> Text
"." forall a. Semigroup a => a -> a -> a
<> Text
identifierText = do
          ([Text]
sourceTextLines, Int
lineOffset, Int -> Int -> Int -> Int
updateColOffset Int
row Int
lineOffset -> Int
colOffset) <- forall (m :: * -> *) s. Monad m => StateT s m s
State.get
          let lines :: [Text]
lines = forall a. Int -> [a] -> [a]
List.drop (Int
row forall a. Num a => a -> a -> a
- Int
lineOffset) [Text]
sourceTextLines
          let (Text
replacementText, [Text]
remainingLines) =
                if | Text
line : [Text]
remainingLines <- [Text]
lines
                   , let lineStartingAtIdentifier :: Text
lineStartingAtIdentifier = Int -> Text -> Text
Text.drop (Int
startCol forall a. Num a => a -> a -> a
- Int
colOffset) Text
line
                   , Just (Char
c, Text
_) <- Text -> Maybe (Char, Text)
Text.uncons Text
lineStartingAtIdentifier
                   , let isParenthesized :: Bool
isParenthesized = Char
c forall a. Eq a => a -> a -> Bool
== Char
'('
                   , let isBackticked :: Bool
isBackticked = Char
c forall a. Eq a => a -> a -> Bool
== Char
'`'
                   , let replacementText :: Text
replacementText =
                           if | Bool
isParenthesized -> Text
"(" forall a. Semigroup a => a -> a -> a
<> Text
qualifiedIdentifierText forall a. Semigroup a => a -> a -> a
<> Text
")"
                              | Bool
isBackticked -> Text
"`" forall a. Semigroup a => a -> a -> a
<> Text
qualifiedIdentifierText forall a. Semigroup a => a -> a -> a
<> Text
"`"
                              | Bool
otherwise -> Text
qualifiedIdentifierText ->
                       (Text
replacementText, Text
lineStartingAtIdentifier forall a. a -> [a] -> [a]
: [Text]
remainingLines)
                   | Bool
otherwise -> (Text
qualifiedIdentifierText, [Text]
lines)
          let textEdit :: TextEdit
textEdit = Range -> Text -> TextEdit
TextEdit Range
identifierRange Text
replacementText
          forall (m :: * -> *) s. Monad m => s -> StateT s m ()
State.put ([Text]
remainingLines, Int
row, Int
startCol)
          forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ TextEdit
textEdit forall a. a -> [a] -> [a]
: [TextEdit]
prevTextEdits
      | Bool
otherwise = forall (f :: * -> *) a. Applicative f => a -> f a
pure [TextEdit]
prevTextEdits

    makeStateComputation :: [UsedIdentifier] -> State ([Text], Int, Int) [TextEdit]
    makeStateComputation :: [UsedIdentifier] -> State ([Text], Int, Int) [TextEdit]
makeStateComputation [UsedIdentifier]
usedIdentifiers = forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM [TextEdit] -> UsedIdentifier -> State ([Text], Int, Int) [TextEdit]
folder [] [UsedIdentifier]
usedIdentifiers

-- The overall idea:
-- 1. GlobalRdrEnv from typechecking phase contains info on what imported a
--    name.
-- 2. refMap from GetHieAst contains location of names and how they are used.
-- 3. For each used name in refMap check whether the name comes from an import
--    at the origin of the code action.
codeActionProvider :: PluginMethodHandler IdeState Method_TextDocumentCodeAction
codeActionProvider :: PluginMethodHandler IdeState 'Method_TextDocumentCodeAction
codeActionProvider IdeState
ideState PluginId
pluginId (CodeActionParams Maybe ProgressToken
_ Maybe ProgressToken
_ TextDocumentIdentifier
documentId Range
range CodeActionContext
context) = do
  NormalizedFilePath
normalizedFilePath <- forall (m :: * -> *).
Monad m =>
Uri -> ExceptT PluginError m NormalizedFilePath
getNormalizedFilePathE (TextDocumentIdentifier
documentId forall s a. s -> Getting a s a -> a
^. forall s a. HasUri s a => Lens' s a
L.uri)
  TcModuleResult { ParsedModule
tmrParsed :: ParsedModule
tmrParsed :: TcModuleResult -> ParsedModule
tmrParsed, TcGblEnv
tmrTypechecked :: TcGblEnv
tmrTypechecked :: TcModuleResult -> TcGblEnv
tmrTypechecked } <- forall (m :: * -> *) e a.
MonadIO m =>
String -> IdeState -> ExceptT e Action a -> ExceptT e m a
runActionE String
"QualifyImportedNames.TypeCheck" IdeState
ideState forall a b. (a -> b) -> a -> b
$ forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> ExceptT PluginError Action v
useE TypeCheck
TypeCheck NormalizedFilePath
normalizedFilePath
  if forall a. Maybe a -> Bool
isJust (Range -> ParsedModule -> Maybe (LImportDecl GhcPs)
findLImportDeclAt Range
range ParsedModule
tmrParsed)
    then do
          HAR {RefMap a
refMap :: RefMap a
refMap :: ()
..} <- forall (m :: * -> *) e a.
MonadIO m =>
String -> IdeState -> ExceptT e Action a -> ExceptT e m a
runActionE String
"QualifyImportedNames.GetHieAst" IdeState
ideState (forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> ExceptT PluginError Action v
useE GetHieAst
GetHieAst NormalizedFilePath
normalizedFilePath)
          (FileVersion
_, Maybe Text
sourceTextM) <-  forall (m :: * -> *) e a.
MonadIO m =>
String -> IdeState -> ExceptT e Action a -> ExceptT e m a
runActionE String
"QualifyImportedNames.GetFileContents" IdeState
ideState (forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> ExceptT PluginError Action v
useE GetFileContents
GetFileContents NormalizedFilePath
normalizedFilePath)
          Text
sourceText <- forall (m :: * -> *) e b. Monad m => e -> Maybe b -> ExceptT e m b
handleMaybe (Text -> PluginError
PluginRuleFailed Text
"GetFileContents") Maybe Text
sourceTextM
          let globalRdrEnv :: GlobalRdrEnv
globalRdrEnv = TcGblEnv -> GlobalRdrEnv
tcg_rdr_env TcGblEnv
tmrTypechecked
              nameToImportedByMap :: NameEnv [ImportedBy]
nameToImportedByMap = GlobalRdrEnv -> NameEnv [ImportedBy]
globalRdrEnvToNameToImportedByMap GlobalRdrEnv
globalRdrEnv
              usedIdentifiers :: [UsedIdentifier]
usedIdentifiers = forall a. RefMap a -> [UsedIdentifier]
refMapToUsedIdentifiers RefMap a
refMap
              textEdits :: [TextEdit]
textEdits = Range
-> NameEnv [ImportedBy] -> Text -> [UsedIdentifier] -> [TextEdit]
usedIdentifiersToTextEdits Range
range NameEnv [ImportedBy]
nameToImportedByMap Text
sourceText [UsedIdentifier]
usedIdentifiers
          forall (f :: * -> *) a. Applicative f => a -> f a
pure  forall a b. (a -> b) -> a -> b
$ forall a b. a -> a |? b
InL (forall a. Uri -> [TextEdit] -> [a |? CodeAction]
makeCodeActions (TextDocumentIdentifier
documentId forall s a. s -> Getting a s a -> a
^. forall s a. HasUri s a => Lens' s a
L.uri) [TextEdit]
textEdits)
    else forall (f :: * -> *) a. Applicative f => a -> f a
pure  forall a b. (a -> b) -> a -> b
$ forall a b. a -> a |? b
InL []