{-| Module : Text.Ogmarkup Copyright : (c) Ogma Project, 2016 License : MIT Stability : experimental The ogmarkup library provides an ogmarkup document compiler. This module is the only one you should need to import in your project. The library is still in an early stage of development, hence the "experimental" stability. Be aware the exposed interface may change in future realase. -} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} module Text.Ogmarkup ( -- * Parse and Generate ogmarkup, ogmarkup', -- * Generation Configuration Conf.GenConf (..), Conf.Template, -- * Typography Typo.frenchTypo, Typo.englishTypo, Typo.Typography (..), -- * Punctuation marks and space Ast.Mark (..), Typo.Space (..), ) where import Data.List hiding (uncons) import Data.Monoid import Data.Proxy (Proxy) import Data.String import Text.Megaparsec import qualified Text.Ogmarkup.Private.Ast as Ast import qualified Text.Ogmarkup.Private.Config as Conf import qualified Text.Ogmarkup.Private.Generator as Gen import qualified Text.Ogmarkup.Private.Parser as Parser import qualified Text.Ogmarkup.Private.Typography as Typo -- | From a String, parse and generate an output according to a generation configuration. -- The inner definitions of the parser and the generator imply that the output -- type has to be an instance of the 'IsString' and 'Monoid' classes. ogmarkup :: forall c a b. (Stream a, Token a ~ Char, IsString (Tokens a), IsString b, Monoid b, Conf.GenConf c b) => a -- ^ The input string -> b ogmarkup input = case Parser.parse Parser.document "" input of Right ast -> Gen.runGenerator (Gen.document @c @b $ merge ast) Left _ -> error "failed to parse an ogmarkup document even with best effort" where merge :: Ast.Document b -> Ast.Document b merge (Ast.Story x:rest) = (Ast.Story $ mergep x):rest merge (Ast.Aside cls x:rest) = Ast.Aside cls (mergep x):rest merge (x:rest) = x:merge rest merge [] = [] mergep :: [Ast.Paragraph b] -> [Ast.Paragraph b] mergep (x@(_:_):y@(Ast.Dialogue _ _:_):rest) = case last x of Ast.Dialogue _ _ -> mergep $ (x `mappend` y):rest _ -> x:mergep (y:rest) mergep (x:y:rest) = x:mergep (y:rest) mergep x = x -- | If you don’t want to use the `TypeApplications` pragma, you can use this -- functions insead (but of course, it itself uses the pragma) ogmarkup' :: forall c a b. (Stream a, Token a ~ Char, IsString (Tokens a), IsString b, Monoid b, Conf.GenConf c b) => Proxy c -> a -- ^ The input string -> b ogmarkup' _ = ogmarkup @c