{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP                        #-}
{-# LANGUAGE DeriveDataTypeable         #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TemplateHaskell            #-}
module Text.Pandoc.Extensions ( Extension(..)
                              , Extensions
                              , emptyExtensions
                              , extensionsFromList
                              , parseFormatSpec
                              , extensionEnabled
                              , enableExtension
                              , disableExtension
                              , getDefaultExtensions
                              , pandocExtensions
                              , plainExtensions
                              , strictExtensions
                              , phpMarkdownExtraExtensions
                              , githubMarkdownExtensions
                              , multimarkdownExtensions )
where
import Prelude
import Data.Aeson (FromJSON (..), ToJSON (..), defaultOptions)
import Data.Aeson.TH (deriveJSON)
import Data.Bits (clearBit, setBit, testBit, (.|.))
import Data.Data (Data)
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
import Text.Pandoc.Shared (safeRead)
import Text.Parsec
newtype Extensions = Extensions Integer
  deriving (Show, Read, Eq, Ord, Data, Typeable, Generic, ToJSON, FromJSON)
instance Semigroup Extensions where
  (Extensions a) <> (Extensions b) = Extensions (a .|. b)
instance Monoid Extensions where
  mempty = Extensions 0
  mappend = (<>)
extensionsFromList :: [Extension] -> Extensions
extensionsFromList = foldr enableExtension emptyExtensions
emptyExtensions :: Extensions
emptyExtensions = Extensions 0
extensionEnabled :: Extension -> Extensions -> Bool
extensionEnabled x (Extensions exts) = testBit exts (fromEnum x)
enableExtension :: Extension -> Extensions -> Extensions
enableExtension x (Extensions exts) = Extensions (setBit exts (fromEnum x))
disableExtension :: Extension -> Extensions -> Extensions
disableExtension x (Extensions exts) = Extensions (clearBit exts (fromEnum x))
data Extension =
      Ext_abbreviations       
    | Ext_all_symbols_escapable  
    | Ext_amuse 
    | Ext_angle_brackets_escapable  
    | Ext_ascii_identifiers   
    | Ext_auto_identifiers    
    | Ext_autolink_bare_uris  
    | Ext_backtick_code_blocks    
    | Ext_blank_before_blockquote 
    | Ext_blank_before_header     
    | Ext_bracketed_spans         
    | Ext_citations           
    | Ext_compact_definition_lists  
                                    
    | Ext_definition_lists    
    | Ext_east_asian_line_breaks  
                                  
                                  
                                  
                                  
    | Ext_emoji               
    | Ext_empty_paragraphs 
    | Ext_epub_html_exts      
    | Ext_escaped_line_breaks     
    | Ext_example_lists       
    | Ext_fancy_lists         
    | Ext_fenced_code_attributes  
    | Ext_fenced_code_blocks  
    | Ext_fenced_divs             
    | Ext_footnotes           
    | Ext_four_space_rule     
    | Ext_gfm_auto_identifiers  
                                
    | Ext_grid_tables         
    | Ext_hard_line_breaks    
    | Ext_header_attributes   
    | Ext_ignore_line_breaks  
    | Ext_implicit_figures    
    | Ext_implicit_header_references 
    | Ext_inline_code_attributes  
    | Ext_inline_notes        
    | Ext_intraword_underscores  
    | Ext_latex_macros        
    | Ext_line_blocks         
    | Ext_link_attributes         
    | Ext_lists_without_preceding_blankline 
    | Ext_literate_haskell    
    | Ext_markdown_attribute      
                                  
    | Ext_markdown_in_html_blocks 
    | Ext_mmd_header_identifiers 
    | Ext_mmd_link_attributes     
    | Ext_mmd_title_block     
    | Ext_multiline_tables    
    | Ext_native_divs             
    | Ext_native_spans            
    | Ext_ntb                 
    | Ext_old_dashes          
    | Ext_pandoc_title_block  
    | Ext_pipe_tables         
    | Ext_raw_attribute           
    | Ext_raw_html            
    | Ext_raw_tex             
    | Ext_shortcut_reference_links 
    | Ext_simple_tables       
    | Ext_smart               
    | Ext_space_in_atx_header 
    | Ext_spaced_reference_links 
    | Ext_startnum            
    | Ext_strikeout           
    | Ext_subscript           
    | Ext_superscript         
    | Ext_styles              
    | Ext_table_captions      
    | Ext_tex_math_dollars    
    | Ext_tex_math_double_backslash  
    | Ext_tex_math_single_backslash  
    | Ext_yaml_metadata_block 
    deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
pandocExtensions :: Extensions
pandocExtensions = extensionsFromList
  [ Ext_footnotes
  , Ext_inline_notes
  , Ext_pandoc_title_block
  , Ext_yaml_metadata_block
  , Ext_table_captions
  , Ext_implicit_figures
  , Ext_simple_tables
  , Ext_multiline_tables
  , Ext_grid_tables
  , Ext_pipe_tables
  , Ext_citations
  , Ext_raw_tex
  , Ext_raw_html
  , Ext_tex_math_dollars
  , Ext_latex_macros
  , Ext_fenced_code_blocks
  , Ext_fenced_code_attributes
  , Ext_backtick_code_blocks
  , Ext_inline_code_attributes
  , Ext_raw_attribute
  , Ext_markdown_in_html_blocks
  , Ext_native_divs
  , Ext_fenced_divs
  , Ext_native_spans
  , Ext_bracketed_spans
  , Ext_escaped_line_breaks
  , Ext_fancy_lists
  , Ext_startnum
  , Ext_definition_lists
  , Ext_example_lists
  , Ext_all_symbols_escapable
  , Ext_intraword_underscores
  , Ext_blank_before_blockquote
  , Ext_blank_before_header
  , Ext_space_in_atx_header
  , Ext_strikeout
  , Ext_superscript
  , Ext_subscript
  , Ext_auto_identifiers
  , Ext_header_attributes
  , Ext_link_attributes
  , Ext_implicit_header_references
  , Ext_line_blocks
  , Ext_shortcut_reference_links
  , Ext_smart
  ]
plainExtensions :: Extensions
plainExtensions = extensionsFromList
  [ Ext_table_captions
  , Ext_implicit_figures
  , Ext_simple_tables
  , Ext_multiline_tables
  , Ext_grid_tables
  , Ext_latex_macros
  , Ext_fancy_lists
  , Ext_startnum
  , Ext_definition_lists
  , Ext_example_lists
  , Ext_intraword_underscores
  , Ext_blank_before_blockquote
  , Ext_blank_before_header
  , Ext_strikeout
  ]
phpMarkdownExtraExtensions :: Extensions
phpMarkdownExtraExtensions = extensionsFromList
  [ Ext_footnotes
  , Ext_pipe_tables
  , Ext_raw_html
  , Ext_markdown_attribute
  , Ext_fenced_code_blocks
  , Ext_definition_lists
  , Ext_intraword_underscores
  , Ext_header_attributes
  , Ext_link_attributes
  , Ext_abbreviations
  , Ext_shortcut_reference_links
  , Ext_spaced_reference_links
  ]
githubMarkdownExtensions :: Extensions
githubMarkdownExtensions = extensionsFromList
  [ Ext_angle_brackets_escapable
  , Ext_pipe_tables
  , Ext_raw_html
  , Ext_fenced_code_blocks
  , Ext_gfm_auto_identifiers
  , Ext_ascii_identifiers
  , Ext_backtick_code_blocks
  , Ext_autolink_bare_uris
  , Ext_space_in_atx_header
  , Ext_intraword_underscores
  , Ext_strikeout
  , Ext_emoji
  , Ext_lists_without_preceding_blankline
  , Ext_shortcut_reference_links
  ]
multimarkdownExtensions :: Extensions
multimarkdownExtensions = extensionsFromList
  [ Ext_pipe_tables
  , Ext_raw_html
  , Ext_markdown_attribute
  , Ext_mmd_link_attributes
  
  
  
  , Ext_tex_math_double_backslash
  , Ext_intraword_underscores
  , Ext_mmd_title_block
  , Ext_footnotes
  , Ext_definition_lists
  , Ext_all_symbols_escapable
  , Ext_implicit_header_references
  , Ext_shortcut_reference_links
  , Ext_auto_identifiers
  , Ext_mmd_header_identifiers
  , Ext_implicit_figures
  
  
  
  
  
  
  , Ext_superscript
  , Ext_subscript
  , Ext_backtick_code_blocks
  , Ext_spaced_reference_links
  
  , Ext_raw_attribute
  ]
strictExtensions :: Extensions
strictExtensions = extensionsFromList
  [ Ext_raw_html
  , Ext_shortcut_reference_links
  , Ext_spaced_reference_links
  ]
getDefaultExtensions :: String -> Extensions
getDefaultExtensions "markdown_strict" = strictExtensions
getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
getDefaultExtensions "markdown_github" = githubMarkdownExtensions
getDefaultExtensions "markdown"        = pandocExtensions
getDefaultExtensions "muse"            = extensionsFromList
                                           [Ext_amuse,
                                            Ext_auto_identifiers]
getDefaultExtensions "plain"           = plainExtensions
getDefaultExtensions "gfm"             = githubMarkdownExtensions
getDefaultExtensions "commonmark"      = extensionsFromList
                                          [Ext_raw_html]
getDefaultExtensions "org"             = extensionsFromList
                                          [Ext_citations,
                                           Ext_auto_identifiers]
getDefaultExtensions "html"            = extensionsFromList
                                          [Ext_auto_identifiers,
                                           Ext_native_divs,
                                           Ext_line_blocks,
                                           Ext_native_spans]
getDefaultExtensions "html4"           = getDefaultExtensions "html"
getDefaultExtensions "html5"           = getDefaultExtensions "html"
getDefaultExtensions "epub"            = extensionsFromList
                                          [Ext_raw_html,
                                           Ext_native_divs,
                                           Ext_native_spans,
                                           Ext_epub_html_exts]
getDefaultExtensions "epub2"           = getDefaultExtensions "epub"
getDefaultExtensions "epub3"           = getDefaultExtensions "epub"
getDefaultExtensions "latex"           = extensionsFromList
                                          [Ext_smart,
                                           Ext_latex_macros,
                                           Ext_auto_identifiers]
getDefaultExtensions "beamer"          = extensionsFromList
                                          [Ext_smart,
                                           Ext_latex_macros,
                                           Ext_auto_identifiers]
getDefaultExtensions "context"         = extensionsFromList
                                          [Ext_smart,
                                           Ext_auto_identifiers]
getDefaultExtensions "textile"         = extensionsFromList
                                          [Ext_old_dashes,
                                           Ext_smart,
                                           Ext_raw_html,
                                           Ext_auto_identifiers]
getDefaultExtensions "opml"            = pandocExtensions 
getDefaultExtensions _                 = extensionsFromList
                                          [Ext_auto_identifiers]
parseFormatSpec :: String
                -> Either ParseError (String, Extensions -> Extensions)
parseFormatSpec = parse formatSpec ""
  where formatSpec = do
          name <- formatName
          extMods <- many extMod
          return (name, \x -> foldl (flip ($)) x extMods)
        formatName = many1 $ noneOf "-+"
        extMod = do
          polarity <- oneOf "-+"
          name <- many $ noneOf "-+"
          ext <- case safeRead ("Ext_" ++ name) of
                       Just n  -> return n
                       Nothing
                         | name == "lhs" -> return Ext_literate_haskell
                         | otherwise -> fail $ "Unknown extension: " ++ name
          return $ case polarity of
                        '-' -> disableExtension ext
                        _   -> enableExtension ext
$(deriveJSON defaultOptions ''Extension)