packages feed

pdfname (empty) → 0.1

raw patch · 10 files changed

+768/−0 lines, 10 filesdep +basedep +directorydep +filepathsetup-changed

Dependencies added: base, directory, filepath, optparse-applicative, pdfinfo, text

Files

+ CHANGELOG.md view
@@ -0,0 +1,7 @@+Changelog for pdfname+=====================++0.1+---++First release.
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2017 Andrés Sicard-Ramírez++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,65 @@+pdfname+=======++Description+-----------++Name a PDF file using information (author, year of creation and title)+from the `pdfinfo` program.++Prerequisites+--------------++* Glasgow Haskell Compiler ([GHC](https://www.haskell.org/ghc/))++* [cabal-install](http://www.haskell.org/cabal/)++* [pdfinfo](http://linuxcommand.org/man_pages/pdfinfo1.html) Unix+  program++Installation+------------++The program can installed with the following commands:++```bash+$ cabal update+$ cabal install+```++Usage+-----++Just run `pdfname` on your PDF file.++How is the file name chosen?+---------------------------++Given the author, year of creation and title information extracted+from the `pdfinfo` program (fields `Author`, `CreationDate` and+`Title`, respectively) the name of the PDF file will be++```+author-year.title.pdf+```++where `author` and `title` are the strings obtained after making+certain substitutions (e.g. remove whitespace, translate non-ASCCI+characters and remove TeX/LaTeX specific information) to the+information shown by the `pdfinfo` program.++Example. Let's suppose that running `pdfinfo` on the file `foo.pdf`+shows the following (fictional and incomplete) information:++```bash+$ pdfinfo foo.pdf+Title:          Introducction to the <TEX>$\lambda$</TEX>-Calculus+Author:         Per Martin-Löf+CreationDate:   Fri Apr  9 07:14:01 2010+```++Now, running `pdfname` on that file will create the new file++```+/tmp/martin-lof-2010.introduction-to-the-lambda-calculus.pdf+```
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ pdfname.cabal view
@@ -0,0 +1,65 @@+name:          pdfname+version:       0.1+license:       MIT+license-file:  LICENSE+author:        Andrés Sicard-Ramírez+maintainer:    Andrés Sicard-Ramírez <asr@eafit.edu.co>+copyright:     Andrés Sicard-Ramírez 2017+homepage:      https://github.com/asr/pdfname#readme+bug-reports:   https://github.com/asr/pdfname/issues+category:      PDF+build-type:    Simple+cabal-version: >= 1.10+synopsis:      Name a PDF file using information from the pdfinfo command+description:+  pdfname names a PDF file using the author, year of creation and+  title information extracted from the pdfinfo program.+tested-with:   GHC == 8.0.2++extra-source-files: CHANGELOG.md+                    README.md++executable pdfname+  main-is:        Main.hs+  hs-source-dirs: src++  build-depends:  base                 >= 4.7.0.2 && < 4.11+                , directory            >= 1.2.1.0 && < 1.4+                , filepath             >= 1.3.0.2 && < 1.5+                , optparse-applicative >= 0.14.0  && < 0.15+                , pdfinfo              >= 1.5.4   && < 1.6+                , text                 >= 1.2.0.4 && < 1.3++  default-language: Haskell2010++  default-extensions:  OverloadedStrings+                     , UnicodeSyntax++  other-modules:  CreateFile+                , Options+                , Paths_pdfname+                , Substituions+                , Utilities++  if impl(ghc >= 8.0)+    ghc-options:  -Wall+                  -Widentities+                  -Wincomplete-record-updates+                  -Wincomplete-uni-patterns+                  -Wderiving-typeable+                  -Wmissing-import-lists+                  -Wmissing-local-signatures+                  -Wmissing-monadfail-instances+                  -Wmissing-pattern-synonym-signatures+                  -Wmonomorphism-restriction+                  -Wnoncanonical-monad-instances+                  -Wnoncanonical-monadfail-instances+                  -Wnoncanonical-monoid-instances+                  -Wredundant-constraints+                  -Wsemigroup+                  -Wunused-binds+                  -Wunused-type-patterns++  if impl(ghc >= 8.2)+    ghc-options: -Wcpp-undef+                 -Wsimplifiable-class-constraints
+ src/CreateFile.hs view
@@ -0,0 +1,120 @@+-- | Creation of the PDF file.++module CreateFile+  ( createFile+  , generateFileName+  ) where++import Data.Char  ( isAscii )+import Data.Maybe ( fromMaybe )++import Data.Text ( Text )+import qualified Data.Text as T++import System.Directory ( copyFile )+import System.FilePath  ( (</>) )++import Text.PDF.Info+  ( PDFInfo+  , pdfInfoAuthor+  , pdfInfoCreationDate+  , pdfInfoTitle+  )++------------------------------------------------------------------------------+-- Local imports++import Options ( outputDir )++import Substituions+  ( authorSubst+  , chSubst+  , titleSubst+  )++import Utilities+  ( (+++)+  , die+  , replace+  )++------------------------------------------------------------------------------+defaultValue ∷ Text+defaultValue = "xx"++getAuthor ∷ Text → Text+getAuthor xs =+  if T.null xs+  then defaultValue+  else+    -- NB that the substituions are not commutative.+    ( replace chSubst+      . T.intercalate (T.singleton '-')+      . map (T.toLower . T.reverse . T.takeWhile (' ' /=) . T.reverse)+      . T.split (',' ==)+      . replace authorSubst+    ) xs++getYear ∷ Text → Text+getYear xs = if T.null xs then defaultValue else T.take 4 xs++getTitle ∷ Text → Text+getTitle xs =+  if T.null xs+  then defaultValue+  else+    -- NB that the substituions are not commutative.+    ( T.toLower+      . replace chSubst+      . replace titleSubst+    ) xs++generateFileName ∷ PDFInfo → IO FilePath+generateFileName info = do++  let authorHelper ∷ Text+      authorHelper = maybe defaultValue getAuthor $ pdfInfoAuthor info++  author ← if validateName authorHelper+           then return authorHelper+           else die $ "could not generate the author from "+                       +++ "`"+                       +++ fromMaybe "missing author field" (pdfInfoAuthor info)+                       +++ "`"++  let year ∷ Text+      year = maybe defaultValue (getYear . T.pack . show ) $ pdfInfoCreationDate info++  let titleHelper ∷ Text+      titleHelper = maybe defaultValue getTitle $ pdfInfoTitle info++  title ← if validateName titleHelper+            then return titleHelper+            else die $ "could not generate the title from "+                       +++ "`"+                       +++ fromMaybe "missing title field" (pdfInfoTitle info)+                       +++ "`"++  let fileName ∷ FilePath+      fileName = T.unpack $ foldl1 T.append+                   [ author+                   , T.singleton '-'+                   , year+                   , T.singleton '.'+                   , title+                   , ".pdf"+                   ]++  return fileName++-- TODO (2017-07-04): Is there Data.Text functions instead of+-- Data.Char functions for implementing this function?+validateName ∷ Text → Bool+validateName t = all (== True) $ map isAscii $ T.unpack t++createFile ∷ FilePath → FilePath → IO ()+createFile f newF =+  copyFile f outputPath >> putStrLn ("Created " ++ outputPath)+  where+  outputPath ∷ FilePath+  outputPath = outputDir </> newF
+ src/Main.hs view
@@ -0,0 +1,66 @@+-- | pdfname: Name a PDF file using the information from the `pdfinfo`+-- command.++module Main where++import qualified Data.Text as T+import qualified Data.Text.IO as T++import Options.Applicative ( execParser )++import System.Exit     ( exitFailure )+import System.FilePath ( (</>) )++import System.IO+  ( hPrint+  , stderr+  )++import Text.PDF.Info ( pdfInfo )++------------------------------------------------------------------------------+-- Local imports++import CreateFile+  ( createFile+  , generateFileName+  )++import Options+  ( options+  , Options( optDryRun+           , optInputFile+           )+  , outputDir+  )++import Utilities+  ( (+++)+  , die+  , isPDF+  , unlessM+  )++------------------------------------------------------------------------------++main ∷ IO ()+main = do+  opts ← execParser options++  let file ∷ FilePath+      file = optInputFile opts++  unlessM (isPDF file) $ die $ T.pack file +++ " is not a PDF file"++  info ← pdfInfo file+  case info of+    Right i → do+      newFile ← generateFileName i+      if optDryRun opts+        then putStrLn $ "The full path name will be " ++ outputDir </> newFile+        else createFile file newFile++    Left  err → do+      T.hPutStr stderr "pdfInfo exception: "+      hPrint stderr err+      exitFailure
+ src/Options.hs view
@@ -0,0 +1,65 @@+-- | Process the command-line arguments.++module Options+  ( options+  , Options( Options -- Improve Haddock information.+           , optDryRun+           , optInputFile+           )+  , outputDir+  ) where++import Data.Monoid ( (<>) )++import Options.Applicative+  ( argument+  , info+  , infoOption+  , help+  , helper+  , long+  , metavar+  , Parser+  , ParserInfo+  , short+  , str+  , switch+  )++------------------------------------------------------------------------------+-- Local imports++import Utilities ( progNameVersion )++------------------------------------------------------------------------------+-- | Program command-line options.+data Options = Options+  { optDryRun    ∷ Bool+  , optInputFile ∷ FilePath+  }++pOptDryRun ∷ Parser Bool+pOptDryRun =+  switch ( long "dry-run"+           <> help ("Do not create the PDF file only print which would be "+                    ++ "its full path name")+         )++-- | Parse a version flag.+pOptVersion ∷ Parser (a → a)+pOptVersion = infoOption progNameVersion $+  long "version"+  <> short 'V'+  <> help "Show version number"++pOptInputFile ∷ Parser FilePath+pOptInputFile = argument str (metavar "FILE")++pOptions :: Parser Options+pOptions = Options <$> pOptDryRun <*> pOptInputFile++options ∷ ParserInfo Options+options = info (helper <*> pOptVersion <*> pOptions) mempty++outputDir ∷ FilePath+outputDir = "/tmp/"
+ src/Substituions.hs view
@@ -0,0 +1,272 @@+-- | Substituions.++module Substituions+  ( authorSubst+  , chSubst+  , titleSubst+  ) where++import Data.Text ( Text )++------------------------------------------------------------------------------+-- Characters substituions++-- If a new entry is added here, please also add it to the+-- characters-decimal substituions.++-- | Characters in non-numeric notation.+chNNSubst ∷ [(Text,Text)]+chNNSubst =+  [ ("&ouml;", "o")  -- LATIN SMALL LETTER O WITH DIAERESIS   (ö)+  , ("&Auml;", "A")  -- LATIN CAPITAL LETTER A WITH DIAERESIS (Ä)+  , ("&Uuml;", "U")  -- LATIN CAPITAL LETTER U WITH DIAERESIS (Ü)+  ]++-- If a new entry is added here, please also add it to the+-- characters-hexadecimal substituions.++-- | Characters substituions in decimal notation.+chDecSubst ∷ [(Text,Text)]+chDecSubst =+  [ ("&#225;",  "a")              -- LATIN SMALL LETTER A WITH ACUTE+  , ("&#233;",  "e")              -- LATIN SMALL LETTER E WITH ACUTE+  , ("&#237;",  "i")              -- LATIN SMALL LETTER I WITH ACUTE+  , ("&#243;",  "o")              -- LATIN SMALL LETTER O WITH ACUTE+  , ("&#246;",  "o")              -- LATIN SMALL LETTER O WITH DIAERESIS (ö)+  , ("&#250;",  "u")              -- LATIN SMALL LETTER U WITH ACUTE+  , ("&#352",   "S")              -- LATIN CAPITAL LETTER S WITH CARON+  , ("&#353",   "s")              -- LATIN SMALL LETTER S WITH CARON+  , ("&#955;",  "lambda")         -- GREEK SMALL LETTER LAMDA+  , ("&#8216;", "")               -- LEFT SINGLE QUOTATION MARK+  , ("&#8217",  "")               -- RIGHT SINGLE QUOTATION MARK+  ]++-- | Characters substituions in hexadecimal notation.+chHexSubst ∷ [(Text,Text)]+chHexSubst =+  [ ("&#x00C4;",  "A")              -- LATIN CAPITAL LETTER A WITH DIAERESIS (Ä)+  , ("&#x00DC;",  "U")              -- LATIN CAPITAL LETTER U WITH DIAERESIS (Ü)+  , ("&#x00E1;",  "a")              -- LATIN SMALL LETTER A WITH ACUTE+  , ("&#x00E9;",  "e")              -- LATIN SMALL LETTER E WITH ACUTE+  , ("&#x00ED;",  "i")              -- LATIN SMALL LETTER I WITH ACUTE+  , ("&#x00F3;",  "o")              -- LATIN SMALL LETTER O WITH ACUTE+  , ("&#x00FA;",  "u")              -- LATIN SMALL LETTER U WITH ACUTE+  , ("&#x00F6;",  "o")              -- LATIN SMALL LETTER O WITH DIAERESIS (ö)+  , ("&#x00FC;",  "u")              -- LATIN SMALL LETTER U WITH DIAERESIS (ü)+  , ("&#x0160",   "S")              -- LATIN CAPITAL LETTER S WITH CARON+  , ("&#x0161",   "s")              -- LATIN SMALL LETTER S WITH CARON+  , ("&#x012A;",  "I")              -- LATIN CAPITAL LETTER I WITH MACRON+  , ("&#x012B;",  "I")              -- LATIN SMALL LETTER I WITH MACRON+  , ("&#x015A;",  "S")              -- LATIN CAPITAL LETTER S WITH ACUTE+  , ("&#x015B;",  "s")              -- LATIN SMALL LETTER S WITH ACUTE+  , ("&#x015E;",  "s")              -- LATIN CAPITAL LETTER S WITH CEDILLA+  , ("&#x015F;",  "s")              -- LATIN SMALL LETTER S WITH CEDILLA+  , ("&#x012A;",  "I")              -- LATIN CAPITAL LETTER I WITH MACRON+  , ("&#x012B;",  "i")              -- LATIN SMALL LETTER I WITH MACRON+  , ("&#x03B1;",  "alpha")          -- GREEK SMALL LETTER ALPHA+  , ("&#x03B2;",  "beta")           -- GREEK SMALL LETTER BETA+  , ("&#x03B3;",  "gamma")          -- GREEK SMALL LETTER GAMMA+  , ("&#x03B4;",  "delta")          -- GREEK SMALL LETTER DELTA+  , ("&#x03B5;",  "epsilon")        -- GREEK SMALL LETTER EPSILON+  , ("&#x03B6;",  "zeta")           -- GREEK SMALL LETTER ZETA+  , ("&#x03B7;",  "eta")            -- GREEK SMALL LETTER ETA+  , ("&#x03B8;",  "theta")          -- GREEK SMALL LETTER THETA+  , ("&#x03B9;",  "iota")           -- GREEK SMALL LETTER IOTA+  , ("&#x03BA;",  "kappa")          -- GREEK SMALL LETTER KAPPA+  , ("&#x03BB;",  "lambda")         -- GREEK SMALL LETTER LAMDA+  , ("&#x03BC;",  "mu")             -- GREEK SMALL LETTER MU+  , ("&#x03BD;",  "nu")             -- GREEK SMALL LETTER NU+  , ("&#x03BE;",  "xi")             -- GREEK SMALL LETTER XI+  , ("&#x03BF;",  "omicron")        -- GREEK SMALL LETTER OMICRON+  , ("&#x03C0;",  "pi")             -- GREEK SMALL LETTER PI+  , ("&#x03C1;",  "rho")            -- GREEK SMALL LETTER RHO+  , ("&#x03C2;",  "sigma")          -- GREEK SMALL LETTER FINAL SIGMA+  , ("&#x03C3;",  "sigma")          -- GREEK SMALL LETTER SIGMA+  , ("&#x03C4;",  "tau")            -- GREEK SMALL LETTER TAU+  , ("&#x03C5;",  "upsilon")        -- GREEK SMALL LETTER UPSILON+  , ("&#x03C6;",  "phi")            -- GREEK SMALL LETTER PHI+  , ("&#x03C7;",  "chi")            -- GREEK SMALL LETTER CHI+  , ("&#x03C8;",  "psi")            -- GREEK SMALL LETTER PSI+  , ("&#x03C9;",  "omega")          -- GREEK SMALL LETTER OMEGA+  , ("&#x2010;",  "-")              -- HYPHEN+  , ("&#x2013;",  "-")              -- EN DASH+  , ("&#x2014;",  ".")              -- EM DAS+  , ("&#x2018;",  "")               -- LEFT SINGLE QUOTATION MARK+  , ("&#x2019;",  "")               -- RIGHT SINGLE QUOTATION MARK+  , ("&#x201A;",  "")               -- SINGLE LOW-9 QUOTATION MAR+  , ("&#x201C;",  "")               -- LEFT DOUBLE QUOTATION MARK+  , ("&#x201D;",  "")               -- RIGHT DOUBLE QUOTATION MARK+  , ("&#x201E;",  "")               -- DOUBLE LOW-9 QUOTATION MARK+  , ("&#x2020;",  "dagger")         -- DAGGER+  , ("&#x2021;",  "dagger-dagger")  -- DOUBLE DAGGER+  , ("&#x2022;",  "")               -- BULLET+  , ("&#x2026;",  "")               -- HORIZONTAL ELLIPSIS+  , ("&#x2283;",  "")               -- SUPERSET OF+  , ("&#x231D;",  "")               -- TOP RIGHT CORNER+  , ("&#x02010;", "-")              -- HYPHEN+  ]++-- | Characters substituions in Unicode notation.+chUnicodeSubst ∷ [(Text,Text)]+chUnicodeSubst =+  [ ("\r",          "")         -- U+000D CARRIAGE RETURN (CR)+  , (" ",           "-")        -- U+0020 SPACE+  , ("!",           "")         -- U+0021 EXCLAMATION MARK+  , ("\"",          "")         -- U+0022 QUOTATION MARK+  , ("#",           "")         -- U+0023 NUMBER SIGN+  , ("$",           "")         -- U+0024 DOLLAR SIGN+  , ("&",           "")         -- U+0026 AMPERSAND+  , ("'",           "")         -- U+0027 APOSTROPHE+  , ("(",           "")         -- U+0028 LEFT PARENTHESIS+  , (")",           "")         -- U+0029 RIGHT PARENTHESIS+  , ("*",           "")         -- U+002A ASTERISK+  , ("+",           "")         -- U+002B PLUS SIGN+  , (",",           "")         -- U+002C COMMA+  , ("/",           "-")        -- U+002F SOLIDUS+  , ("²",           "2")        -- U+00B2 SUPERSCRIPT TWO+  , ("³",           "3")        -- U+00B3 SUPERSCRIPT THREE+  , ("¹",           "1")        -- U+00B9 SUPERSCRIPT ONE+  , (":",           ".")        -- U+003A COLON+  , (";",           ".")        -- U+003B SEMICOLON+  , ("<",           "")         -- U+003C LESS-THAN SIGN+  , ("=",           "")         -- U+003D EQUALS SIGN+  , (">",           "")         -- U+003E GREATER-THAN SIGN+  , ("?",           "")         -- U+003F QUESTION MARK+  , ("@",           "")         -- U+0040 COMMERCIAL AT+  , ("[",           "")         -- U+005B LEFT SQUARE BRACKET+  , ("\\",          "")         -- U+005C REVERSE SOLIDUS+  , ("]",           "")         -- U+005D RIGHT SQUARE BRACKET+  , ("_",           "-")        -- U+005F LOW LINE+  , ("`",           "")         -- U+0060 GRAVE ACCENT+  , ("|",           "")         -- U+007C VERTICAL LINE+  , ("¡",           "")         -- U+00A1 INVERTED EXCLAMATION MARK+  , ("¬",           "")         -- U+00AC NOT SIGN+  , ("À",           "A")        -- U+00C0 LATIN CAPITAL LETTER A WITH GRAVE+  , ("Á",           "A")        -- U+00C1 LATIN CAPITAL LETTER A WITH ACUTE+  , ("Ã",           "A")        -- U+00C3 LATIN CAPITAL LETTER A WITH TILDE+  , ("Æ",           "E")        -- U+00C6 LATIN CAPITAL LETTER AE+  , ("É",           "E")        -- U+00C9 LATIN CAPITAL LETTER E WITH ACUTE+  , ("Í",           "I")        -- U+00CD LATIN CAPITAL LETTER I WITH ACUTE+  , ("Ñ",           "N")        -- U+00D1 LATIN CAPITAL LETTER N WITH TILDE+  , ("Ó",           "O")        -- U+00D3 LATIN CAPITAL LETTER O WITH ACUTE+  , ("Ú",           "U")        -- U+00DA LATIN CAPITAL LETTER U WITH ACUTE+  , ("Ö",           "O")        -- U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS+  , ("×",           "")         -- U+00D7 MULTIPLICATION SIGN+  , ("à",           "a")        -- U+00E0 LATIN SMALL LETTER A WITH GRAVE+  , ("á",           "a")        -- U+00E1 LATIN SMALL LETTER A WITH ACUTE+  , ("â",           "a")        -- U+00E2 LATIN SMALL LETTER A CIRCUMFLEX+  , ("ã",           "a")        -- U+00E3 LATIN SMALL LETTER A WITH TILDE+  , ("ä",           "a")        -- U+00E4 LATIN SMALL LETTER A WITH DIAERESIS+  , ("æ",           "e")        -- U+00E6 LATIN SMALL LETTER AE+  , ("ç",           "c")        -- U+00E7 LATIN SMALL LETTER C WITH CEDILLA+  , ("é",           "e")        -- U+00E9 LATIN SMALL LETTER E WITH ACUTE+  , ("í",           "i")        -- U+00ED LATIN SMALL LETTER I WITH ACUTE+  , ("ñ",           "n")        -- U+00F1 LATIN SMALL LETTER N WITH TILDE+  , ("ò",           "o")        -- U+00F2 LATIN SMALL LETTER O WITH GRAVE+  , ("ó",           "o")        -- U+00F3 LATIN SMALL LETTER O WITH ACUTE+  , ("ö",           "o")        -- U+00F6 LATIN SMALL LETTER O WITH DIAERESIS+  , ("ø",           "o")        -- U+00F8 LATIN SMALL LETTER O WITH STROKE+  , ("ú",           "u")        -- U+00FA LATIN SMALL LETTER U WITH ACUTE+  , ("ü",           "u")        -- U+00FC LATIN SMALL LETTER U WITH DIAERESIS+  , ("þ",           "t")        -- U+00FE LATIN SMALL LETTER THORN+  , ("ÿ",           "y")        -- U+00FF LATIN SMALL LETTER Y WITH DIAERESIS+  , ("ć",           "c")        -- U+0107 LATIN SMALL LETTER C WITH ACUTE+  , ("č",           "c")        -- U+010D LATIN SMALL LETTER C WITH CARON+  , ("Ł",           "L")        -- U+0141 LATIN CAPITAL LETTER L WITH STROKE+  , ("ņ",           "n")        -- U+0146 LATIN SMALL LETTER N WITH CEDILLA+  , ("ř",           "r")        -- U+0159 LATIN SMALL LETTER R WITH CARON+  , ("š",           "s")        -- U+0161 LATIN SMALL LETTER S WITH CARON+  , ("ū",           "u")        -- U+016B LATIN SMALL LETTER U WITH MACRON+  , ("Ÿ",           "Y")        -- U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS+  , ("Ω",           "Omega")    -- U+03A9 GREEK CAPITAL LETTER OMEGA+  , ("α",           "alpha")    -- U+03B1 GREEK SMALL LETTER ALPHA+  , ("β",           "beta")     -- U+03B2 GREEK SMALL LETTER BETA+  , ("γ",           "gamma")    -- U+03B3 GREEK SMALL LETTER GAMMA+  , ("δ",           "delta")    -- U+03B4 GREEK SMALL LETTER DELTA+  , ("ε",           "epsilon")  -- U+03B5 GREEK SMALL LETTER EPSILON+  , ("ζ",           "zeta")     -- U+03B6 GREEK SMALL LETTER ZETA+  , ("η",           "eta")      -- U+03B7 GREEK SMALL LETTER ETA+  , ("θ",           "theta")    -- U+03B8 GREEK SMALL LETTER THETA+  , ("ι",           "iota")     -- U+03B9 GREEK SMALL LETTER IOTA+  , ("κ",           "kappa")    -- U+03BA GREEK SMALL LETTER KAPPA+  , ("λ",           "lambda")   -- U+03BB GREEK SMALL LETTER LAMDA+  , ("μ",           "mu")       -- U+03BC GREEK SMALL LETTER MU+  , ("ν",           "nu")       -- U+03BD GREEK SMALL LETTER NU+  , ("ξ",           "xi")       -- U+03BE GREEK SMALL LETTER ZI+  , ("ο",           "omicron")  -- U+03BF GREEK SMALL LETTER OMICRON+  , ("π",           "pi")       -- U+03C0 GREEK SMALL LETTER PI+  , ("ρ",           "rho")      -- U+03C1 GREEK SMALL LETTER RHO+  , ("σ",           "sigma")    -- U+03C3 GREEK SMALL LETTER SIGMA+  , ("ς",           "sigma")    -- U+03C2 GREEK SMALL LETTER FINAL SIGMA+  , ("τ",           "tau")      -- U+03C4 GREEK SMALL LETTER TAU+  , ("υ",           "upsilon")  -- U+03C5 GREEK SMALL LETTER UPSILON+  , ("φ",           "phi")      -- U+03C6 GREEK SMALL LETTER PHI+  , ("χ",           "chi")      -- U+03C7 GREEK SMALL LETTER CHI+  , ("ψ",           "psi")      -- U+03C8 GREEK SMALL LETTER PSI+  , ("ω",           "omega")    -- U+03C9 GREEK SMALL LETTER OMEGA+  , ("–",           "-")        -- U+2013 EN DASH+  , ("—",           "-")        -- U+2014 EM DASH+  , ("‘",           "")         -- U+2018 LEFT SINGLE QUOTATION MARK+  , ("’",           "")         -- U+2019 RIGHT SINGLE QUOTATION MARK+  , ("‡",           "")         -- U+2021 DOUBLE DAGGER+  , ("™",           "")         -- U+2122 TRADE MARK SIGN+  , ("�",          "")         -- U+FFFD REPLACEMENT CHARACTER+  ]++-- | All the characters substituions.+-- NB that the substituions are not commutative.+chSubst ∷ [(Text, Text)]+chSubst =  chHexSubst ++ chNNSubst ++ chDecSubst ++ chUnicodeSubst++------------------------------------------------------------------------------+-- Author substituions++authorSubst ∷ [(Text, Text)]+authorSubst =+  [ (", ",   ",")+  , (" and", ",")+  -- See Issue #1.+  , ("Ã\x00AD", "i")  -- U+00C3 and U+00AD+  -- See Issue #1.+  , ("á",      "a")  -- U+00C3 and U+00A1+  , ("Mcbride", "McBride")+  ]++------------------------------------------------------------------------------+-- Title substituions++-- These substituions should be done before converting to lower case.+titleSubst ∷ [(Text,Text)]+titleSubst =+  [ ("<Emphasis Type=\"BoldItalic\">P </Emphasis>",       "P")+  , ("<Emphasis Type=\"Italic\">0 </Emphasis>",           "0")+  , ("<Emphasis Type=\"Italic\">C</Emphasis>",            "C")+  , ("<Emphasis Type=\"Italic\">CC</Emphasis>",           "CC")+  , ("<Emphasis Type=\"Italic\">I </Emphasis>",           "I")+  , ("<Emphasis Type=\"Italic\">J</Emphasis>",            "J")+  , ("<Emphasis Type=\"Italic\">Modus ponens</Emphasis>", "Modus ponens")+  , ("<Emphasis Type=\"Italic\">P </Emphasis>",           "P")+  , ("<Emphasis Type=\"Italic\">really </Emphasis>",      "really")+  , ("<Emphasis Type=\"Italic\">S-P</Emphasis>",          "S-P")+  , ("<Subscript>3</Subscript>",                          "3")+  -- The whitespace around `+` is not the standard one.+  -- TODO (2017-07-04): Added test case.+  , ("<Superscript> + </Superscript>",                    "plus")+  , ("<Subscript>&#x03C9;</Subscript>",                   "omega")+  , ("<TEX>$\\alpha$</TEX>",                              "alpha")+  , ("<TEX>$\\beta$</TEX>",                               "beta")+  , ("<TEX>$\\gamma$</TEX>",                              "gamma")+  , ("<TEX>$\\epsilon$</TEX>",                            "epsilon")+  , ("<TEX>$\\eta$</TEX>",                                "eta")+  -- See Issue #2.+  , ("<TEX>$\\lambda$</TEX>",                             "lambda")+  , ("<TEX>$\\pi$</TEX>",                                 "pi")+  , ("<TEX>$\\omega$</TEX>",                              "omega")+  , ("<TEX>{\\sc Coq}</TEX>",                             "Coq")+  , ("<TEX>{\\sf Haskell}</TEX>:",                        "Haskell")+  , ("<TEX>{\\sc QuickSpec}</TEX>:",                      "QuickSpec")+  , ("<TEX>{\\sc QuodLibet}</TEX>!",                      "QuodLibet")+  , ("<TEX>{\\sc Vampire}</TEX>",                         "Vampire")+  , ("Å›", "s")  -- U+00C5 and U+203A+  , ("ö", "")   -- U+00C3 and U+00B6+  ]
+ src/Utilities.hs view
@@ -0,0 +1,85 @@+-- | Utilities.++module Utilities+ ( (+++)+ , die+ , ifM+ , isPDF+ , progNameVersion+ , replace+ , unless_+ , unlessM+ , upperFirst+ ) where++import Data.Char ( toUpper )++import Data.Text ( Text )+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Data.Version ( showVersion )++import Control.Monad ( replicateM, unless, void )++import Paths_pdfname ( version )++import System.Environment ( getProgName )+import System.Exit        ( exitFailure )++import System.IO+  ( IOMode(ReadMode)+  , hGetChar+  , stderr+  , withBinaryFile+  )++------------------------------------------------------------------------------+-- Utilities from the Agda library++ifM ∷ Monad m ⇒ m Bool → m a → m a → m a+ifM c m m' = do+  b ← c+  if b then m else m'++-- | @unless_@ is just @Control.Monad.unless@ with a more general type.+unless_ ∷ Monad m ⇒ Bool → m a → m ()+unless_ b m = unless b $ void m++unlessM ∷ Monad m ⇒ m Bool → m a → m ()+unlessM c m = c >>= (`unless_` m)++------------------------------------------------------------------------------+-- Utilities++die ∷ Text → IO a+die err = do+  progName ← getProgName+  T.hPutStrLn stderr (T.pack progName +++ ": " +++ err)+  exitFailure++replace ∷ [(Text,Text)] → Text → Text+replace xs ys = foldl (flip (uncurry T.replace)) ys xs++-- | Uppercase the first character of a text.+upperFirst ∷ Text → Text+upperFirst xs =+  case T.uncons xs of+    Nothing        → T.empty+    Just (x', xs') → T.cons (toUpper x') (T.toLower xs')++-- | Append synonymous.+(+++) ∷ Text → Text → Text+(+++) = T.append++-- | Return version information.+-- TODO (2017-07-06): To use `getProgName`.+progNameVersion ∷ String+progNameVersion = "pdfname" ++ " version " ++ showVersion version++isPDF ∷ FilePath → IO Bool+isPDF f =+  ifM ((==) "%PDF" <$> withBinaryFile f ReadMode (replicateM 4 . hGetChar))+      (return True)+      (return False)+