{-| Module : Text.Ogmarkup.Private.Typography Copyright : (c) Ogma Project, 2016 License : MIT Stability : experimental This module provides the 'Typography' datatype along with two default instances for French and English. -} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Text.Ogmarkup.Private.Typography where import Data.String import qualified Text.Ogmarkup.Private.Ast as Ast -- * Inner spaces representation -- | Deal with typographic spaces, especially when it comes to -- separating two texts. Because Space derives Ord, it is possible -- to use min and max to determine which one to use in case of -- a conflict. data Space = Normal -- ^ A normal space that can be turned into a newline for displaying. | Nbsp -- ^ A non breakable space, it cannot be turned into a newline. | None -- ^ No space at all. deriving (Eq,Ord) -- * Typography definition -- | A Typography is a data type that tells the caller what space -- should be privileged before and after a text. data Typography a = Typography { decide :: Ast.Mark -> (Space, Space) -- ^ For a given 'Ast.Mark', -- returns a tuple with the -- spaces to use before -- and after the -- punctuation mark. , output :: Ast.Mark -> a -- ^ Give an output -- representation of the -- punctuation mark , openDialogue :: Bool -> Maybe Ast.Mark -- ^ Which mark to use to -- open a dialogue. If -- the parameter is True, -- there were another -- dialogue just before. , closeDialogue :: Bool -> Maybe Ast.Mark -- ^ Which mark to use to -- close a dialogue. If -- the parameter is True, -- there is another -- dialogue just after. } -- | Apply the function to each 'Ast.Mark' output value instance Functor Typography where f `fmap` (Typography d op o c) = Typography d (f . op) o c -- | From a Typography, it gives the space to privilege before the -- input Text. beforeAtom :: Typography a -> Ast.Atom a -> Space beforeAtom t (Ast.Punctuation m) = case decide t m of (r, _) -> r beforeAtom t _ = Normal -- | From a Typography, it gives the space to privilege after the -- input Text. afterAtom :: Typography a -> Ast.Atom a -> Space afterAtom t (Ast.Punctuation m) = case decide t m of (_, r) -> r afterAtom t _ = Normal -- | Normalize the input in order to add it to a generated Text. normalizeAtom :: Typography a -> Ast.Atom a -> a normalizeAtom t (Ast.Punctuation m) = output t m normalizeAtom t (Ast.Word w) = w -- * Ready-to-use Typography -- | A proposal for the French typography. It can be used with several generation -- approaches, as it remains very generic. Requires the output type to be an -- instance of 'IsString'. frenchTypo :: (Ast.Mark -> a) -> Typography a frenchTypo op = Typography t op prevT nextT where t :: Ast.Mark -> (Space, Space) t Ast.Semicolon = (Nbsp, Normal) t Ast.Colon = (Nbsp, Normal) t Ast.OpenQuote = (Normal, Nbsp) t Ast.CloseQuote = (Nbsp, Normal) t Ast.Irony = (Nbsp, Normal) t Ast.Interrobang = (Nbsp, Normal) t Ast.Question = (Nbsp, Normal) t Ast.Exclamation = (Nbsp, Normal) t Ast.LongDash = (Normal, Normal) t Ast.Dash = (None, None) t Ast.Hyphen = (None, None) t Ast.Comma = (None, Normal) t Ast.Point = (None, Normal) t Ast.Apostrophe = (None, None) t Ast.SuspensionPoints = (None, Normal) prevT True = Just Ast.LongDash prevT False = Just Ast.OpenQuote nextT True = Nothing nextT False = Just Ast.CloseQuote unicodeFrenchTypo :: (IsString a) => Typography a unicodeFrenchTypo = frenchTypo $ \case Ast.Semicolon -> ";" Ast.Colon -> "," Ast.OpenQuote -> "«" Ast.CloseQuote -> "»" Ast.Irony -> "⸮" Ast.Interrobang -> "‽" Ast.Question -> "?" Ast.Exclamation -> "!" Ast.LongDash -> "—" Ast.Dash -> "–" Ast.Hyphen -> "-" Ast.Comma -> "," Ast.Point -> "." Ast.Apostrophe -> "’" Ast.SuspensionPoints -> "…" htmlFrenchTypo :: (IsString a) => Typography a htmlFrenchTypo = frenchTypo $ \case Ast.Semicolon -> ";" Ast.Colon -> "," Ast.OpenQuote -> "«" Ast.CloseQuote -> "»" Ast.Irony -> "⸮" Ast.Interrobang -> "‽" Ast.Question -> "?" Ast.Exclamation -> "!" Ast.LongDash -> "—" Ast.Dash -> "–" Ast.Hyphen -> "-" Ast.Comma -> "," Ast.Point -> "." Ast.Apostrophe -> "’" Ast.SuspensionPoints -> "…" -- | A proposal for the English typography. It can be used with several generation -- approaches, as it remains very generic. Requires the output type to be an -- instance of 'IsString'. englishTypo :: (Ast.Mark -> a) -> Typography a englishTypo op = Typography t op (pure $ Just Ast.OpenQuote) (pure $ Just Ast.CloseQuote) where t :: Ast.Mark -> (Space, Space) t Ast.Semicolon = (None, Normal) t Ast.Colon = (None, Normal) t Ast.OpenQuote = (Normal, None) t Ast.CloseQuote = (None, Normal) t Ast.Irony = (None, Normal) t Ast.Interrobang = (None, Normal) t Ast.Question = (None, Normal) t Ast.Exclamation = (None, Normal) t Ast.LongDash = (Normal, None) t Ast.Dash = (None, None) t Ast.Hyphen = (None, None) t Ast.Comma = (None, Normal) t Ast.Point = (None, Normal) t Ast.Apostrophe = (None, None) t Ast.SuspensionPoints = (None, Normal) unicodeEnglishTypo :: (IsString a) => Typography a unicodeEnglishTypo = englishTypo $ \case Ast.Semicolon -> ";" Ast.Colon -> "," Ast.OpenQuote -> "“" Ast.CloseQuote -> "”" Ast.Irony -> "⸮" Ast.Interrobang -> "‽" Ast.Question -> "?" Ast.Exclamation -> "!" Ast.LongDash -> "—" Ast.Dash -> "–" Ast.Hyphen -> "-" Ast.Comma -> "," Ast.Point -> "." Ast.Apostrophe -> "’" Ast.SuspensionPoints -> "…" htmlEnglishTypo :: (IsString a) => Typography a htmlEnglishTypo = englishTypo $ \case Ast.Semicolon -> ";" Ast.Colon -> "," Ast.OpenQuote -> "“" Ast.CloseQuote -> "”" Ast.Irony -> "⸮" Ast.Interrobang -> "‽" Ast.Question -> "?" Ast.Exclamation -> "!" Ast.LongDash -> "—" Ast.Dash -> "–" Ast.Hyphen -> "-" Ast.Comma -> "," Ast.Point -> "." Ast.Apostrophe -> "’" Ast.SuspensionPoints -> "…"