{-# 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
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 []