{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveDataTypeable #-} module AsciiDoc.AST ( Document(..) , Meta(..) , Author(..) , Revision(..) , Block(..) , BlockType(..) , BlockTitle(..) , Inline(..) , InlineType(..) , ListType(..) , ListItem(..) , CheckboxState(..) , ColumnSpec(..) , CellStyle(..) , TableRow(..) , TableCell(..) , HorizAlign(..) , VertAlign(..) , AdmonitionType(..) , Target(..) , LinkType(..) , MathType(..) , Attr(..) , attrNull , Level(..) , Language(..) , Attribution(..) , AltText(..) , Width(..) , Height(..) , FootnoteId(..) , AttributeName(..) , Callout(..) , IndexTerm(..) , SourceLine(..) , CounterType(..) ) where import Control.Monad import Data.Text (Text) import Data.Data (Data) import Data.Typeable (Typeable) import GHC.Generics (Generic) import qualified Data.Map.Strict as Map import Data.Map.Strict (Map) import Data.Aeson (ToJSON(..), FromJSON(..), genericToEncoding, defaultOptions) -- | A complete AsciiDoc document data Document = Document { docMeta :: Meta , docBlocks :: [Block] } deriving (Show, Eq, Generic, Data, Typeable) instance Semigroup Document where d1 <> d2 = Document { docMeta = docMeta d1 <> docMeta d2 , docBlocks = docBlocks d1 <> docBlocks d2 } instance Monoid Document where mappend = (<>) mempty = Document mempty mempty instance ToJSON Document where toEncoding = genericToEncoding defaultOptions instance FromJSON Document -- | Author information data Author = Author { authorName :: Text , authorEmail :: Maybe Text } deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON Author where toEncoding = genericToEncoding defaultOptions instance FromJSON Author -- | Revision information data Revision = Revision { revVersion :: Text , revDate :: Maybe Text , revRemark :: Maybe Text } deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON Revision where toEncoding = genericToEncoding defaultOptions instance FromJSON Revision -- | Document metadata data Meta = Meta { docTitle :: [Inline] , docTitleAttributes :: Maybe Attr , docAuthors :: [Author] , docRevision :: Maybe Revision , docAttributes :: Map Text Text } deriving (Eq, Generic, Data, Typeable) instance Show Meta where show x | x == mempty = "Meta mempty" show (Meta title titleAttr authors revision attributes) = "Meta{ docTitle = " <> show title <> ", docTitleAttributes = " <> show titleAttr <> ", docAuthors = " <> show authors <> ", docRevision = " <> show revision <> ", docAttributes = " <> show attributes <> "}" instance ToJSON Meta where toEncoding = genericToEncoding defaultOptions instance FromJSON Meta instance Semigroup Meta where -- left-biased m1 <> m2 = Meta { docTitle = case docTitle m1 of [] -> docTitle m2 ils -> ils , docTitleAttributes = case docTitle m1 of [] -> docTitleAttributes m2 _ -> docTitleAttributes m2 , docAuthors = docAuthors m1 <> docAuthors m2 , docRevision = docRevision m1 `mplus` docRevision m2 , docAttributes = docAttributes m1 <> docAttributes m2 } instance Monoid Meta where mappend = (<>) mempty = Meta [] Nothing [] Nothing mempty -- | Attributes attached to an element. -- The first parameter stores positional attributes in order. -- The second parameter stores named attributes (including special keys -- like id/role/options) in a map. data Attr = Attr [Text] (Map Text Text) deriving (Eq, Generic, Data, Typeable) instance Show Attr where show (Attr pos m) | null pos && Map.null m = "mempty" | otherwise = "Attr " ++ show (pos, m) instance Semigroup Attr where Attr p1 m1 <> Attr p2 m2 = let m = m2 <> m1 -- left-biased, favor m2 m' = (case (Map.lookup "role" m1, Map.lookup "role" m2) of (Just x1, Just x2) -> Map.insert "role" (x1 <> " " <> x2) _ -> id) . (case (Map.lookup "options" m1, Map.lookup "options" m2) of (Just x1, Just x2) -> Map.insert "options" (x1 <> "," <> x2) _ -> id) $ m in Attr (p1 <> p2) m' instance Monoid Attr where mempty = Attr [] Map.empty mappend = (<>) instance ToJSON Attr where toEncoding = genericToEncoding defaultOptions instance FromJSON Attr attrNull :: Attr -> Bool attrNull (Attr pos m) = null pos && Map.null m -- | Nesting or section level newtype Level = Level Int deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON Level where toEncoding = genericToEncoding defaultOptions instance FromJSON Level -- | Programming or markup language identifier newtype Language = Language Text deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON Language where toEncoding = genericToEncoding defaultOptions instance FromJSON Language -- | Attribution for quotes newtype Attribution = Attribution Text deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON Attribution where toEncoding = genericToEncoding defaultOptions instance FromJSON Attribution -- | Alternative text for images newtype AltText = AltText Text deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON AltText where toEncoding = genericToEncoding defaultOptions instance FromJSON AltText -- | Width specification in pixels newtype Width = Width Int deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON Width where toEncoding = genericToEncoding defaultOptions instance FromJSON Width -- | Height specification in pixels newtype Height = Height Int deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON Height where toEncoding = genericToEncoding defaultOptions instance FromJSON Height -- | Footnote identifier newtype FootnoteId = FootnoteId Text deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON FootnoteId where toEncoding = genericToEncoding defaultOptions instance FromJSON FootnoteId -- | Attribute name newtype AttributeName = AttributeName Text deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON AttributeName where toEncoding = genericToEncoding defaultOptions instance FromJSON AttributeName -- | Source line callout newtype Callout = Callout Int deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON Callout where toEncoding = genericToEncoding defaultOptions instance FromJSON Callout -- | Source line with possible annotation data SourceLine = SourceLine Text [Callout] deriving (Show, Eq, Ord, Generic, Data, Typeable) instance ToJSON SourceLine where toEncoding = genericToEncoding defaultOptions instance FromJSON SourceLine -- | Block-level element with attributes data Block = Block Attr (Maybe BlockTitle) BlockType deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON Block where toEncoding = genericToEncoding defaultOptions instance FromJSON Block -- | Block-level element types data BlockType = Section Level [Inline] [Block] | DiscreteHeading Level [Inline] | Paragraph [Inline] | Verse (Maybe Attribution) [Block] | LiteralBlock Text | Listing (Maybe Language) [SourceLine] | IncludeListing (Maybe Language) FilePath (Maybe [SourceLine]) | ExampleBlock [Block] | QuoteBlock (Maybe Attribution) [Block] | Sidebar [Block] | OpenBlock [Block] | PassthroughBlock Text | MathBlock (Maybe MathType) Text | List ListType [ListItem] | DefinitionList [([Inline], [Block])] | Table [ColumnSpec] (Maybe [TableRow]) [TableRow] (Maybe [TableRow]) | BlockImage Target (Maybe AltText) (Maybe Width) (Maybe Height) | BlockAudio Target | BlockVideo Target | TOC | Admonition AdmonitionType [Block] | PageBreak | ThematicBreak | Include FilePath (Maybe [Block]) deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON BlockType where toEncoding = genericToEncoding defaultOptions instance FromJSON BlockType newtype BlockTitle = BlockTitle [Inline] deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON BlockTitle where toEncoding = genericToEncoding defaultOptions instance FromJSON BlockTitle -- | Types of admonitions data AdmonitionType = Note | Tip | Important | Caution | Warning deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON AdmonitionType where toEncoding = genericToEncoding defaultOptions instance FromJSON AdmonitionType data IndexTerm = TermInText Text | TermConcealed [Text] deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON IndexTerm where toEncoding = genericToEncoding defaultOptions instance FromJSON IndexTerm -- | List types data ListType = BulletList Level | OrderedList Level (Maybe Int) | CheckList | CalloutList deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON ListType where toEncoding = genericToEncoding defaultOptions instance FromJSON ListType -- | A list item data ListItem = ListItem (Maybe CheckboxState) [Block] deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON ListItem where toEncoding = genericToEncoding defaultOptions instance FromJSON ListItem -- | Checkbox state for checklists data CheckboxState = Checked | Unchecked deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON CheckboxState where toEncoding = genericToEncoding defaultOptions instance FromJSON CheckboxState -- | Column specification data ColumnSpec = ColumnSpec { colHorizAlign :: Maybe HorizAlign , colVertAlign :: Maybe VertAlign , colWidth :: Maybe Int , colStyle :: Maybe CellStyle } deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON ColumnSpec where toEncoding = genericToEncoding defaultOptions instance FromJSON ColumnSpec -- | Defines how cell contents are parsed data CellStyle = AsciiDocStyle | DefaultStyle | EmphasisStyle | LiteralStyle | HeaderStyle | MonospaceStyle | StrongStyle deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON CellStyle where toEncoding = genericToEncoding defaultOptions instance FromJSON CellStyle -- | Table row newtype TableRow = TableRow [TableCell] deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON TableRow where toEncoding = genericToEncoding defaultOptions instance FromJSON TableRow -- | Table cell data TableCell = TableCell { cellContent :: [Block] , cellHorizAlign :: Maybe HorizAlign , cellVertAlign :: Maybe VertAlign , cellColspan :: Int , cellRowspan :: Int } deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON TableCell where toEncoding = genericToEncoding defaultOptions instance FromJSON TableCell -- | Cell alignment data HorizAlign = AlignLeft | AlignCenter | AlignRight deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON HorizAlign where toEncoding = genericToEncoding defaultOptions instance FromJSON HorizAlign data VertAlign = AlignTop | AlignMiddle | AlignBottom deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON VertAlign where toEncoding = genericToEncoding defaultOptions instance FromJSON VertAlign -- | Inline element with attributes data Inline = Inline Attr InlineType deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON Inline where toEncoding = genericToEncoding defaultOptions instance FromJSON Inline -- | Inline element types data InlineType = Str Text | HardBreak | Bold [Inline] | Italic [Inline] | Monospace [Inline] | Superscript [Inline] | Subscript [Inline] | Highlight [Inline] | Strikethrough [Inline] | DoubleQuoted [Inline] | SingleQuoted [Inline] | Math (Maybe MathType) Text | Icon Text | Button Text | Kbd [Text] | Menu [Text] | Link LinkType Target [Inline] | InlineImage Target (Maybe AltText) (Maybe Width) (Maybe Height) | Footnote (Maybe FootnoteId) [Inline] | InlineAnchor Text [Inline] | BibliographyAnchor Text [Inline] | CrossReference Text (Maybe [Inline]) | AttributeReference AttributeName | Span [Inline] | IndexEntry IndexTerm | Counter Text CounterType Int | Passthrough Text deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON InlineType where toEncoding = genericToEncoding defaultOptions instance FromJSON InlineType data MathType = AsciiMath | LaTeXMath deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON MathType where toEncoding = genericToEncoding defaultOptions instance FromJSON MathType -- | Link types data LinkType = URLLink | EmailLink deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON LinkType where toEncoding = genericToEncoding defaultOptions instance FromJSON LinkType -- | Link or image target newtype Target = Target Text deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON Target where toEncoding = genericToEncoding defaultOptions instance FromJSON Target data CounterType = DecimalCounter | UpperAlphaCounter | LowerAlphaCounter deriving (Show, Eq, Generic, Data, Typeable) instance ToJSON CounterType where toEncoding = genericToEncoding defaultOptions instance FromJSON CounterType