bibtex 0.1.0.6 → 0.1.0.7
raw patch · 5 files changed
+235/−221 lines, 5 filesdep +bibtexdep ~Cabaldep ~basedep ~latexPVP ok
version bump matches the API change (PVP)
Dependencies added: bibtex
Dependency ranges changed: Cabal, base, latex, parsec, tar, utf8-string, utility-ht
API changes (from Hackage documentation)
Files
- bibtex.cabal +22/−12
- demo/Hackage.hs +168/−0
- demo/Publications.hs +45/−0
- src/Hackage.hs +0/−164
- src/Publications.hs +0/−45
bibtex.cabal view
@@ -1,5 +1,5 @@ Name: bibtex-Version: 0.1.0.6+Version: 0.1.0.7 License: BSD3 License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -62,7 +62,7 @@ . > TeX capacity exceeded, sorry [save size=5000] Tested-With: GHC==6.12.3-Cabal-Version: >=1.6+Cabal-Version: >=1.10 Build-Type: Simple Extra-Source-Files: Makefile@@ -76,7 +76,7 @@ location: http://code.haskell.org/~thielema/bibtex/ Source-Repository this- tag: 0.1.0.6+ tag: 0.1.0.7 type: darcs location: http://code.haskell.org/~thielema/bibtex/ @@ -100,6 +100,7 @@ base >= 1.0 && < 2, special-functors >=1.0 && <1.1 + Default-Language: Haskell98 GHC-Options: -Wall Hs-Source-Dirs: src Exposed-Modules:@@ -109,24 +110,33 @@ Executable publication-overview- If !flag(buildExamples)+ If flag(buildExamples)+ Build-Depends:+ bibtex,+ parsec,+ base+ Else Buildable: False + Default-Language: Haskell98 GHC-Options: -Wall- Hs-source-dirs: src- Main-Is: Publications.hs+ Main-Is: demo/Publications.hs Executable hackage-bibtex If flag(buildExamples) Build-Depends:+ bibtex,+ latex, old-time >=1.0 && <1.2,- Cabal >=1.6 && <1.24,- tar >=0.3 && <0.5,- utf8-string >=0.3.4 && <0.4,- bytestring >=0.9 && <0.11+ Cabal >=3.6 && <3.11,+ tar >=0.3 && <0.6,+ utf8-string >=0.3.4 && <2,+ bytestring >=0.9 && <0.13,+ utility-ht,+ base Else Buildable: False + Default-Language: Haskell98 GHC-Options: -Wall- Hs-source-dirs: src- Main-Is: Hackage.hs+ Main-Is: demo/Hackage.hs
+ demo/Hackage.hs view
@@ -0,0 +1,168 @@+module Main where++import qualified Text.BibTeX.Format as Format+import qualified Text.BibTeX.Entry as Entry+import qualified Text.LaTeX.Character as LaTeX++import qualified Distribution.PackageDescription.Parsec as PkgP+import qualified Distribution.PackageDescription as PkgD+import qualified Distribution.Package as Pkg+import qualified Distribution.Types.PackageName as PkgN+import qualified Distribution.Verbosity as Verbosity+import Distribution.PackageDescription+ (PackageDescription, )+import Distribution.Package+ (PackageIdentifier(..), )+import Distribution.PackageDescription.Parsec+ (parseGenericPackageDescription, )+import Distribution.Simple.PackageDescription+ (readGenericPackageDescription, )+import System.Time (ClockTime(TOD), getClockTime,+ toCalendarTime, toUTCTime,+ CalendarTime, ctYear, ctMonth, )++import qualified Codec.Archive.Tar as Tar+import qualified Codec.Archive.Tar.Entry as TarEnt+import qualified Data.ByteString.Lazy.UTF8 as UTF8+import qualified Data.ByteString.Lazy as B+import qualified System.IO as IO++import Distribution.Text (display, )+import Distribution.Pretty (prettyShow, )+import Distribution.Utils.ShortText (fromShortText, )++import Data.String.HT (trim, )+import Data.Tuple.HT (mapFst, )+import Data.List.HT (switchL, switchR, )+import Data.Char (toLower, isSpace, isAlpha, chr, )+import qualified Data.List as List+++{- |+See hackage-server:Distribution/Server/Pages/Package.hs+-}+packageURL :: PackageIdentifier -> String+packageURL pkgid = "/package/" ++ display pkgid+++{- |+Filter out parts in parentheses and e-mails addresses+-}+removeAnnotations :: String -> String+removeAnnotations "" = ""+removeAnnotations (c:cs) =+ case c of+ '(' -> removeAnnotations $ drop 1 $ dropWhile (')'/=) cs+ '<' -> removeAnnotations $ drop 1 $ dropWhile ('>'/=) cs+ _ -> c : removeAnnotations cs++splitList :: String -> [String]+splitList =+ let separate rest = ([], uncurry (:) $ recourse rest)+ continue c rest = mapFst (c:) $ recourse rest+ recourse str =+ case str of+ '/' : rest -> separate rest+ '&' : rest -> separate rest+ ',' : rest -> separate rest+ c0:rest0@('a':'n':'d':c1:rest) ->+ if isSpace c0 && isSpace c1+ then separate rest+ else continue c0 rest0+ c:rest -> continue c rest+ "" -> ([], [])+ in uncurry (:) . recourse++splitAuthorList :: String -> [String]+splitAuthorList =+ map (\author ->+ case author of+ "..." -> "others"+ "et al." -> "others"+ _ -> author) .+ filter (not . null) .+ map trim .+ splitList .+ -- remove numbers, quotation marks ...+ filter (\c -> isAlpha c || isSpace c || elem c ".-'@/&,") .+ removeAnnotations++{- authors must be split with respect to ',', '/', '&' and ' and ' -}+fromPackage :: CalendarTime -> PackageDescription -> Entry.T+fromPackage time pkg =+ let authors =+ splitAuthorList $ fromShortText $ PkgD.author pkg+ surname =+ switchL "unknown" (\firstAuthor _ ->+ switchR "" (\_ -> filter isAlpha) $+ words firstAuthor) $+ authors+ pkgId = PkgD.package pkg+ name = PkgN.unPackageName (Pkg.pkgName pkgId)+ year = ctYear time+ versionStr = prettyShow (Pkg.pkgVersion pkgId)+ bibId =+ map toLower surname ++ show year +++ name ++ "-" ++ versionStr+ in Entry.Cons "Misc" bibId $+ ("author",+ if null authors+ then "unknown"+ else Format.authorList $+ map LaTeX.fromUnicodeString authors) :+ ("title",+ "{" ++ name ++ ": " +++ LaTeX.fromUnicodeString (fromShortText (PkgD.synopsis pkg)) ++ "}") :+ ("howpublished",+ "\\url{http://hackage.haskell.org" +++ packageURL (PkgD.package pkg) ++ "}") :+ ("year", show year) :+ ("month", show (ctMonth time)) :+ ("version", versionStr) :+ ("keywords", "Haskell, " ++ fromShortText (PkgD.category pkg)) :+ ("subtype", "program") :+ []++example :: IO ()+example =+ do now <- toCalendarTime =<< getClockTime+ pkg <- readGenericPackageDescription Verbosity.silent "example.cabal"+ putStrLn (Format.entry $ fromPackage now $ PkgD.packageDescription pkg)+++{- |+This decodes UTF-8 but in contrast to UTF8.toString+it handles invalid characters like Latin-1 ones.+This way we can also cope with many texts that contain actually Latin-1.+-}+decodeUTF8orLatin :: B.ByteString -> String+decodeUTF8orLatin =+ List.unfoldr (\bstr ->+ flip fmap (UTF8.uncons bstr) $ \(c, rest) ->+ if c==UTF8.replacement_char+ then (chr $ fromIntegral $ B.head bstr, B.tail bstr)+ else (c,rest))+++fromTarEntry :: Tar.Entry -> String+fromTarEntry ent =+ case (List.isSuffixOf ".cabal" $ TarEnt.entryPath ent,+ TarEnt.entryContent ent) of+ (True, TarEnt.NormalFile txt _size) ->+ case PkgP.runParseResult+ (parseGenericPackageDescription (B.toStrict txt)) of+ (_, Right pkg) ->+ Format.entry $+ fromPackage+ (toUTCTime (TOD (fromIntegral $ TarEnt.entryTime ent) 0))+ (PkgD.packageDescription pkg)+ (_, Left err) -> show err+ _ -> ""++main :: IO ()+main =+ Tar.foldEntries+ (\entry cont -> putStrLn (fromTarEntry entry) >> cont)+ (return ()) (IO.hPutStr IO.stderr . show) .+ Tar.read =<<+ B.getContents
+ demo/Publications.hs view
@@ -0,0 +1,45 @@+module Main where++import qualified Text.BibTeX.Parse as Parse+import qualified Text.BibTeX.Entry as Entry+import qualified Text.ParserCombinators.Parsec as Parsec++import qualified Data.Char as Char+import System.IO (hPutStrLn, stderr, )+++typeTable :: [((String, Maybe String), String)]+typeTable =+ (("article", Just "reviewed"), "reviewedjournal") :+ (("article", Just "popular"), "popular") :+ (("article", Nothing), "journal") :+ (("inproceedings", Just "reviewed"), "reviewedconference") :+ (("inproceedings", Nothing), "conference") :+ (("techreport", Nothing), "techreport") :+ (("inbook", Just "program"), "program") :+ (("misc", Just "program"), "program") :+ (("misc", Just "talk"), "talk") :+ (("mastersthesis", Nothing), "thesis") :+ (("phdthesis", Nothing), "thesis") :+ []+++cite :: Entry.T -> String+cite entry =+ maybe+ "% \\nocite"+ ("\\nocite" ++ )+ (lookup+ (map Char.toLower (Entry.entryType entry),+ lookup "subtype" (Entry.fields (Entry.lowerCaseFieldNames entry)))+ typeTable) +++ "{" ++ Entry.identifier entry ++ "}"+++main :: IO ()+main =+ do bib <- getContents+ case Parsec.parse (Parsec.skipMany Parsec.space >> Parse.file) "stdin" bib of+ Left errMsg -> hPutStrLn stderr (show errMsg)+ Right entries ->+ mapM_ (putStrLn . cite) entries
− src/Hackage.hs
@@ -1,164 +0,0 @@-module Main where--import qualified Text.BibTeX.Format as Format-import qualified Text.BibTeX.Entry as Entry-import qualified Text.LaTeX.Character as LaTeX--import qualified Distribution.PackageDescription.Parse as PkgP-import qualified Distribution.PackageDescription as PkgD-import qualified Distribution.Package as Pkg-import qualified Distribution.Verbosity as Verbosity-import Distribution.PackageDescription- (PackageDescription, )-import Distribution.Package- (PackageIdentifier(..), )-import Distribution.PackageDescription.Parse- (parsePackageDescription,- readPackageDescription, )-import System.Time (ClockTime(TOD), getClockTime,- toCalendarTime, toUTCTime,- CalendarTime, ctYear, ctMonth, )--import qualified Codec.Archive.Tar as Tar-import qualified Codec.Archive.Tar.Entry as TarEnt-import qualified Data.ByteString.Lazy.UTF8 as UTF8-import qualified Data.ByteString.Lazy as B-import qualified System.IO as IO--import Distribution.Text (display, )--import Data.String.HT (trim, )-import Data.Tuple.HT (mapFst, )-import Data.List.HT (switchL, switchR, )-import Data.Char (toLower, isSpace, isAlpha, chr, )-import Data.Version (showVersion, )-import qualified Data.List as List---{- |-See hackage-server:Distribution/Server/Pages/Package.hs--}-packageURL :: PackageIdentifier -> String-packageURL pkgid = "/package/" ++ display pkgid---{- |-Filter out parts in parentheses and e-mails addresses--}-removeAnnotations :: String -> String-removeAnnotations "" = ""-removeAnnotations (c:cs) =- case c of- '(' -> removeAnnotations $ drop 1 $ dropWhile (')'/=) cs- '<' -> removeAnnotations $ drop 1 $ dropWhile ('>'/=) cs- _ -> c : removeAnnotations cs--splitList :: String -> [String]-splitList =- let separate rest = ([], uncurry (:) $ recourse rest)- continue c rest = mapFst (c:) $ recourse rest- recourse str =- case str of- '/' : rest -> separate rest- '&' : rest -> separate rest- ',' : rest -> separate rest- c0:rest0@('a':'n':'d':c1:rest) ->- if isSpace c0 && isSpace c1- then separate rest- else continue c0 rest0- c:rest -> continue c rest- "" -> ([], [])- in uncurry (:) . recourse--splitAuthorList :: String -> [String]-splitAuthorList =- map (\author ->- case author of- "..." -> "others"- "et al." -> "others"- _ -> author) .- filter (not . null) .- map trim .- splitList .- -- remove numbers, quotation marks ...- filter (\c -> isAlpha c || isSpace c || elem c ".-'@/&,") .- removeAnnotations--{- authors must be split with respect to ',', '/', '&' and ' and ' -}-fromPackage :: CalendarTime -> PackageDescription -> Entry.T-fromPackage time pkg =- let authors =- splitAuthorList $ PkgD.author pkg- surname =- switchL "unknown" (\firstAuthor _ ->- switchR "" (\_ -> filter isAlpha) $- words firstAuthor) $- authors- pkgId = PkgD.package pkg- Pkg.PackageName name = Pkg.pkgName pkgId- year = ctYear time- versionStr = showVersion (Pkg.pkgVersion pkgId)- bibId =- map toLower surname ++ show year ++- name ++ "-" ++ versionStr- in Entry.Cons "Misc" bibId $- ("author",- if null authors- then "unknown"- else Format.authorList $- map LaTeX.fromUnicodeString authors) :- ("title",- "{" ++ name ++ ": " ++- LaTeX.fromUnicodeString (PkgD.synopsis pkg) ++ "}") :- ("howpublished",- "\\url{http://hackage.haskell.org" ++- packageURL (PkgD.package pkg) ++ "}") :- ("year", show year) :- ("month", show (ctMonth time)) :- ("version", versionStr) :- ("keywords", "Haskell, " ++ PkgD.category pkg ) :- ("subtype", "program") :- []--example :: IO ()-example =- do now <- toCalendarTime =<< getClockTime- pkg <- readPackageDescription Verbosity.silent "example.cabal"- putStrLn (Format.entry $ fromPackage now $ PkgD.packageDescription pkg)---{- |-This decodes UTF-8 but in contrast to UTF8.toString-it handles invalid characters like Latin-1 ones.-This way we can also cope with many texts that contain actually Latin-1.--}-decodeUTF8orLatin :: B.ByteString -> String-decodeUTF8orLatin =- List.unfoldr (\bstr ->- flip fmap (UTF8.uncons bstr) $ \(c, rest) ->- if c==UTF8.replacement_char- then (chr $ fromIntegral $ B.head bstr, B.tail bstr)- else (c,rest))---fromTarEntry :: Tar.Entry -> String-fromTarEntry ent =- case (List.isSuffixOf ".cabal" $ TarEnt.entryPath ent,- TarEnt.entryContent ent) of- (True, TarEnt.NormalFile txt _size) ->- case parsePackageDescription (decodeUTF8orLatin txt) of- PkgP.ParseOk _ pkg ->- Format.entry $- fromPackage- (toUTCTime (TOD (fromIntegral $ TarEnt.entryTime ent) 0))- (PkgD.packageDescription pkg)- PkgP.ParseFailed msg -> show msg- _ -> ""--main :: IO ()-main =- Tar.foldEntries- (\entry cont -> putStrLn (fromTarEntry entry) >> cont)- (return ()) (IO.hPutStr IO.stderr . show) .- Tar.read =<<- B.getContents
− src/Publications.hs
@@ -1,45 +0,0 @@-module Main where--import qualified Text.BibTeX.Parse as Parse-import qualified Text.BibTeX.Entry as Entry-import qualified Text.ParserCombinators.Parsec as Parsec--import qualified Data.Char as Char-import System.IO (hPutStrLn, stderr, )---typeTable :: [((String, Maybe String), String)]-typeTable =- (("article", Just "reviewed"), "reviewedjournal") :- (("article", Just "popular"), "popular") :- (("article", Nothing), "journal") :- (("inproceedings", Just "reviewed"), "reviewedconference") :- (("inproceedings", Nothing), "conference") :- (("techreport", Nothing), "techreport") :- (("inbook", Just "program"), "program") :- (("misc", Just "program"), "program") :- (("misc", Just "talk"), "talk") :- (("mastersthesis", Nothing), "thesis") :- (("phdthesis", Nothing), "thesis") :- []---cite :: Entry.T -> String-cite entry =- maybe- "% \\nocite"- ("\\nocite" ++ )- (lookup- (map Char.toLower (Entry.entryType entry),- lookup "subtype" (Entry.fields (Entry.lowerCaseFieldNames entry)))- typeTable) ++- "{" ++ Entry.identifier entry ++ "}"---main :: IO ()-main =- do bib <- getContents- case Parsec.parse (Parsec.skipMany Parsec.space >> Parse.file) "stdin" bib of- Left errMsg -> hPutStrLn stderr (show errMsg)- Right entries ->- mapM_ (putStrLn . cite) entries