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 +7/−0
- LICENSE +21/−0
- README.md +65/−0
- Setup.hs +2/−0
- pdfname.cabal +65/−0
- src/CreateFile.hs +120/−0
- src/Main.hs +66/−0
- src/Options.hs +65/−0
- src/Substituions.hs +272/−0
- src/Utilities.hs +85/−0
+ 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 =+ [ ("ö", "o") -- LATIN SMALL LETTER O WITH DIAERESIS (ö)+ , ("Ä", "A") -- LATIN CAPITAL LETTER A WITH DIAERESIS (Ä)+ , ("Ü", "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 =+ [ ("á", "a") -- LATIN SMALL LETTER A WITH ACUTE+ , ("é", "e") -- LATIN SMALL LETTER E WITH ACUTE+ , ("í", "i") -- LATIN SMALL LETTER I WITH ACUTE+ , ("ó", "o") -- LATIN SMALL LETTER O WITH ACUTE+ , ("ö", "o") -- LATIN SMALL LETTER O WITH DIAERESIS (ö)+ , ("ú", "u") -- LATIN SMALL LETTER U WITH ACUTE+ , ("Š", "S") -- LATIN CAPITAL LETTER S WITH CARON+ , ("š", "s") -- LATIN SMALL LETTER S WITH CARON+ , ("λ", "lambda") -- GREEK SMALL LETTER LAMDA+ , ("‘", "") -- LEFT SINGLE QUOTATION MARK+ , ("’", "") -- RIGHT SINGLE QUOTATION MARK+ ]++-- | Characters substituions in hexadecimal notation.+chHexSubst ∷ [(Text,Text)]+chHexSubst =+ [ ("Ä", "A") -- LATIN CAPITAL LETTER A WITH DIAERESIS (Ä)+ , ("Ü", "U") -- LATIN CAPITAL LETTER U WITH DIAERESIS (Ü)+ , ("á", "a") -- LATIN SMALL LETTER A WITH ACUTE+ , ("é", "e") -- LATIN SMALL LETTER E WITH ACUTE+ , ("í", "i") -- LATIN SMALL LETTER I WITH ACUTE+ , ("ó", "o") -- LATIN SMALL LETTER O WITH ACUTE+ , ("ú", "u") -- LATIN SMALL LETTER U WITH ACUTE+ , ("ö", "o") -- LATIN SMALL LETTER O WITH DIAERESIS (ö)+ , ("ü", "u") -- LATIN SMALL LETTER U WITH DIAERESIS (ü)+ , ("Š", "S") -- LATIN CAPITAL LETTER S WITH CARON+ , ("š", "s") -- LATIN SMALL LETTER S WITH CARON+ , ("Ī", "I") -- LATIN CAPITAL LETTER I WITH MACRON+ , ("ī", "I") -- LATIN SMALL LETTER I WITH MACRON+ , ("Ś", "S") -- LATIN CAPITAL LETTER S WITH ACUTE+ , ("ś", "s") -- LATIN SMALL LETTER S WITH ACUTE+ , ("Ş", "s") -- LATIN CAPITAL LETTER S WITH CEDILLA+ , ("ş", "s") -- LATIN SMALL LETTER S WITH CEDILLA+ , ("Ī", "I") -- LATIN CAPITAL LETTER I WITH MACRON+ , ("ī", "i") -- LATIN SMALL LETTER I WITH MACRON+ , ("α", "alpha") -- GREEK SMALL LETTER ALPHA+ , ("β", "beta") -- GREEK SMALL LETTER BETA+ , ("γ", "gamma") -- GREEK SMALL LETTER GAMMA+ , ("δ", "delta") -- GREEK SMALL LETTER DELTA+ , ("ε", "epsilon") -- GREEK SMALL LETTER EPSILON+ , ("ζ", "zeta") -- GREEK SMALL LETTER ZETA+ , ("η", "eta") -- GREEK SMALL LETTER ETA+ , ("θ", "theta") -- GREEK SMALL LETTER THETA+ , ("ι", "iota") -- GREEK SMALL LETTER IOTA+ , ("κ", "kappa") -- GREEK SMALL LETTER KAPPA+ , ("λ", "lambda") -- GREEK SMALL LETTER LAMDA+ , ("μ", "mu") -- GREEK SMALL LETTER MU+ , ("ν", "nu") -- GREEK SMALL LETTER NU+ , ("ξ", "xi") -- GREEK SMALL LETTER XI+ , ("ο", "omicron") -- GREEK SMALL LETTER OMICRON+ , ("π", "pi") -- GREEK SMALL LETTER PI+ , ("ρ", "rho") -- GREEK SMALL LETTER RHO+ , ("ς", "sigma") -- GREEK SMALL LETTER FINAL SIGMA+ , ("σ", "sigma") -- GREEK SMALL LETTER SIGMA+ , ("τ", "tau") -- GREEK SMALL LETTER TAU+ , ("υ", "upsilon") -- GREEK SMALL LETTER UPSILON+ , ("φ", "phi") -- GREEK SMALL LETTER PHI+ , ("χ", "chi") -- GREEK SMALL LETTER CHI+ , ("ψ", "psi") -- GREEK SMALL LETTER PSI+ , ("ω", "omega") -- GREEK SMALL LETTER OMEGA+ , ("‐", "-") -- HYPHEN+ , ("–", "-") -- EN DASH+ , ("—", ".") -- EM DAS+ , ("‘", "") -- LEFT SINGLE QUOTATION MARK+ , ("’", "") -- RIGHT SINGLE QUOTATION MARK+ , ("‚", "") -- SINGLE LOW-9 QUOTATION MAR+ , ("“", "") -- LEFT DOUBLE QUOTATION MARK+ , ("”", "") -- RIGHT DOUBLE QUOTATION MARK+ , ("„", "") -- DOUBLE LOW-9 QUOTATION MARK+ , ("†", "dagger") -- DAGGER+ , ("‡", "dagger-dagger") -- DOUBLE DAGGER+ , ("•", "") -- BULLET+ , ("…", "") -- HORIZONTAL ELLIPSIS+ , ("⊃", "") -- SUPERSET OF+ , ("⌝", "") -- TOP RIGHT CORNER+ , ("‐", "-") -- 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>ω</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)+