{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -Wwarn -fno-warn-type-defaults #-}
module Ide.Plugin.ModuleName (
descriptor,
Log,
) where
import Control.Monad (forM_, void)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except
import Control.Monad.Trans.Maybe
import Data.Aeson (toJSON)
import Data.Char (isLower, isUpper)
import Data.List (intercalate, minimumBy,
stripPrefix, uncons)
import qualified Data.List.NonEmpty as NE
import qualified Data.Map as Map
import Data.Maybe (mapMaybe)
import Data.Ord (comparing)
import Data.String (IsString)
import qualified Data.Text as T
import Development.IDE (GetParsedModule (GetParsedModule),
GhcSession (GhcSession),
IdeState, Pretty,
Priority (Debug),
Recorder, WithPriority,
colon, evalGhcEnv,
hscEnvWithImportPaths,
logWith,
realSrcSpanToRange,
runAction, useWithStale,
(<+>))
import Development.IDE.Core.PluginUtils
import Development.IDE.Core.PositionMapping (toCurrentRange)
import Development.IDE.GHC.Compat (GenLocated (L),
getSessionDynFlags,
hsmodName, importPaths,
locA, moduleNameString,
pattern RealSrcSpan,
pm_parsed_source, unLoc)
import Ide.Logger (Pretty (..))
import Ide.Plugin.Error
import Ide.Types
import Language.LSP.Protocol.Message
import Language.LSP.Protocol.Types
import Language.LSP.Server
import Language.LSP.VFS (virtualFileText)
import System.Directory (makeAbsolute)
import System.FilePath (dropExtension, normalise,
pathSeparator,
splitDirectories,
takeFileName)
descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
descriptor :: Recorder (WithPriority Log)
-> PluginId -> PluginDescriptor IdeState
descriptor Recorder (WithPriority Log)
recorder PluginId
plId =
(PluginId -> Text -> PluginDescriptor IdeState
forall ideState. PluginId -> Text -> PluginDescriptor ideState
defaultPluginDescriptor PluginId
plId Text
"Provides a code action to alter the module name if it is wrong")
{ pluginHandlers = mkPluginHandler SMethod_TextDocumentCodeLens (codeLens recorder)
, pluginCommands = [PluginCommand updateModuleNameCommand "set name of module to match with file path" (command recorder)]
}
updateModuleNameCommand :: IsString p => p
updateModuleNameCommand :: forall p. IsString p => p
updateModuleNameCommand = p
"updateModuleName"
codeLens :: Recorder (WithPriority Log) -> PluginMethodHandler IdeState 'Method_TextDocumentCodeLens
codeLens :: Recorder (WithPriority Log)
-> PluginMethodHandler IdeState 'Method_TextDocumentCodeLens
codeLens Recorder (WithPriority Log)
recorder IdeState
state PluginId
pluginId CodeLensParams{$sel:_textDocument:CodeLensParams :: CodeLensParams -> TextDocumentIdentifier
_textDocument=TextDocumentIdentifier Uri
uri} = do
[Action]
res <- Recorder (WithPriority Log)
-> IdeState -> Uri -> ExceptT PluginError (LspM Config) [Action]
forall c.
Recorder (WithPriority Log)
-> IdeState -> Uri -> ExceptT PluginError (LspM c) [Action]
action Recorder (WithPriority Log)
recorder IdeState
state Uri
uri
([CodeLens] |? Null)
-> ExceptT PluginError (LspM Config) ([CodeLens] |? Null)
forall a. a -> ExceptT PluginError (LspM Config) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (([CodeLens] |? Null)
-> ExceptT PluginError (LspM Config) ([CodeLens] |? Null))
-> ([CodeLens] |? Null)
-> ExceptT PluginError (LspM Config) ([CodeLens] |? Null)
forall a b. (a -> b) -> a -> b
$ [CodeLens] -> [CodeLens] |? Null
forall a b. a -> a |? b
InL (Action -> CodeLens
asCodeLens (Action -> CodeLens) -> [Action] -> [CodeLens]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Action]
res)
where
asCodeLens :: Action -> CodeLens
asCodeLens :: Action -> CodeLens
asCodeLens Replace{Text
Range
Uri
aUri :: Uri
aRange :: Range
aTitle :: Text
aCode :: Text
aUri :: Action -> Uri
aRange :: Action -> Range
aTitle :: Action -> Text
aCode :: Action -> Text
..} = Range -> Maybe Command -> Maybe Value -> CodeLens
CodeLens Range
aRange (Command -> Maybe Command
forall a. a -> Maybe a
Just Command
cmd) Maybe Value
forall a. Maybe a
Nothing
where
cmd :: Command
cmd = PluginId -> CommandId -> Text -> Maybe [Value] -> Command
mkLspCommand PluginId
pluginId CommandId
forall p. IsString p => p
updateModuleNameCommand Text
aTitle ([Value] -> Maybe [Value]
forall a. a -> Maybe a
Just [Uri -> Value
forall a. ToJSON a => a -> Value
toJSON Uri
aUri])
command :: Recorder (WithPriority Log) -> CommandFunction IdeState Uri
command :: Recorder (WithPriority Log) -> CommandFunction IdeState Uri
command Recorder (WithPriority Log)
recorder IdeState
state Maybe ProgressToken
_ Uri
uri = do
[Action]
actMaybe <- Recorder (WithPriority Log)
-> IdeState -> Uri -> ExceptT PluginError (LspM Config) [Action]
forall c.
Recorder (WithPriority Log)
-> IdeState -> Uri -> ExceptT PluginError (LspM c) [Action]
action Recorder (WithPriority Log)
recorder IdeState
state Uri
uri
[Action]
-> (Action -> ExceptT PluginError (LspM Config) ())
-> ExceptT PluginError (LspM Config) ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Action]
actMaybe ((Action -> ExceptT PluginError (LspM Config) ())
-> ExceptT PluginError (LspM Config) ())
-> (Action -> ExceptT PluginError (LspM Config) ())
-> ExceptT PluginError (LspM Config) ()
forall a b. (a -> b) -> a -> b
$ \Replace{Text
Range
Uri
aUri :: Action -> Uri
aRange :: Action -> Range
aTitle :: Action -> Text
aCode :: Action -> Text
aUri :: Uri
aRange :: Range
aTitle :: Text
aCode :: Text
..} ->
let
edit :: WorkspaceEdit
edit = Maybe (Map Uri [TextEdit])
-> Maybe
[TextDocumentEdit |? (CreateFile |? (RenameFile |? DeleteFile))]
-> Maybe (Map ChangeAnnotationIdentifier ChangeAnnotation)
-> WorkspaceEdit
WorkspaceEdit (Map Uri [TextEdit] -> Maybe (Map Uri [TextEdit])
forall a. a -> Maybe a
Just (Map Uri [TextEdit] -> Maybe (Map Uri [TextEdit]))
-> Map Uri [TextEdit] -> Maybe (Map Uri [TextEdit])
forall a b. (a -> b) -> a -> b
$ Uri -> [TextEdit] -> Map Uri [TextEdit]
forall k a. k -> a -> Map k a
Map.singleton Uri
aUri [Range -> Text -> TextEdit
TextEdit Range
aRange Text
aCode]) Maybe
[TextDocumentEdit |? (CreateFile |? (RenameFile |? DeleteFile))]
forall a. Maybe a
Nothing Maybe (Map ChangeAnnotationIdentifier ChangeAnnotation)
forall a. Maybe a
Nothing
in
ExceptT
PluginError (LspM Config) (LspId 'Method_WorkspaceApplyEdit)
-> ExceptT PluginError (LspM Config) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ExceptT
PluginError (LspM Config) (LspId 'Method_WorkspaceApplyEdit)
-> ExceptT PluginError (LspM Config) ())
-> ExceptT
PluginError (LspM Config) (LspId 'Method_WorkspaceApplyEdit)
-> ExceptT PluginError (LspM Config) ()
forall a b. (a -> b) -> a -> b
$ LspM Config (LspId 'Method_WorkspaceApplyEdit)
-> ExceptT
PluginError (LspM Config) (LspId 'Method_WorkspaceApplyEdit)
forall (m :: * -> *) a. Monad m => m a -> ExceptT PluginError m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (LspM Config (LspId 'Method_WorkspaceApplyEdit)
-> ExceptT
PluginError (LspM Config) (LspId 'Method_WorkspaceApplyEdit))
-> LspM Config (LspId 'Method_WorkspaceApplyEdit)
-> ExceptT
PluginError (LspM Config) (LspId 'Method_WorkspaceApplyEdit)
forall a b. (a -> b) -> a -> b
$ SServerMethod 'Method_WorkspaceApplyEdit
-> MessageParams 'Method_WorkspaceApplyEdit
-> (Either ResponseError (MessageResult 'Method_WorkspaceApplyEdit)
-> LspT Config IO ())
-> LspM Config (LspId 'Method_WorkspaceApplyEdit)
forall (m :: Method 'ServerToClient 'Request) (f :: * -> *) config.
MonadLsp config f =>
SServerMethod m
-> MessageParams m
-> (Either ResponseError (MessageResult m) -> f ())
-> f (LspId m)
sendRequest SServerMethod 'Method_WorkspaceApplyEdit
SMethod_WorkspaceApplyEdit (Maybe Text -> WorkspaceEdit -> ApplyWorkspaceEditParams
ApplyWorkspaceEditParams Maybe Text
forall a. Maybe a
Nothing WorkspaceEdit
edit) (LspT Config IO ()
-> Either ResponseError ApplyWorkspaceEditResult
-> LspT Config IO ()
forall a b. a -> b -> a
const (() -> LspT Config IO ()
forall a. a -> LspT Config IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()))
(Value |? Null)
-> ExceptT PluginError (LspM Config) (Value |? Null)
forall a. a -> ExceptT PluginError (LspM Config) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Value |? Null)
-> ExceptT PluginError (LspM Config) (Value |? Null))
-> (Value |? Null)
-> ExceptT PluginError (LspM Config) (Value |? Null)
forall a b. (a -> b) -> a -> b
$ Null -> Value |? Null
forall a b. b -> a |? b
InR Null
Null
data Action = Replace
{ Action -> Uri
aUri :: Uri
, Action -> Range
aRange :: Range
, Action -> Text
aTitle :: T.Text
, Action -> Text
aCode :: T.Text
}
deriving (Int -> Action -> ShowS
[Action] -> ShowS
Action -> String
(Int -> Action -> ShowS)
-> (Action -> String) -> ([Action] -> ShowS) -> Show Action
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Action -> ShowS
showsPrec :: Int -> Action -> ShowS
$cshow :: Action -> String
show :: Action -> String
$cshowList :: [Action] -> ShowS
showList :: [Action] -> ShowS
Show)
action :: Recorder (WithPriority Log) -> IdeState -> Uri -> ExceptT PluginError (LspM c) [Action]
action :: forall c.
Recorder (WithPriority Log)
-> IdeState -> Uri -> ExceptT PluginError (LspM c) [Action]
action Recorder (WithPriority Log)
recorder IdeState
state Uri
uri = do
NormalizedFilePath
nfp <- Uri -> ExceptT PluginError (LspM c) NormalizedFilePath
forall (m :: * -> *).
Monad m =>
Uri -> ExceptT PluginError m NormalizedFilePath
getNormalizedFilePathE Uri
uri
String
fp <- Uri -> ExceptT PluginError (LspM c) String
forall (m :: * -> *).
Monad m =>
Uri -> ExceptT PluginError m String
uriToFilePathE Uri
uri
Maybe VirtualFile
contents <- LspM c (Maybe VirtualFile)
-> ExceptT PluginError (LspM c) (Maybe VirtualFile)
forall (m :: * -> *) a. Monad m => m a -> ExceptT PluginError m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (LspM c (Maybe VirtualFile)
-> ExceptT PluginError (LspM c) (Maybe VirtualFile))
-> (NormalizedUri -> LspM c (Maybe VirtualFile))
-> NormalizedUri
-> ExceptT PluginError (LspM c) (Maybe VirtualFile)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NormalizedUri -> LspM c (Maybe VirtualFile)
forall config (m :: * -> *).
MonadLsp config m =>
NormalizedUri -> m (Maybe VirtualFile)
getVirtualFile (NormalizedUri -> ExceptT PluginError (LspM c) (Maybe VirtualFile))
-> NormalizedUri
-> ExceptT PluginError (LspM c) (Maybe VirtualFile)
forall a b. (a -> b) -> a -> b
$ Uri -> NormalizedUri
toNormalizedUri Uri
uri
let emptyModule :: Bool
emptyModule = Bool -> (VirtualFile -> Bool) -> Maybe VirtualFile -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Text -> Bool
T.null (Text -> Bool) -> (VirtualFile -> Text) -> VirtualFile -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.strip (Text -> Text) -> (VirtualFile -> Text) -> VirtualFile -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VirtualFile -> Text
virtualFileText) Maybe VirtualFile
contents
[Text]
correctNames <- (IO (Either PluginError [Text])
-> LspM c (Either PluginError [Text]))
-> ExceptT PluginError IO [Text]
-> ExceptT PluginError (LspM c) [Text]
forall (m :: * -> *) e a (n :: * -> *) e' b.
(m (Either e a) -> n (Either e' b))
-> ExceptT e m a -> ExceptT e' n b
mapExceptT IO (Either PluginError [Text])
-> LspM c (Either PluginError [Text])
forall a. IO a -> LspT c IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (ExceptT PluginError IO [Text]
-> ExceptT PluginError (LspM c) [Text])
-> ExceptT PluginError IO [Text]
-> ExceptT PluginError (LspM c) [Text]
forall a b. (a -> b) -> a -> b
$ Recorder (WithPriority Log)
-> IdeState
-> NormalizedFilePath
-> String
-> ExceptT PluginError IO [Text]
pathModuleNames Recorder (WithPriority Log)
recorder IdeState
state NormalizedFilePath
nfp String
fp
Recorder (WithPriority Log)
-> Priority -> Log -> ExceptT PluginError (LspM c) ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Debug ([Text] -> Log
CorrectNames [Text]
correctNames)
let bestName :: Maybe Text
bestName = (Text -> Text -> Ordering) -> NonEmpty Text -> Text
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy ((Text -> Int) -> Text -> Text -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing Text -> Int
T.length) (NonEmpty Text -> Text) -> Maybe (NonEmpty Text) -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text] -> Maybe (NonEmpty Text)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty [Text]
correctNames
Recorder (WithPriority Log)
-> Priority -> Log -> ExceptT PluginError (LspM c) ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Debug (Maybe Text -> Log
BestName Maybe Text
bestName)
Maybe (Range, Text)
statedNameMaybe <- IO (Maybe (Range, Text))
-> ExceptT PluginError (LspM c) (Maybe (Range, Text))
forall a. IO a -> ExceptT PluginError (LspM c) a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe (Range, Text))
-> ExceptT PluginError (LspM c) (Maybe (Range, Text)))
-> IO (Maybe (Range, Text))
-> ExceptT PluginError (LspM c) (Maybe (Range, Text))
forall a b. (a -> b) -> a -> b
$ IdeState -> NormalizedFilePath -> IO (Maybe (Range, Text))
codeModuleName IdeState
state NormalizedFilePath
nfp
Recorder (WithPriority Log)
-> Priority -> Log -> ExceptT PluginError (LspM c) ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Debug (Maybe Text -> Log
ModuleName (Maybe Text -> Log) -> Maybe Text -> Log
forall a b. (a -> b) -> a -> b
$ (Range, Text) -> Text
forall a b. (a, b) -> b
snd ((Range, Text) -> Text) -> Maybe (Range, Text) -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Range, Text)
statedNameMaybe)
case (Maybe Text
bestName, Maybe (Range, Text)
statedNameMaybe) of
(Just Text
bestName, Just (Range
nameRange, Text
statedName))
| Text
statedName Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Text]
correctNames ->
[Action] -> ExceptT PluginError (LspM c) [Action]
forall a. a -> ExceptT PluginError (LspM c) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Uri -> Range -> Text -> Text -> Action
Replace Uri
uri Range
nameRange (Text
"Set module name to " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
bestName) Text
bestName]
(Just Text
bestName, Maybe (Range, Text)
Nothing)
| Bool
emptyModule ->
let code :: Text
code = Text
"module " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
bestName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" where\n"
in [Action] -> ExceptT PluginError (LspM c) [Action]
forall a. a -> ExceptT PluginError (LspM c) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Uri -> Range -> Text -> Text -> Action
Replace Uri
uri (Position -> Position -> Range
Range (UInt -> UInt -> Position
Position UInt
0 UInt
0) (UInt -> UInt -> Position
Position UInt
0 UInt
0)) Text
code Text
code]
(Maybe Text, Maybe (Range, Text))
_ -> [Action] -> ExceptT PluginError (LspM c) [Action]
forall a. a -> ExceptT PluginError (LspM c) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
pathModuleNames :: Recorder (WithPriority Log) -> IdeState -> NormalizedFilePath -> FilePath -> ExceptT PluginError IO [T.Text]
pathModuleNames :: Recorder (WithPriority Log)
-> IdeState
-> NormalizedFilePath
-> String
-> ExceptT PluginError IO [Text]
pathModuleNames Recorder (WithPriority Log)
recorder IdeState
state NormalizedFilePath
normFilePath String
filePath
| Char -> Bool
isLower (Char -> Bool) -> (String -> Char) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Char
forall a. HasCallStack => [a] -> a
head (String -> Bool) -> String -> Bool
forall a b. (a -> b) -> a -> b
$ ShowS
takeFileName String
filePath = [Text] -> ExceptT PluginError IO [Text]
forall a. a -> ExceptT PluginError IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Text
"Main"]
| Bool
otherwise = do
(HscEnvEq
session, PositionMapping
_) <- String
-> IdeState
-> ExceptT PluginError Action (HscEnvEq, PositionMapping)
-> ExceptT PluginError IO (HscEnvEq, PositionMapping)
forall (m :: * -> *) e a.
MonadIO m =>
String -> IdeState -> ExceptT e Action a -> ExceptT e m a
runActionE String
"ModuleName.ghcSession" IdeState
state (ExceptT PluginError Action (HscEnvEq, PositionMapping)
-> ExceptT PluginError IO (HscEnvEq, PositionMapping))
-> ExceptT PluginError Action (HscEnvEq, PositionMapping)
-> ExceptT PluginError IO (HscEnvEq, PositionMapping)
forall a b. (a -> b) -> a -> b
$ GhcSession
-> NormalizedFilePath
-> ExceptT PluginError Action (HscEnvEq, PositionMapping)
forall k v.
IdeRule k v =>
k
-> NormalizedFilePath
-> ExceptT PluginError Action (v, PositionMapping)
useWithStaleE GhcSession
GhcSession NormalizedFilePath
normFilePath
[String]
srcPaths <- IO [String] -> ExceptT PluginError IO [String]
forall a. IO a -> ExceptT PluginError IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [String] -> ExceptT PluginError IO [String])
-> IO [String] -> ExceptT PluginError IO [String]
forall a b. (a -> b) -> a -> b
$ HscEnv -> Ghc [String] -> IO [String]
forall b. HscEnv -> Ghc b -> IO b
evalGhcEnv (HscEnvEq -> HscEnv
hscEnvWithImportPaths HscEnvEq
session) (Ghc [String] -> IO [String]) -> Ghc [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ DynFlags -> [String]
importPaths (DynFlags -> [String]) -> Ghc DynFlags -> Ghc [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ghc DynFlags
forall (m :: * -> *). GhcMonad m => m DynFlags
getSessionDynFlags
Recorder (WithPriority Log)
-> Priority -> Log -> ExceptT PluginError IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Debug ([String] -> Log
SrcPaths [String]
srcPaths)
let paths :: [String]
paths = ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (ShowS
normalise ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Char -> String
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure Char
pathSeparator)) [String]
srcPaths
Recorder (WithPriority Log)
-> Priority -> Log -> ExceptT PluginError IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Debug ([String] -> Log
NormalisedPaths [String]
paths)
String
mdlPath <- IO String -> ExceptT PluginError IO String
forall a. IO a -> ExceptT PluginError IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO String -> ExceptT PluginError IO String)
-> IO String -> ExceptT PluginError IO String
forall a b. (a -> b) -> a -> b
$ String -> IO String
makeAbsolute String
filePath
Recorder (WithPriority Log)
-> Priority -> Log -> ExceptT PluginError IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Debug (String -> Log
AbsoluteFilePath String
mdlPath)
let suffixes :: [String]
suffixes = (String -> Maybe String) -> [String] -> [String]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (String -> String -> Maybe String
forall a. Eq a => [a] -> [a] -> Maybe [a]
`stripPrefix` String
mdlPath) [String]
paths
[Text] -> ExceptT PluginError IO [Text]
forall a. a -> ExceptT PluginError IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
moduleNameFrom [String]
suffixes)
where
moduleNameFrom :: String -> Text
moduleNameFrom =
String -> Text
T.pack
(String -> Text) -> ShowS -> String -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"."
([String] -> String) -> (String -> [String]) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> ((Char, String) -> Bool) -> Maybe (Char, String) -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (Char -> Bool
isUpper (Char -> Bool)
-> ((Char, String) -> Char) -> (Char, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char, String) -> Char
forall a b. (a, b) -> a
fst) (Maybe (Char, String) -> Bool)
-> (String -> Maybe (Char, String)) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe (Char, String)
forall a. [a] -> Maybe (a, [a])
uncons)
([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
splitDirectories
(String -> [String]) -> ShowS -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
dropExtension
codeModuleName :: IdeState -> NormalizedFilePath -> IO (Maybe (Range, T.Text))
codeModuleName :: IdeState -> NormalizedFilePath -> IO (Maybe (Range, Text))
codeModuleName IdeState
state NormalizedFilePath
nfp = MaybeT IO (Range, Text) -> IO (Maybe (Range, Text))
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (MaybeT IO (Range, Text) -> IO (Maybe (Range, Text)))
-> MaybeT IO (Range, Text) -> IO (Maybe (Range, Text))
forall a b. (a -> b) -> a -> b
$ do
(ParsedModule
pm, PositionMapping
mp) <- IO (Maybe (ParsedModule, PositionMapping))
-> MaybeT IO (ParsedModule, PositionMapping)
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe (ParsedModule, PositionMapping))
-> MaybeT IO (ParsedModule, PositionMapping))
-> (Action (Maybe (ParsedModule, PositionMapping))
-> IO (Maybe (ParsedModule, PositionMapping)))
-> Action (Maybe (ParsedModule, PositionMapping))
-> MaybeT IO (ParsedModule, PositionMapping)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String
-> IdeState
-> Action (Maybe (ParsedModule, PositionMapping))
-> IO (Maybe (ParsedModule, PositionMapping))
forall a. String -> IdeState -> Action a -> IO a
runAction String
"ModuleName.GetParsedModule" IdeState
state (Action (Maybe (ParsedModule, PositionMapping))
-> MaybeT IO (ParsedModule, PositionMapping))
-> Action (Maybe (ParsedModule, PositionMapping))
-> MaybeT IO (ParsedModule, PositionMapping)
forall a b. (a -> b) -> a -> b
$ GetParsedModule
-> NormalizedFilePath
-> Action (Maybe (ParsedModule, PositionMapping))
forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> Action (Maybe (v, PositionMapping))
useWithStale GetParsedModule
GetParsedModule NormalizedFilePath
nfp
L (SrcSpanAnn' (EpAnn AnnListItem) -> SrcSpan
forall a. SrcSpanAnn' a -> SrcSpan
locA -> (RealSrcSpan RealSrcSpan
l Maybe BufSpan
_)) ModuleName
m <- IO
(Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
-> MaybeT
IO (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO
(Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
-> MaybeT
IO (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
-> (ParsedSource
-> IO
(Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)))
-> ParsedSource
-> MaybeT
IO (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)
-> IO
(Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)
-> IO
(Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)))
-> (ParsedSource
-> Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
-> ParsedSource
-> IO
(Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HsModule GhcPs -> Maybe (XRec GhcPs ModuleName)
HsModule GhcPs
-> Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)
forall p. HsModule p -> Maybe (XRec p ModuleName)
hsmodName (HsModule GhcPs
-> Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
-> (ParsedSource -> HsModule GhcPs)
-> ParsedSource
-> Maybe (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsedSource -> HsModule GhcPs
forall l e. GenLocated l e -> e
unLoc (ParsedSource
-> MaybeT
IO (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName))
-> ParsedSource
-> MaybeT
IO (GenLocated (SrcSpanAnn' (EpAnn AnnListItem)) ModuleName)
forall a b. (a -> b) -> a -> b
$ ParsedModule -> ParsedSource
pm_parsed_source ParsedModule
pm
Range
range <- IO (Maybe Range) -> MaybeT IO Range
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe Range) -> MaybeT IO Range)
-> (Maybe Range -> IO (Maybe Range))
-> Maybe Range
-> MaybeT IO Range
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe Range -> IO (Maybe Range)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe Range -> MaybeT IO Range) -> Maybe Range -> MaybeT IO Range
forall a b. (a -> b) -> a -> b
$ PositionMapping -> Range -> Maybe Range
toCurrentRange PositionMapping
mp (RealSrcSpan -> Range
realSrcSpanToRange RealSrcSpan
l)
(Range, Text) -> MaybeT IO (Range, Text)
forall a. a -> MaybeT IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Range
range, String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ ModuleName -> String
moduleNameString ModuleName
m)
data Log =
CorrectNames [T.Text]
| BestName (Maybe T.Text)
| ModuleName (Maybe T.Text)
| SrcPaths [FilePath]
| NormalisedPaths [FilePath]
| AbsoluteFilePath FilePath
deriving Int -> Log -> ShowS
[Log] -> ShowS
Log -> String
(Int -> Log -> ShowS)
-> (Log -> String) -> ([Log] -> ShowS) -> Show Log
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Log -> ShowS
showsPrec :: Int -> Log -> ShowS
$cshow :: Log -> String
show :: Log -> String
$cshowList :: [Log] -> ShowS
showList :: [Log] -> ShowS
Show
instance Pretty Log where
pretty :: forall ann. Log -> Doc ann
pretty Log
log = Doc ann
"ModuleName." Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> case Log
log of
CorrectNames [Text]
log -> Doc ann
"CorrectNames" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
colon Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> [Text] -> Doc ann
forall ann. [Text] -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty [Text]
log
BestName Maybe Text
log -> Doc ann
"BestName" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
colon Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Maybe Text -> Doc ann
forall ann. Maybe Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Maybe Text
log
ModuleName Maybe Text
log -> Doc ann
"StatedNameMaybe" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
colon Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Maybe Text -> Doc ann
forall ann. Maybe Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Maybe Text
log
SrcPaths [String]
log -> Doc ann
"SrcPaths" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
colon Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> [String] -> Doc ann
forall ann. [String] -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty [String]
log
NormalisedPaths [String]
log -> Doc ann
"NormalisedPaths" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
colon Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> [String] -> Doc ann
forall ann. [String] -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty [String]
log
AbsoluteFilePath String
log -> Doc ann
"AbsoluteFilePath" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
colon Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> String -> Doc ann
forall ann. String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty String
log