{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE CPP #-}
module Development.IDE.Spans.Documentation (
getDocumentation
, getDocumentationTryGhc
, getDocumentationsTryGhc
, DocMap
, mkDocMap
) where
import Control.Monad
import Control.Monad.Extra (findM)
import Control.Monad.IO.Class
import Data.Either
import Data.Foldable
import Data.List.Extra
import qualified Data.Map as M
import Data.Maybe
import qualified Data.Set as S
import qualified Data.Text as T
import Development.IDE.Core.Compile
import Development.IDE.Core.RuleTypes
import Development.IDE.GHC.Compat
import Development.IDE.GHC.Compat.Util
import Development.IDE.GHC.Error
import Development.IDE.GHC.Util (printOutputable)
import Development.IDE.Spans.Common
import Language.LSP.Protocol.Types (filePathToUri, getUri)
import Prelude hiding (mod)
import System.Directory
import System.FilePath
mkDocMap
:: HscEnv
-> RefMap a
-> TcGblEnv
-> IO DocAndKindMap
mkDocMap :: forall a. HscEnv -> RefMap a -> TcGblEnv -> IO DocAndKindMap
mkDocMap HscEnv
env RefMap a
rm TcGblEnv
this_mod =
do
#if MIN_VERSION_ghc(9,3,0)
(Just Docs{docs_decls = UniqMap this_docs}) <- extractDocs (hsc_dflags env) this_mod
#else
(Maybe HsDocString
_ , DeclDocMap Map Name HsDocString
this_docs, ArgDocMap
_) <- forall (m :: * -> *).
MonadIO m =>
TcGblEnv -> m (Maybe HsDocString, DeclDocMap, ArgDocMap)
extractDocs TcGblEnv
this_mod
#endif
#if MIN_VERSION_ghc(9,3,0)
d <- foldrM getDocs (fmap (\(_, x) -> (map hsDocString x) `SpanDocString` SpanDocUris Nothing Nothing) this_docs) names
#else
NameEnv SpanDoc
d <- forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> b -> m b) -> b -> t a -> m b
foldrM Name -> NameEnv SpanDoc -> IO (NameEnv SpanDoc)
getDocs (forall a. [(Name, a)] -> NameEnv a
mkNameEnv forall a b. (a -> b) -> a -> b
$ forall k a. Map k a -> [(k, a)]
M.toList forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (HsDocString -> SpanDocUris -> SpanDoc
`SpanDocString` Maybe Text -> Maybe Text -> SpanDocUris
SpanDocUris forall a. Maybe a
Nothing forall a. Maybe a
Nothing) Map Name HsDocString
this_docs) [Name]
names
#endif
NameEnv TyThing
k <- forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> b -> m b) -> b -> t a -> m b
foldrM Name -> NameEnv TyThing -> IO (NameEnv TyThing)
getType (TcGblEnv -> NameEnv TyThing
tcg_type_env TcGblEnv
this_mod) [Name]
names
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ NameEnv SpanDoc -> NameEnv TyThing -> DocAndKindMap
DKMap NameEnv SpanDoc
d NameEnv TyThing
k
where
getDocs :: Name -> NameEnv SpanDoc -> IO (NameEnv SpanDoc)
getDocs Name
n NameEnv SpanDoc
nameMap
| forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Module
mod forall a. Eq a => a -> a -> Bool
==) forall a b. (a -> b) -> a -> b
$ Name -> Maybe Module
nameModule_maybe Name
n = forall (f :: * -> *) a. Applicative f => a -> f a
pure NameEnv SpanDoc
nameMap
| Bool
otherwise = do
SpanDoc
doc <- HscEnv -> Name -> IO SpanDoc
getDocumentationTryGhc HscEnv
env Name
n
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. NameEnv a -> Name -> a -> NameEnv a
extendNameEnv NameEnv SpanDoc
nameMap Name
n SpanDoc
doc
getType :: Name -> NameEnv TyThing -> IO (NameEnv TyThing)
getType Name
n NameEnv TyThing
nameMap
| OccName -> Bool
isTcOcc forall a b. (a -> b) -> a -> b
$ forall name. HasOccName name => name -> OccName
occName Name
n
, Maybe TyThing
Nothing <- forall a. NameEnv a -> Name -> Maybe a
lookupNameEnv NameEnv TyThing
nameMap Name
n
= do Maybe TyThing
kind <- HscEnv -> Name -> IO (Maybe TyThing)
lookupKind HscEnv
env Name
n
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall b a. b -> (a -> b) -> Maybe a -> b
maybe NameEnv TyThing
nameMap (forall a. NameEnv a -> Name -> a -> NameEnv a
extendNameEnv NameEnv TyThing
nameMap Name
n) Maybe TyThing
kind
| Bool
otherwise = forall (f :: * -> *) a. Applicative f => a -> f a
pure NameEnv TyThing
nameMap
names :: [Name]
names = forall a b. [Either a b] -> [b]
rights forall a b. (a -> b) -> a -> b
$ forall a. Set a -> [a]
S.toList Set Identifier
idents
idents :: Set Identifier
idents = forall k a. Map k a -> Set k
M.keysSet RefMap a
rm
mod :: Module
mod = TcGblEnv -> Module
tcg_mod TcGblEnv
this_mod
lookupKind :: HscEnv -> Name -> IO (Maybe TyThing)
lookupKind :: HscEnv -> Name -> IO (Maybe TyThing)
lookupKind HscEnv
env =
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall b a. b -> Either a b -> b
fromRight forall a. Maybe a
Nothing) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a.
DynFlags -> Text -> IO a -> IO (Either [FileDiagnostic] a)
catchSrcErrors (HscEnv -> DynFlags
hsc_dflags HscEnv
env) Text
"span" forall b c a. (b -> c) -> (a -> b) -> a -> c
. HscEnv -> Name -> IO (Maybe TyThing)
lookupName HscEnv
env
getDocumentationTryGhc :: HscEnv -> Name -> IO SpanDoc
getDocumentationTryGhc :: HscEnv -> Name -> IO SpanDoc
getDocumentationTryGhc HscEnv
env Name
n =
(forall a. a -> Maybe a -> a
fromMaybe SpanDoc
emptySpanDoc forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> Maybe a
listToMaybe forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HscEnv -> [Name] -> IO [SpanDoc]
getDocumentationsTryGhc HscEnv
env [Name
n])
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` (\(IOEnvFailure
_ :: IOEnvFailure) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure SpanDoc
emptySpanDoc)
getDocumentationsTryGhc :: HscEnv -> [Name] -> IO [SpanDoc]
getDocumentationsTryGhc :: HscEnv -> [Name] -> IO [SpanDoc]
getDocumentationsTryGhc HscEnv
env [Name]
names = do
Either
[FileDiagnostic]
[Either String (Maybe HsDocString, IntMap HsDocString)]
resOr <- forall a.
DynFlags -> Text -> IO a -> IO (Either [FileDiagnostic] a)
catchSrcErrors (HscEnv -> DynFlags
hsc_dflags HscEnv
env) Text
"docs" forall a b. (a -> b) -> a -> b
$ HscEnv
-> [Name]
-> IO [Either String (Maybe HsDocString, IntMap HsDocString)]
getDocsBatch HscEnv
env [Name]
names
case Either
[FileDiagnostic]
[Either String (Maybe HsDocString, IntMap HsDocString)]
resOr of
Left [FileDiagnostic]
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return []
Right [Either String (Maybe HsDocString, IntMap HsDocString)]
res -> forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM forall {f :: * -> *} {a} {b}.
MonadIO f =>
Either a (Maybe HsDocString, b) -> Name -> f SpanDoc
unwrap [Either String (Maybe HsDocString, IntMap HsDocString)]
res [Name]
names
where
#if MIN_VERSION_ghc(9,3,0)
unwrap (Right (Just docs, _)) n = SpanDocString (map hsDocString docs) <$> getUris n
#else
unwrap :: Either a (Maybe HsDocString, b) -> Name -> f SpanDoc
unwrap (Right (Just HsDocString
docs, b
_)) Name
n = HsDocString -> SpanDocUris -> SpanDoc
SpanDocString HsDocString
docs forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall {m :: * -> *}. MonadIO m => Name -> m SpanDocUris
getUris Name
n
#endif
unwrap Either a (Maybe HsDocString, b)
_ Name
n = forall {f :: * -> *}. MonadIO f => Name -> f SpanDoc
mkSpanDocText Name
n
mkSpanDocText :: Name -> f SpanDoc
mkSpanDocText Name
name =
[Text] -> SpanDocUris -> SpanDoc
SpanDocText [] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall {m :: * -> *}. MonadIO m => Name -> m SpanDocUris
getUris Name
name
getUris :: Name -> m SpanDocUris
getUris Name
name = do
(Maybe Text
docFu, Maybe Text
srcFu) <-
case Name -> Maybe Module
nameModule_maybe Name
name of
Just Module
mod -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ do
Maybe Text
doc <- IO (Maybe String) -> IO (Maybe Text)
toFileUriText forall a b. (a -> b) -> a -> b
$ HscEnv -> Module -> IO (Maybe String)
lookupDocHtmlForModule HscEnv
env Module
mod
Maybe Text
src <- IO (Maybe String) -> IO (Maybe Text)
toFileUriText forall a b. (a -> b) -> a -> b
$ HscEnv -> Module -> IO (Maybe String)
lookupSrcHtmlForModule HscEnv
env Module
mod
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Text
doc, Maybe Text
src)
Maybe Module
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a. Maybe a
Nothing, forall a. Maybe a
Nothing)
let docUri :: Maybe Text
docUri = (forall a. Semigroup a => a -> a -> a
<> Text
"#" forall a. Semigroup a => a -> a -> a
<> Text
selector forall a. Semigroup a => a -> a -> a
<> forall a. Outputable a => a -> Text
printOutputable Name
name) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Text
docFu
srcUri :: Maybe Text
srcUri = (forall a. Semigroup a => a -> a -> a
<> Text
"#" forall a. Semigroup a => a -> a -> a
<> forall a. Outputable a => a -> Text
printOutputable Name
name) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Text
srcFu
selector :: Text
selector
| Name -> Bool
isValName Name
name = Text
"v:"
| Bool
otherwise = Text
"t:"
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Maybe Text -> Maybe Text -> SpanDocUris
SpanDocUris Maybe Text
docUri Maybe Text
srcUri
toFileUriText :: IO (Maybe String) -> IO (Maybe Text)
toFileUriText = (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) (Uri -> Text
getUri forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Uri
filePathToUri)
getDocumentation
:: HasSrcSpan name
=> [ParsedModule]
-> name
-> [T.Text]
getDocumentation :: forall name. HasSrcSpan name => [ParsedModule] -> name -> [Text]
getDocumentation [ParsedModule]
_sources name
_targetName = []
lookupDocHtmlForModule :: HscEnv -> Module -> IO (Maybe FilePath)
lookupDocHtmlForModule :: HscEnv -> Module -> IO (Maybe String)
lookupDocHtmlForModule =
(String -> String -> String)
-> HscEnv -> Module -> IO (Maybe String)
lookupHtmlForModule (\String
pkgDocDir String
modDocName -> String
pkgDocDir String -> String -> String
</> String
modDocName String -> String -> String
<.> String
"html")
lookupSrcHtmlForModule :: HscEnv -> Module -> IO (Maybe FilePath)
lookupSrcHtmlForModule :: HscEnv -> Module -> IO (Maybe String)
lookupSrcHtmlForModule =
(String -> String -> String)
-> HscEnv -> Module -> IO (Maybe String)
lookupHtmlForModule (\String
pkgDocDir String
modDocName -> String
pkgDocDir String -> String -> String
</> String
"src" String -> String -> String
</> String
modDocName String -> String -> String
<.> String
"html")
lookupHtmlForModule :: (FilePath -> FilePath -> FilePath) -> HscEnv -> Module -> IO (Maybe FilePath)
lookupHtmlForModule :: (String -> String -> String)
-> HscEnv -> Module -> IO (Maybe String)
lookupHtmlForModule String -> String -> String
mkDocPath HscEnv
hscEnv Module
m = do
let mfs :: Maybe [String]
mfs = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
go) (HscEnv -> GenUnit UnitId -> Maybe [String]
lookupHtmls HscEnv
hscEnv GenUnit UnitId
ui)
Maybe String
html <- forall (m :: * -> *) a.
Monad m =>
(a -> m Bool) -> [a] -> m (Maybe a)
findM String -> IO Bool
doesFileExist (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Maybe a -> [a]
maybeToList forall a b. (a -> b) -> a -> b
$ Maybe [String]
mfs)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse String -> IO String
canonicalizePath Maybe String
html
where
go :: String -> [String]
go String
pkgDocDir = forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
mkDocPath String
pkgDocDir) [String]
mns
ui :: GenUnit UnitId
ui = forall unit. GenModule unit -> unit
moduleUnit Module
m
mns :: [String]
mns = do
[String]
chunks <- (forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
drop1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [[a]]
inits forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (Partial, Eq a) => [a] -> [a] -> [[a]]
splitOn String
".") forall a b. (a -> b) -> a -> b
$ (ModuleName -> String
moduleNameString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall unit. GenModule unit -> ModuleName
moduleName) Module
m
forall a b. (a -> b) -> [a] -> [b]
map (forall a. [a] -> [[a]] -> [a]
`intercalate` [String]
chunks) [String
".", String
"-"]
lookupHtmls :: HscEnv -> Unit -> Maybe [FilePath]
lookupHtmls :: HscEnv -> GenUnit UnitId -> Maybe [String]
lookupHtmls HscEnv
df GenUnit UnitId
ui =
forall a b. (a -> b) -> [a] -> [b]
map String -> String
takeDirectory forall b c a. (b -> c) -> (a -> b) -> a -> c
. UnitInfo -> [String]
unitHaddockInterfaces forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HscEnv -> GenUnit UnitId -> Maybe UnitInfo
lookupUnit HscEnv
df GenUnit UnitId
ui