git.iko.soy/typeable/pandoc
on master help sign in
Moved BCP47 specific functions from Writers.Shared to new module.

Text.Pandoc.BCP47 (unexported, internal module). `getLang`, `Lang(..)`, `parseBCP47`.

commitac9423eccc76005f996a10a545594247ac753e02 authorJohn MacFarlane <jgm@berkeley.edu> dateSun 25 Jun 2017, 21:00 (9 years ago) parent643cbdf
6 files changed+126−87
pandoc.cabal+1 src/Text/Pandoc/BCP47.hs+117 src/Text/Pandoc/Writers/Docx.hs+2−1 src/Text/Pandoc/Writers/ODT.hs+2−2 src/Text/Pandoc/Writers/OpenDocument.hs+1 src/Text/Pandoc/Writers/Shared.hs+3−84
pandoc.cabal+1
@@ -463,6 +463,7 @@ Library
463463 Text.Pandoc.Lua.Util,
464464 Text.Pandoc.CSS,
465465 Text.Pandoc.UUID,
466+ Text.Pandoc.BCP47
466467 Text.Pandoc.Slides,
467468 Text.Pandoc.Compat.Time,
468469 Paths_pandoc
src/Text/Pandoc/BCP47.hsnew file+117
@@ -0,0 +1,117 @@
1+{-
2+Copyright (C) 2017 John MacFarlane <jgm@berkeley.edu>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
18+
19+{- |
20+ Module : Text.Pandoc.BCP47
21+ Copyright : Copyright (C) 2017 John MacFarlane
22+ License : GNU GPL, version 2 or above
23+
24+ Maintainer : John MacFarlane <jgm@berkeley.edu>
25+ Stability : alpha
26+ Portability : portable
27+
28+Functions for parsing and rendering BCP47 language identifiers.
29+-}
30+module Text.Pandoc.BCP47 (
31+ getLang
32+ , parseBCP47
33+ , Lang(..)
34+ , renderLang
35+ )
36+where
37+import Control.Monad (guard)
38+import Data.Char (isAscii, isLetter, isUpper, isLower)
39+import Data.List (intercalate)
40+import Text.Pandoc.Definition
41+import Text.Pandoc.Class (PandocMonad, report)
42+import Text.Pandoc.Logging
43+import Text.Pandoc.Options
44+import qualified Text.Parsec as P
45+
46+-- | Represents BCP 47 language/country code.
47+data Lang = Lang{ langLanguage :: String
48+ , langScript :: String
49+ , langRegion :: String
50+ , langVariants :: [String] }
51+ deriving (Eq, Ord, Show)
52+
53+-- | Render a Lang as BCP 47.
54+renderLang :: Lang -> String
55+renderLang lang = intercalate "-" (langLanguage lang : filter (not . null)
56+ ([langScript lang, langRegion lang] ++ langVariants lang))
57+
58+-- | Get the contents of the `lang` metadata field or variable.
59+getLang :: PandocMonad m => WriterOptions -> Meta -> m (Maybe Lang)
60+getLang opts meta = case
61+ (case lookup "lang" (writerVariables opts) of
62+ Just s -> Just s
63+ _ ->
64+ case lookupMeta "lang" meta of
65+ Just (MetaInlines [Str s]) -> Just s
66+ Just (MetaString s) -> Just s
67+ _ -> Nothing) of
68+ Nothing -> return Nothing
69+ Just s -> case parseBCP47 s of
70+ Left _ -> do
71+ report $ InvalidLang s
72+ return Nothing
73+ Right l -> return (Just l)
74+
75+-- | Parse a BCP 47 string as a Lang.
76+parseBCP47 :: String -> Either String Lang
77+parseBCP47 lang =
78+ case P.parse bcp47 "lang" lang of
79+ Right r -> Right r
80+ Left e -> Left $ show e
81+ where bcp47 = do
82+ language <- pLanguage
83+ script <- P.option "" pScript
84+ region <- P.option "" pRegion
85+ variants <- P.many pVariant
86+ () <$ P.char '-' P.<|> P.eof
87+ return $ Lang{ langLanguage = language
88+ , langScript = script
89+ , langRegion = region
90+ , langVariants = variants }
91+ asciiLetter = P.satisfy (\c -> isAscii c && isLetter c)
92+ pLanguage = do
93+ cs <- P.many1 asciiLetter
94+ let lcs = length cs
95+ guard $ lcs == 2 || lcs == 3
96+ return cs
97+ pScript = P.try $ do
98+ P.char '-'
99+ x <- P.satisfy (\c -> isAscii c && isLetter c && isUpper c)
100+ xs <- P.count 3
101+ (P.satisfy (\c -> isAscii c && isLetter c && isLower c))
102+ return (x:xs)
103+ pRegion = P.try $ do
104+ P.char '-'
105+ cs <- P.many1 asciiLetter
106+ let lcs = length cs
107+ guard $ lcs == 2 || lcs == 3
108+ return cs
109+ pVariant = P.try $ do
110+ P.char '-'
111+ ds <- P.option "" (P.count 1 P.digit)
112+ cs <- P.many1 asciiLetter
113+ let var = ds ++ cs
114+ guard $ if null ds
115+ then length var >= 5 && length var <= 8
116+ else length var == 4
117+ return var
src/Text/Pandoc/Writers/Docx.hs+2−1
@@ -67,7 +67,8 @@ import Text.Pandoc.Shared hiding (Element)
6767import qualified Text.Pandoc.UTF8 as UTF8
6868import Text.Pandoc.Walk
6969import Text.Pandoc.Writers.Math
70−import Text.Pandoc.Writers.Shared (fixDisplayMath, getLang, renderLang)
70+import Text.Pandoc.Writers.Shared (fixDisplayMath)
71+import Text.Pandoc.BCP47 (getLang, renderLang)
7172import Text.Printf (printf)
7273import Text.TeXMath
7374import Text.XML.Light as XML
src/Text/Pandoc/Writers/ODT.hs+2−2
@@ -50,8 +50,8 @@ import Text.Pandoc.Shared (stringify)
5050import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toStringLazy)
5151import Text.Pandoc.Walk
5252import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
53−import Text.Pandoc.Writers.Shared (fixDisplayMath, getLang, Lang(..),
54− renderLang)
53+import Text.Pandoc.Writers.Shared (fixDisplayMath)
54+import Text.Pandoc.BCP47 (getLang, Lang(..), renderLang)
5555import Text.Pandoc.XML
5656import Text.TeXMath
5757import Text.XML.Light
src/Text/Pandoc/Writers/OpenDocument.hs+1
@@ -50,6 +50,7 @@ import Text.Pandoc.Templates (renderTemplate')
5050import Text.Pandoc.Writers.Math
5151import Text.Pandoc.Writers.Shared
5252import Text.Pandoc.XML
53+import Text.Pandoc.BCP47 (parseBCP47, Lang(..))
5354import Text.Printf (printf)
5455
5556-- | Auxiliary function to convert Plain block to Para.
src/Text/Pandoc/Writers/Shared.hs+3−84
@@ -29,11 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2929Shared utility functions for pandoc writers.
3030-}
3131module Text.Pandoc.Writers.Shared (
32− getLang
33− , parseBCP47
34− , Lang(..)
35− , renderLang
36− , metaToJSON
32+ metaToJSON
3733 , metaToJSON'
3834 , addVariablesToJSON
3935 , getField
@@ -46,97 +42,20 @@ module Text.Pandoc.Writers.Shared (
4642 , gridTable
4743 )
4844where
49−import Control.Monad (liftM, zipWithM, guard)
45+import Control.Monad (liftM, zipWithM)
5046import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object),
5147 encode, fromJSON)
52−import Data.Char (isAscii, isLetter, isUpper, isLower)
5348import qualified Data.HashMap.Strict as H
54−import Data.List (groupBy, intersperse, transpose, intercalate)
49+import Data.List (groupBy, intersperse, transpose)
5550import qualified Data.Map as M
5651import Data.Maybe (isJust)
5752import qualified Data.Text as T
5853import qualified Data.Traversable as Traversable
5954import Text.Pandoc.Definition
60−import Text.Pandoc.Class (PandocMonad, report)
61−import Text.Pandoc.Logging
6255import Text.Pandoc.Options
6356import Text.Pandoc.Pretty
6457import Text.Pandoc.UTF8 (toStringLazy)
6558import Text.Pandoc.XML (escapeStringForXML)
66−import qualified Text.Parsec as P
67−
68−-- | Represents BCP 47 language/country code.
69−data Lang = Lang{ langLanguage :: String
70− , langScript :: String
71− , langRegion :: String
72− , langVariants :: [String] }
73− deriving (Eq, Ord, Show)
74−
75−-- | Render a Lang as BCP 47.
76−renderLang :: Lang -> String
77−renderLang lang = intercalate "-" (langLanguage lang : filter (not . null)
78− ([langScript lang, langRegion lang] ++ langVariants lang))
79−
80−-- | Get the contents of the `lang` metadata field or variable.
81−getLang :: PandocMonad m => WriterOptions -> Meta -> m (Maybe Lang)
82−getLang opts meta = case
83− (case lookup "lang" (writerVariables opts) of
84− Just s -> Just s
85− _ ->
86− case lookupMeta "lang" meta of
87− Just (MetaInlines [Str s]) -> Just s
88− Just (MetaString s) -> Just s
89− _ -> Nothing) of
90− Nothing -> return Nothing
91− Just s -> case parseBCP47 s of
92− Left _ -> do
93− report $ InvalidLang s
94− return Nothing
95− Right l -> return (Just l)
96−
97−-- | Parse a BCP 47 string as a Lang.
98−parseBCP47 :: String -> Either String Lang
99−parseBCP47 lang =
100− case P.parse bcp47 "lang" lang of
101− Right r -> Right r
102− Left e -> Left $ show e
103− where bcp47 = do
104− language <- pLanguage
105− script <- P.option "" pScript
106− region <- P.option "" pRegion
107− variants <- P.many pVariant
108− () <$ P.char '-' P.<|> P.eof
109− return $ Lang{ langLanguage = language
110− , langScript = script
111− , langRegion = region
112− , langVariants = variants }
113− asciiLetter = P.satisfy (\c -> isAscii c && isLetter c)
114− pLanguage = do
115− cs <- P.many1 asciiLetter
116− let lcs = length cs
117− guard $ lcs == 2 || lcs == 3
118− return cs
119− pScript = P.try $ do
120− P.char '-'
121− x <- P.satisfy (\c -> isAscii c && isLetter c && isUpper c)
122− xs <- P.count 3
123− (P.satisfy (\c -> isAscii c && isLetter c && isLower c))
124− return (x:xs)
125− pRegion = P.try $ do
126− P.char '-'
127− cs <- P.many1 asciiLetter
128− let lcs = length cs
129− guard $ lcs == 2 || lcs == 3
130− return cs
131− pVariant = P.try $ do
132− P.char '-'
133− ds <- P.option "" (P.count 1 P.digit)
134− cs <- P.many1 asciiLetter
135− let var = ds ++ cs
136− guard $ if null ds
137− then length var >= 5 && length var <= 8
138− else length var == 4
139− return var
14059
14160-- | Create JSON value for template from a 'Meta' and an association list
14261-- of variables, specified at the command line or in the writer.