packages feed

bibtex 0.0.3 → 0.0.4

raw patch · 5 files changed

+355/−49 lines, 5 filesdep +containersdep +utf8-stringPVP ok

version bump matches the API change (PVP)

Dependencies added: containers, utf8-string

API changes (from Hackage documentation)

Files

Makefile view
@@ -14,7 +14,8 @@ 	(cd $(dir $<); pdflatex $(notdir $<); pdflatex $(notdir $<))  %-cite.tex:	%.bib-	ghc -e main src/Publications.hs < $< >$@+	./dist/build/publication-overview/publication-overview < $< >$@+#	ghc -e main src/Publications.hs < $< >$@  %.bbl:	%.aux tex/publications.bib 	(cd $(dir $<); bibtex $(notdir $*))@@ -25,6 +26,6 @@  hackbib:	hackage.bib -hackage.bib:	$(HOME)/.cabal/packages/hackage.haskell.org/00-index.tar.gz-	gunzip --stdout $< | ghc -e main src/Hackage.hs >$@-#	gunzip --stdout $< | hackage-bibtex >$@+hackage.bib:	$(HOME)/.cabal/packages/hackage.haskell.org/00-index.tar.gz src/Hackage.hs+	gunzip --stdout $< | ./dist/build/hackage-bibtex/hackage-bibtex >$@+#	gunzip --stdout $< | ghc -e main src/Hackage.hs >$@
bibtex.cabal view
@@ -1,5 +1,5 @@ Name:             bibtex-Version:          0.0.3+Version:          0.0.4 License:          BSD3 License-File:     LICENSE Author:           Henning Thielemann <haskell@henning-thielemann.de>@@ -44,6 +44,22 @@   The file @hackage.bib@ is written to the current directory.   The program reads an uncompressed tar archive from standard input   and writes the result bibliography file to standard output.+  .+  Note that @hackage.bib@ exceeds some limits of standard BibTeX and LaTeX:+  There are currently much more than 5000 versions of packages,+  the maximum my BibTeX can handle at once.+  That is, you can use the bibliography file,+  but you cannot cite all entries with @\\nocite*@.+  If there are more than 26 uploads by the same author in a year,+  the BibTeX style @alpha@ generates identifiers including curly braces+  -- like @Thi2009\{@,+  which interacts badly with LaTeX's handling of them.+  If you reduce the Bibliography file to 5000 entries+  and try to generate an overview of all entries with @\\nocite@,+  -- @\\nocite{*}@,+  then @pdflatex@ hits its limits:+  .+  > TeX capacity exceeded, sorry [save size=5000] Tested-With:      GHC==6.10.4 Cabal-Version:    >=1.6 Build-Type:       Simple@@ -58,7 +74,7 @@ Source-Repository this   type:     darcs   location: http://code.haskell.org/~thielema/bibtex/-  tag:      0.0.3+  tag:      0.0.4  Flag base2   description: Choose the new smaller, split-up base package.@@ -70,6 +86,7 @@ Library   Build-Depends:     parsec >=2.1 && <3.1,+    containers >= 0.1 && <0.4,     utility-ht >=0.0.5 && <0.1   If flag(base2)     Build-Depends:@@ -102,6 +119,7 @@       old-time >=1.0 && <1.1,       Cabal >=1.6 && <1.10,       tar >=0.3 && <0.4,+      utf8-string >=0.3.4 && <0.4,       bytestring >=0.9 && <0.10   Else     Buildable:      False
src/Hackage.hs view
@@ -1,5 +1,9 @@ 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@@ -17,14 +21,17 @@  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.List.HT (dropWhileRev, )-import Data.Char    (toLower, isSpace, isAlpha, chr, )-import Data.Version (showVersion, )+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  @@ -35,68 +42,127 @@ packageURL pkgid = "/package/" ++ display pkgid  -fromPackage :: CalendarTime -> PackageDescription -> String+{- |+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 author =-          let str = dropWhile isSpace $ PkgD.author pkg-          in  case str of-                 '"' : t -> takeWhile ('"' /=) t-                 _ -> dropWhileRev isSpace $ takeWhile ('<' /=) str+   let authors =+          splitAuthorList $ PkgD.author pkg        surname =-          let nameParts = words author-          in  if null nameParts-                then ""-                else filter isAlpha $ last nameParts+          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)-   in  unlines $-       ("@Misc{" ++ map toLower surname ++ show year ++-                    name ++ "-" ++ versionStr ++ ",") :-       map (\(field,value) -> "  " ++ field ++ " = {" ++ value ++ "},") (-          ("author", author) :-          ("title", "{" ++ name ++ ": " ++ 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") :-          []) ++-       "}" :+       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 (fromPackage now (PkgD.packageDescription pkg))+      putStrLn (Format.entry $ fromPackage now $ PkgD.packageDescription pkg)  -fromTarEntry :: Tar.Entry -> String+{- |+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 -> B.ByteString fromTarEntry ent =    if List.isSuffixOf ".cabal" (TarEnt.entryPath ent)      then        case TarEnt.entryContent ent of           TarEnt.NormalFile txt _size ->-             case parsePackageDescription-                     (map (chr . fromIntegral) (B.unpack txt)) of+             UTF8.fromString $+             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-          _ -> ""-     else ""+          _ -> B.empty+     else B.empty  main :: IO () main =    Tar.foldEntries       (\entry cont ->-         putStrLn (fromTarEntry entry) >> cont)+         B.putStrLn (fromTarEntry entry) >> cont)       (return ()) (IO.hPutStr IO.stderr) .    Tar.read =<<    B.getContents
src/Text/BibTeX/Format.hs view
@@ -14,7 +14,7 @@          "  "++name++" = {"++value++"},\n"    in  "@" ++ entryType ++ "{" ++ bibId ++ ",\n" ++        concatMap formatItem items ++-       "}\n\n"+       "}\n"   enumerate :: [String] -> String
src/Text/LaTeX/Character.hs view
@@ -1,17 +1,79 @@-module Text.LaTeX.Character where+module Text.LaTeX.Character (+   toUnicodeString,+   fromUnicodeString,+   table,+   ) where -import Data.List.HT (multiReplace, )-import Data.Tuple.HT (swap, )+-- import Data.List.HT (multiReplace, )+import Data.Tuple.HT (mapSnd, )+import Data.Char (isLetter, chr, ord, )+import qualified Data.Map as Map  +{- |+Replace LaTeX macros for special characters+by Unicode characters in a lazy way.+-} toUnicodeString :: String -> String-toUnicodeString = multiReplace table+toUnicodeString =+   filter (not . flip elem "{}") .+   toUnicodeStringCore+{-+toUnicodeString =+   multiReplace table+-} +toUnicodeStringCore :: String -> String+toUnicodeStringCore "" = ""+toUnicodeStringCore (c:cs) =+   case c of+     '\\' ->+       let getArgument "" = ("", "")+           getArgument (a:argsuffix) =+              if a/='{'+                then ([a], argsuffix)+                else+                  {-+                  this does not support nested curly braces,+                  however, I have no argument with braces in my dictionary+                  -}+                  let (argstr, suffix) = break ('}'==) argsuffix+                  in  (argstr, drop 1 suffix)+           translateInvocation = do+              (macro,(arg,rest)) <-+                 case cs of+                    [] -> Nothing+                    b:bs -> Just $+                       if elem b "'`^\"~"+                         then ([b], getArgument bs)+                         else mapSnd getArgument $+                              span isLetter cs+              code <- Map.lookup (macro,arg) toMap+              return (code, rest)+       in  case translateInvocation of+              Just (code,rest) -> code : toUnicodeStringCore rest+              Nothing -> c : toUnicodeStringCore cs+     '$' ->+        let (math, rest) = break ('$'==) cs+        in  parseMathString math ++ toUnicodeStringCore (drop 1 rest)+     _ -> c : toUnicodeStringCore cs++parseMathString :: String -> String+parseMathString "" = ""+parseMathString (c:cs) =+   if c/='\\'+     then c : parseMathString cs+     else let (ident,rest) = span isLetter cs+          in  maybe ('\\':ident) (:[])+                 (Map.lookup ident mathMap) +++              parseMathString rest+ fromUnicodeString :: String -> String fromUnicodeString =-   multiReplace (map swap table)-+   concatMap (\c -> Map.findWithDefault [c] c fromMap)+--   multiReplace (map swap table) +{-# DEPRECATED table "use toUnicodeString or fromUnicodeString" #-} table :: [(String, String)] table =    ("\\&",    "&") :@@ -27,4 +89,163 @@    ("\\'e",   "é") :    ("\\'a",   "á") :    ("\\'{\\i}", "í") :+   ("\\'u",   "ú") :+   ("\\'U",   "Ú") :+   ("\\o{}", "ø") :+   ("\\O{}", "Ø") :+   ("\\oe{}", "œ") :+   ("\\OE{}", "Œ") :+   ("\\ae{}", "æ") :+   ("\\AE{}", "Æ") :+   ("\\l{}", "ł") :+   ("\\L{}", "Ł") :+   ("\\c{c}", "ç") :+   ("\\c{C}", "Ç") :+   ("\\~a", "ã") :+   ("\\~A", "Ã") :    []+++fromMap :: Map.Map Char String+fromMap =+   Map.fromList+      (do (base, variants) <- accents+          (accent, code) <- variants+          return (chr code, '\\':accent:'{':base:'}':""))+   `Map.union`+   Map.fromList+      (map (\(ident, code) -> (chr code, "\\"++ident++"{}")) specialChars)+   `Map.union`+   Map.fromList+      -- curly braces around dollars assert that no $$ can occur in the output+      (map (\(ident, code) -> (chr code, "{$\\"++ident++"$}")) mathChars)+   `Map.union`+   Map.fromList+      (map (\c -> (c, '\\':c:[])) escapedChars)+++toMap :: Map.Map (String, String) Char+toMap =+   Map.fromList+      (do (base, variants) <- accents+          (accent, code) <- variants+          return (([accent], [base]), chr code))+   `Map.union`+   Map.fromList+      (map (\(ident, code) -> ((ident, ""), chr code)) specialChars)+   `Map.union`+   Map.fromList+      (map (\c -> (('\\':c:[], ""), c)) escapedChars)+++accents :: [(Char, [(Char, Int)])]+accents =+   ('A', ('`', 192) : ('\'', 193) : ('^', 194) : ('~', 195) : ('"', 196) : []) :+   ('E', ('`', 200) : ('\'', 201) : ('^', 202) : ('"', 203) : []) :+   ('I', ('`', 204) : ('\'', 205) : ('^', 206) : ('"', 207) : []) :+   ('N', ('~', 209) : []) :+   ('O', ('`', 210) : ('\'', 211) : ('^', 212) : ('~', 213) : ('"', 214) : []) :+   ('U', ('`', 217) : ('\'', 218) : ('^', 219) : ('"', 220) : []) :+   ('Y', ('"', 223) : ('\'', 221) : []) :+   ('C', ('c', 199) : ('\'', 262) : ('^', 264) : ('.', 266) : ('v', 268) : []) :+   ('S', ('c', 350) : ('\'', 346) : ('^', 348) : ('v', 352) : []) :+   ('a', ('`', 224) : ('\'', 225) : ('^', 227) : ('"', 228) : []) :+   ('e', ('`', 232) : ('\'', 233) : ('^', 234) : ('"', 235) : []) :+   ('i', ('`', 236) : ('\'', 237) : ('^', 238) : ('"', 239) : []) :+   ('n', ('~', 241) : []) :+   ('o', ('`', 242) : ('\'', 243) : ('^', 244) : ('~', 245) : ('"', 246) : []) :+   ('u', ('`', 249) : ('\'', 250) : ('^', 251) : ('"', 252) : []) :+   ('y', ('"', 255) : ('\'', 253) : []) :+   ('c', ('c', 231) : ('\'', 263) : ('^', 265) : ('.', 267) : ('v', 269) : []) :+   ('s', ('c', 351) : ('\'', 347) : ('^', 349) : ('"', 223) : ('v', 353) : []) :+   []++specialChars :: [(String, Int)]+specialChars =+   ("cc", 231) :+   ("cC", 199) :+   ("aa", 229) :+   ("AA", 197) :+   ("i",  239) :+   ("l",  321) :+   ("L",  322) :+   ("ss", 223) :+   ("3",  223) :+   ("o",  248) :+   ("O",  216) :+   ("ae", 230) :+   ("AE", 198) :+   ("S", 167) :+   ("pounds", 163) :+   ("euro", 8364) :+   ("copyright", 169) :++   ("textbackslash", ord '\\') :+   ("textasciitilde", ord '~') :+   ("textasciicircum", ord '^') :+   ("textless", ord '<') :+   ("textgreater", ord '>') :+   ("textdollar", ord '$') :+   ("textexclamdown", 161) :+   ("textquestiondown", 191) :+   ("textquotedblleft", ord '"') :+   []++mathMap :: Map.Map String Char+mathMap =+   Map.fromList (map (\(name,code) -> (name, chr code)) mathChars)++mathChars :: [(String, Int)]+mathChars =+   ("Alpha",      913) :+   ("Beta",       914) :+   ("Gamma",      915) :+   ("Delta",      916) :+   ("Epsilon",    917) :+   ("Zeta",       918) :+   ("Eta",        919) :+   ("Theta",      920) :+   ("Iota",       921) :+   ("Kappa",      922) :+   ("Lambda",     923) :+   ("Mu",         924) :+   ("Nu",         925) :+   ("Xi",         926) :+   ("Omikron",    927) :+   ("Pi",         928) :+   ("Rho",        929) :+   ("Sigma",      931) :+   ("Tau",        932) :+   ("Upsilon",    933) :+   ("Phi",        934) :+   ("Chi",        935) :+   ("Psi",        936) :+   ("Omega",      937) :+   ("alpha",      945) :+   ("beta",       946) :+   ("gamma",      947) :+   ("delta",      948) :+   ("epsilon",    949) :+   ("zeta",       950) :+   ("eta",        951) :+   ("theta",      952) :+   ("iota",       953) :+   ("kappa",      954) :+   ("lambda",     955) :+   ("mu",         956) :+   ("nu",         957) :+   ("xi",         958) :+   ("omikron",    959) :+   ("pi",         960) :+   ("rho",        961) :+   ("sigma",      963) :+   ("tau",        964) :+   ("upsilon",    965) :+   ("phi",        966) :+   ("chi",        967) :+   ("psi",        968) :+   ("omega",      969) :+   []++escapedChars :: [Char]+escapedChars = "$%&_#{}"