| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | module Main where |
|---|
| 29 | |
|---|
| 30 | import System.Environment |
|---|
| 31 | import Data.List |
|---|
| 32 | import Data.Maybe(catMaybes) |
|---|
| 33 | import Data.Char(toUpper,isAlpha,isAscii,isAlphaNum,ord) |
|---|
| 34 | import qualified Data.Map as Map |
|---|
| 35 | |
|---|
| 36 | import qualified OccName |
|---|
| 37 | import qualified Name |
|---|
| 38 | import qualified Module |
|---|
| 39 | import qualified Packages |
|---|
| 40 | import qualified DynFlags |
|---|
| 41 | import MonadUtils(liftIO) |
|---|
| 42 | import qualified GHC |
|---|
| 43 | |
|---|
| 44 | import qualified GHC.Paths as Paths |
|---|
| 45 | import qualified Distribution.InstalledPackageInfo as PI |
|---|
| 46 | import Documentation.Haddock(freshNameCache |
|---|
| 47 | ,ifInstalledIfaces |
|---|
| 48 | ,readInterfaceFile |
|---|
| 49 | ,InstalledInterface |
|---|
| 50 | ,instVisibleExports |
|---|
| 51 | ,instExports |
|---|
| 52 | ,instDocMap |
|---|
| 53 | ,instMod |
|---|
| 54 | ,Doc(..) |
|---|
| 55 | ,exampleExpression |
|---|
| 56 | ,exampleResult) |
|---|
| 57 | |
|---|
| 58 | instance Show Name.Name where show name = Name.getOccString name |
|---|
| 59 | instance Show Module.PackageId where show pid = Module.packageIdString pid |
|---|
| 60 | instance Show Module.ModuleName where show mname = Module.moduleNameString mname |
|---|
| 61 | |
|---|
| 62 | main = do |
|---|
| 63 | flagArgs <- getArgs |
|---|
| 64 | (withDocs,args) <- getOptsArgs (False,flagArgs) |
|---|
| 65 | iffs <- readInterfaceFiles freshNameCache |
|---|
| 66 | [ parseIfaceOption interfaceFile |
|---|
| 67 | | interfaceFile <- args ] |
|---|
| 68 | (pathMap,ifaces) <- processFile Map.empty [] iffs |
|---|
| 69 | let id_index = index ifaces |
|---|
| 70 | mapM_ (printElt pathMap withDocs . indexElt) $ id_index |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | |
|---|
| 74 | |
|---|
| 75 | processFile m ifs [] |
|---|
| 76 | = return (m,concat ifs) |
|---|
| 77 | processFile m ifs (((path,_),file):files) |
|---|
| 78 | = processFile (Map.insert package path m) (ifaces:ifs) files |
|---|
| 79 | where ifaces@(iface:_) = ifInstalledIfaces file |
|---|
| 80 | package = Module.modulePackageId $ instMod iface |
|---|
| 81 | |
|---|
| 82 | |
|---|
| 83 | getOptsArgs (withDocs,("--installed":args)) = do |
|---|
| 84 | installedHaddocks <- haddockPaths |
|---|
| 85 | getOptsArgs (withDocs,args++installedHaddocks) |
|---|
| 86 | getOptsArgs (withDocs,("--withDocs":args)) = |
|---|
| 87 | getOptsArgs (True,args) |
|---|
| 88 | getOptsArgs optargs = |
|---|
| 89 | return optargs |
|---|
| 90 | |
|---|
| 91 | |
|---|
| 92 | |
|---|
| 93 | |
|---|
| 94 | haddockPaths = GHC.runGhc (Just Paths.libdir) $ do |
|---|
| 95 | dflags <- GHC.getSessionDynFlags |
|---|
| 96 | (dflags,pkgids) <- liftIO $ Packages.initPackages dflags |
|---|
| 97 | case DynFlags.pkgDatabase dflags of |
|---|
| 98 | Nothing -> return [] |
|---|
| 99 | Just pkgDB -> return $ concatMap package pkgDB |
|---|
| 100 | where |
|---|
| 101 | package pkg = case (PI.haddockInterfaces pkg,PI.haddockHTMLs pkg) of |
|---|
| 102 | ([iface],[html]) -> [html++","++iface] |
|---|
| 103 | _ -> [] |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | indexElt (nm,entities) = (nm,map links $ Map.toAscList entities) |
|---|
| 107 | links (nm,entries) = [ ( mdl |
|---|
| 108 | , moduleNameUrl mdl (Name.nameOccName nm) |
|---|
| 109 | , doc |
|---|
| 110 | ) |
|---|
| 111 | | (mdl,doc,True) <- entries ] |
|---|
| 112 | |
|---|
| 113 | |
|---|
| 114 | |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | |
|---|
| 118 | |
|---|
| 119 | printElt pathMap withDoc (nm,modules) = do |
|---|
| 120 | putStrLn nm |
|---|
| 121 | mapM_ (printModule pathMap withDoc) $ concat modules |
|---|
| 122 | |
|---|
| 123 | printModule pathMap withDoc (mdl,url,doc) = |
|---|
| 124 | putStrLn $ " "++mdl_name++" : "++normalize ((pathMap Map.! package)++"/"++url) |
|---|
| 125 | ++if withDoc |
|---|
| 126 | then "\n"++maybe "none" id doc++"\n" |
|---|
| 127 | else "" |
|---|
| 128 | where mdl_name = Module.moduleNameString $ Module.moduleName mdl |
|---|
| 129 | package = Module.modulePackageId mdl |
|---|
| 130 | |
|---|
| 131 | normalize ('\\':'\\':rest) = '/':normalize rest |
|---|
| 132 | normalize ('\\':rest) = '/':normalize rest |
|---|
| 133 | normalize (c:rest) = c:normalize rest |
|---|
| 134 | normalize [] = [] |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | |
|---|
| 138 | |
|---|
| 139 | showDoc (DocEmpty) = "" |
|---|
| 140 | showDoc (DocAppend a b) = showDoc a ++ showDoc b |
|---|
| 141 | showDoc (DocString s) = s |
|---|
| 142 | showDoc (DocParagraph p) = "\n"++showDoc p++"\n" |
|---|
| 143 | showDoc (DocIdentifier ids) = concat [show id++" "|id<-ids] |
|---|
| 144 | showDoc (DocModule s) = s |
|---|
| 145 | showDoc (DocEmphasis d) = showDoc d |
|---|
| 146 | showDoc (DocMonospaced d) = showDoc d |
|---|
| 147 | showDoc (DocUnorderedList ds) = concatMap showDoc ds |
|---|
| 148 | showDoc (DocOrderedList ds) = concatMap showDoc ds |
|---|
| 149 | showDoc (DocDefList dds) = concat [showDoc a++showDoc b|(a,b)<-dds] |
|---|
| 150 | showDoc (DocCodeBlock d) = showDoc d |
|---|
| 151 | showDoc (DocURL s) = s |
|---|
| 152 | showDoc (DocPic s) = s |
|---|
| 153 | showDoc (DocAName s) = s |
|---|
| 154 | showDoc (DocExamples es) = concatMap showExample es |
|---|
| 155 | |
|---|
| 156 | showExample e = exampleExpression e++concat (exampleResult e) |
|---|
| 157 | |
|---|
| 158 | |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | |
|---|
| 164 | |
|---|
| 165 | |
|---|
| 166 | |
|---|
| 167 | |
|---|
| 168 | |
|---|
| 169 | |
|---|
| 170 | parseIfaceOption str = |
|---|
| 171 | case break (==',') str of |
|---|
| 172 | (fpath, ',':rest) -> |
|---|
| 173 | case break (==',') rest of |
|---|
| 174 | (src, ',':file) -> ((fpath, Just src), file) |
|---|
| 175 | (file, _) -> ((fpath, Nothing), file) |
|---|
| 176 | (file, _) -> (("", Nothing), file) |
|---|
| 177 | |
|---|
| 178 | readInterfaceFiles name_cache_accessor pairs = do |
|---|
| 179 | mbPackages <- mapM tryReadIface pairs |
|---|
| 180 | return (catMaybes mbPackages) |
|---|
| 181 | where |
|---|
| 182 | |
|---|
| 183 | tryReadIface (paths, file) = do |
|---|
| 184 | eIface <- readInterfaceFile name_cache_accessor file |
|---|
| 185 | case eIface of |
|---|
| 186 | Left err -> do |
|---|
| 187 | putStrLn ("Warning: Cannot read " ++ file ++ ":") |
|---|
| 188 | putStrLn (" " ++ err) |
|---|
| 189 | putStrLn "Skipping this interface." |
|---|
| 190 | return Nothing |
|---|
| 191 | Right f -> return $ Just (paths, f) |
|---|
| 192 | |
|---|
| 193 | |
|---|
| 194 | |
|---|
| 195 | |
|---|
| 196 | |
|---|
| 197 | full_index :: [InstalledInterface] |
|---|
| 198 | -> Map.Map String (Map.Map Name.Name [(Module.Module,Maybe String,Bool)]) |
|---|
| 199 | full_index ifaces = Map.fromListWith (flip (Map.unionWith (++))) |
|---|
| 200 | (concat (map getIfaceIndex ifaces)) |
|---|
| 201 | |
|---|
| 202 | index :: [InstalledInterface] |
|---|
| 203 | -> [(String, Map.Map Name.Name [(Module.Module,Maybe String,Bool)])] |
|---|
| 204 | index ifaces = sortBy cmp $ Map.toAscList $ full_index ifaces |
|---|
| 205 | where cmp (n1,_) (n2,_) = map toUpper n1 `compare` map toUpper n2 |
|---|
| 206 | |
|---|
| 207 | getIfaceIndex iface = |
|---|
| 208 | [ (Name.getOccString name |
|---|
| 209 | , Map.fromList [(name, [(mdl, fmap showD $ name `Map.lookup` docMap |
|---|
| 210 | , name `elem` instVisibleExports iface)])]) |
|---|
| 211 | | name <- instExports iface |
|---|
| 212 | , let docMap = instDocMap iface ] |
|---|
| 213 | where mdl = instMod iface |
|---|
| 214 | showD (mbDoc,fnargsDoc) = maybe "none" showDoc mbDoc |
|---|
| 215 | |
|---|
| 216 | moduleNameUrl mdl nm = moduleHtmlFile mdl ++ '#' : nameAnchorId nm |
|---|
| 217 | moduleHtmlFile mdl = mdl' ++ ".html" |
|---|
| 218 | where |
|---|
| 219 | mdl' = map (\c -> if c == '.' then '-' else c) |
|---|
| 220 | (Module.moduleNameString (Module.moduleName mdl)) |
|---|
| 221 | |
|---|
| 222 | nameAnchorId name = makeAnchorId (prefix : ':' : OccName.occNameString name) |
|---|
| 223 | where prefix | OccName.isValOcc name = 'v' |
|---|
| 224 | | otherwise = 't' |
|---|
| 225 | |
|---|
| 226 | makeAnchorId :: String -> String |
|---|
| 227 | makeAnchorId [] = [] |
|---|
| 228 | makeAnchorId (f:r) = escape isAlpha f ++ concatMap (escape isLegal) r |
|---|
| 229 | where |
|---|
| 230 | escape p c | p c = [c] |
|---|
| 231 | | otherwise = '-' : (show (ord c)) ++ "-" |
|---|
| 232 | isLegal ':' = True |
|---|
| 233 | isLegal '_' = True |
|---|
| 234 | isLegal '.' = True |
|---|
| 235 | isLegal c = isAscii c && isAlphaNum c |
|---|
| 236 | |
|---|