1414--
1515-- You should have received a copy of the GNU Affero General Public License
1616-- along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
1718module Language.Haskell.GhcMod.ImportedFrom (importedFrom ) where
1819
1920import Control.Applicative
@@ -63,32 +64,36 @@ data ModuleDesc = ModuleDesc
6364 , mdImplicit :: Bool
6465 }
6566
66- getPackageDescFromPackageConfig :: (GmOut m , GmLog m , GhcMonad m , MonadIO m ) => PackageConfig -> m PackageDesc
67+ getPackageDescFromPackageConfig :: (GmOut m , GmLog m , GhcMonad m , MonadIO m )
68+ => PackageConfig -> m PackageDesc
6769getPackageDescFromPackageConfig p@ InstalledPackageInfo {.. }
6870 = do
6971 let (pkgName, pkgVer) = packageNameVesrion p
70- his <- catMaybes <$> mapM ( fmap ( either ( const Nothing ) Just ) . readInterfaceFile') haddockInterfaces
72+ his <- catMaybes <$> mapM readInterfaceFile' haddockInterfaces
7173 return PackageDesc
7274 { pdName = pkgName
7375 , pdVersion = pkgVer
7476 , pdHdHTMLs = haddockHTMLs
7577 , pdHdIfaces = concatMap ifInstalledIfaces his
7678 }
7779
78- readInterfaceFile' :: (GmOut m , GmLog m , MonadIO m , GhcMonad m ) => FilePath -> m (Either String InterfaceFile )
80+ readInterfaceFile' :: (GmOut m , GmLog m , MonadIO m , GhcMonad m )
81+ => FilePath -> m (Maybe InterfaceFile )
7982readInterfaceFile' f = do
80- exists <- liftIO $ doesFileExist f
81- if exists
82- then readInterfaceFile nameCacheFromGhc' f
83- else do
84- gmLog GmWarning " imported-from" haddockSuggestion
85- return $ Left " No such file "
83+ exists <- liftIO $ doesFileExist f
84+ if exists
85+ then either ( const Nothing ) Just <$> readInterfaceFile nameCacheFromGhc' f
86+ else do
87+ gmLog GmWarning " imported-from" haddockSuggestion
88+ return Nothing
8689 where
8790 backticks d = char ' `' <> d <> char ' `'
8891 haddockSuggestion =
8992 text " Couldn't find haddock interface" <+> quotes (text f) $$
9093 text " - To generate Haddock docs for dependencies, try:" $$
91- nest 4 (backticks $ text " cabal install --enable-documentation --haddock-hyperlink-source --only-dependencies" ) $$
94+ nest 4 (backticks $ text " cabal install --enable-documentation\
95+ \--haddock-hyperlink-source\
96+ \--only-dependencies" ) $$
9297 text " " $$
9398 text " - or set" $$
9499 nest 4 (backticks $ text " documentation: True" ) $$
@@ -105,7 +110,8 @@ nameCacheFromGhc' = ( read_from_session , write_to_session )
105110 read_from_session = liftIO =<< readIORef . hsc_NC <$> getSession
106111 write_to_session nc' = liftIO =<< flip writeIORef nc' . hsc_NC <$> getSession
107112
108- getModulePackage :: (GmOut m , GmLog m , GhcMonad m , MonadIO m ) => Module -> m (Maybe PackageDesc )
113+ getModulePackage :: (GmOut m , GmLog m , GhcMonad m , MonadIO m )
114+ => Module -> m (Maybe PackageDesc )
109115getModulePackage m = do
110116 dflag <- getSessionDynFlags
111117 let pkg = lookupPackage' dflag (moduleUnitId' m)
@@ -117,10 +123,9 @@ getModuleHaddockVisibleExports ModuleDesc{..} pkgdesc =
117123 in concatMap instVisibleExports modHdIfs
118124
119125getModuleDescFromImport :: (GhcMonad m ) => ImportDecl Name -> m ModuleDesc
120- getModuleDescFromImport ImportDecl {.. }
121- = do
126+ getModuleDescFromImport ImportDecl {.. } = do
122127 modul <- findModule (unLoc ideclName) (fmap sl_fs' ideclPkgQual)
123- modInfo <- fromJustNote " imported-from, getModuleDescFromImport" <$> getModuleInfo modul
128+ modInfo <- fromJustNote " getModuleDescFromImport" <$> getModuleInfo modul
124129 let listNames :: Data a => a -> [Name ]
125130 listNames = listifyStaged Renamer (const True )
126131 exprts = modInfoExports modInfo
@@ -137,19 +142,18 @@ getModuleDescFromImport ImportDecl{..}
137142 , mdImplicit = ideclImplicit
138143 }
139144
140- modulesWithPackages :: (GmOut m , GmLog m , GhcMonad m , MonadIO m ) => [ModuleDesc ] -> m [(ModuleDesc , PackageDesc )]
141- modulesWithPackages = (fmap catMaybes . ) $ mapM $ \ x@ ModuleDesc {.. } -> runMaybeT $ do
142- pkg <- MaybeT $ getModulePackage mdMod
143- return (x, pkg)
144-
145- preferExplicit :: [ModuleDesc ] -> [ModuleDesc ]
146- preferExplicit ms =
147- let (impl, expl) = partition mdImplicit ms
148- in expl ++ impl
149-
150- guessModule :: Maybe String -> Name -> [(ModuleDesc , PackageDesc )] -> Maybe (Name , (ModuleDesc , PackageDesc ))
151- guessModule mqn n ms =
152- let
145+ modulesWithPackages :: (GmOut m , GmLog m , GhcMonad m , MonadIO m )
146+ => [ModuleDesc ] -> m [(ModuleDesc , PackageDesc )]
147+ modulesWithPackages =
148+ (fmap catMaybes . ) $ mapM $ \ x@ ModuleDesc {.. } -> runMaybeT $ do
149+ pkg <- MaybeT $ getModulePackage mdMod
150+ return (x, pkg)
151+
152+ guessModule :: Maybe String
153+ -> Name
154+ -> [(ModuleDesc , PackageDesc )]
155+ -> Maybe (Name , (ModuleDesc , PackageDesc ))
156+ guessModule mqn n ms = let
153157 occn = occNameString $ occName n
154158 msf = filter f ms
155159 f = (n `elem` ) . uncurry getModuleHaddockVisibleExports
@@ -162,70 +166,75 @@ guessModule mqn n ms =
162166 f3 qn (ModuleDesc {.. },_)
163167 | Just as <- mdAlias = qn `elem` map (++ ' .' : occn) [as, mdName]
164168 | otherwise = qn == (mdName ++ ' .' : occn)
165- in (,) n <$> headMay msf3
169+ in
170+ (,) n <$> headMay msf3
166171
167- showOutput :: (GmOut m , GmLog m , GhcMonad m , MonadIO m ) => Name -> (ModuleDesc , PackageDesc ) -> m String
172+ showOutput :: (GmOut m , GmLog m , GhcMonad m , MonadIO m )
173+ => Name -> (ModuleDesc , PackageDesc ) -> m String
168174showOutput n (ModuleDesc {.. }, imppkg) = do
169- let
170- occn = occNameString $ occName n
171- nmod = nameModule n
172- mn = moduleNameString . moduleName $ nmod
173- modpkg <- fromMaybe imppkg <$> getModulePackage nmod
174- let
175- modpackage
176- | null (versionBranch modpackagever) = pdName modpkg
177- | otherwise = pdName modpkg ++ ' -' : showVersion modpackagever
178- modpackagever = pdVersion modpkg
179- package
180- | null (versionBranch packagever)
181- , Just r <- hdRoot = takeFileName r
182- | otherwise = pdName imppkg ++ ' -' : showVersion packagever
183- packagever = pdVersion imppkg
184- fqn = modpackage ++ ' :' : mn ++ ' .' : occn
185- hdRoot = headMay $ pdHdHTMLs imppkg
186- docFn = dotsToDashes mdName ++ " .html"
187- hdPath = fmap (</> docFn) hdRoot
188- dotsToDashes = map go
189- where go ' .' = ' -'
190- go x = x
191- hackageUrl = " https://hackage.haskell.org/package/" ++ package ++ " /docs/" ++ docFn
192- hdPathReal <- liftIO $ runMaybeT $ do
193- hdp <- MaybeT $ return hdPath
194- exists <- lift $ doesFileExist hdp
195- if exists
196- then return hdp
197- else MaybeT $ return Nothing
198- return $ unwords [fqn, mdName, fromMaybe hackageUrl hdPathReal]
175+ let occn = occNameString $ occName n
176+ nmod = nameModule n
177+ mn = moduleNameString . moduleName $ nmod
178+ modpkg <- fromMaybe imppkg <$> getModulePackage nmod
179+ let modpackage
180+ | null (versionBranch modpackagever) = pdName modpkg
181+ | otherwise = pdName modpkg ++ ' -' : showVersion modpackagever
182+ modpackagever = pdVersion modpkg
183+ package
184+ | null (versionBranch packagever)
185+ , Just r <- hdRoot = takeFileName r
186+ | otherwise = pdName imppkg ++ ' -' : showVersion packagever
187+ packagever = pdVersion imppkg
188+ fqn = modpackage ++ ' :' : mn ++ ' .' : occn
189+ hdRoot = headMay $ pdHdHTMLs imppkg
190+ docFn = dotsToDashes mdName ++ " .html"
191+ hdPath = fmap (</> docFn) hdRoot
192+ dotsToDashes = map go
193+ where go ' .' = ' -'
194+ go x = x
195+ hackageUrl = " https://hackage.haskell.org/package/"
196+ ++ package ++ " /docs/" ++ docFn
197+ hdPathReal <- liftIO $ runMaybeT $ do
198+ hdp <- MaybeT $ return hdPath
199+ exists <- lift $ doesFileExist hdp
200+ if exists
201+ then return hdp
202+ else MaybeT $ return Nothing
203+ return $ unwords [fqn, mdName, fromMaybe hackageUrl hdPathReal]
199204
200205-- | Look up Haddock docs for a symbol.
201206importedFrom :: forall m . IOish m
202- => FilePath -- ^ A target file.
203- -> Int -- ^ Line number.
204- -> Int -- ^ Column number.
205- -> Maybe Expression -- ^ Expression (symbol)
207+ => FilePath -- ^ A target file.
208+ -> Int -- ^ Line number.
209+ -> Int -- ^ Column number.
210+ -> Maybe Expression -- ^ Expression (symbol)
206211 -> GhcModT m String
207212importedFrom file lineNr colNr symbol =
208- ghandle handler $
209- runGmlT' [Left file] deferErrors $
210- withInteractiveContext $ do
211- crdl <- cradle
212- modSum <- fileModSummaryWithMapping (cradleCurrentDir crdl </> file)
213- (decls,imports, _exports, _docs) <- fromJustNote " imported-from,importedFrom" . renamedSource <$> (parseModule modSum >>= typecheckModule)
214- importDescs <- mapM (getModuleDescFromImport . unLoc) imports
215- bestids <-
216- case fmap snd $ headMay $ sortBy (cmp `on` fst ) $ findSpanName decls (lineNr, colNr) of
217- Just x -> return x
218- Nothing -> error $ " No names found at " ++ show (lineNr, colNr)
219- let idsMods = map (preferExplicit . (\ x -> filter ((x `elem` ) . mdVisibleExports) importDescs)) bestids
220- mbsym = getExpression <$> symbol
221- imps <- mapM modulesWithPackages idsMods
222- bg <-
223- case catMaybes $ zipWith (guessModule mbsym) bestids imps of
224- [] -> error $ " No modules exporting "
225- ++ fromMaybe (intercalate " ," (map (occNameString . getOccName) bestids)) mbsym
226- x -> return x
227- unlines <$> mapM (uncurry showOutput) bg
213+ handler $ runGmlT' [Left file] deferErrors $ withInteractiveContext $ do
214+ crdl <- cradle
215+ modSum <- fileModSummaryWithMapping (cradleCurrentDir crdl </> file)
216+ Just (decls,imports, _exports, _docs)
217+ <- renamedSource <$> (parseModule modSum >>= typecheckModule)
218+ importDescs :: [ModuleDesc ]
219+ <- mapM (getModuleDescFromImport . unLoc) imports
220+ bestids <-
221+ case sortBy (cmp `on` fst ) $ findSpanName decls (lineNr, colNr) of
222+ ((_, x): _) -> return x
223+ [] -> error $ " No names found at " ++ show (lineNr, colNr)
224+ let visExports xs n = filter ((elem n) . mdVisibleExports) xs
225+ idsMods = map (preferExplicit . visExports importDescs) bestids
226+ mbsym = getExpression <$> symbol
227+ imps <- mapM modulesWithPackages idsMods
228+ let bestids_str =
229+ intercalate " ," (map (occNameString . getOccName) bestids)
230+ bg <- case catMaybes $ zipWith (guessModule mbsym) bestids imps of
231+ [] -> error $ " No modules exporting " ++ fromMaybe bestids_str mbsym
232+ x -> return x
233+ unlines <$> mapM (uncurry showOutput) bg
228234 where
229- handler (SomeException ex) = do
230- gmLog GmException " imported-from" $ showDoc ex
231- return []
235+ handler = ghandle $ \ (SomeException ex) ->
236+ gmLog GmException " imported-from" (showDoc ex) >> return []
237+
238+ preferExplicit :: [ModuleDesc ] -> [ModuleDesc ]
239+ preferExplicit ms =
240+ let (impl, expl) = partition mdImplicit ms in expl ++ impl
0 commit comments