    {-# LANGUAGE OverloadedStrings #-}
    {- |
       Module      : Text.Pandoc.Highlighting
       Copyright   : Copyright (C) 2008-2020 John MacFarlane
       License     : GNU GPL, version 2 or above

       Maintainer  : John MacFarlane <jgm@berkeley.edu>
       Stability   : alpha
       Portability : portable

    Exports functions for syntax highlighting.
    -}

    module Text.Pandoc.Highlighting ( highlightingStyles
                                    , languages
                                    , languagesByExtension
                                    , highlight
                                    , formatLaTeXInline
                                    , formatLaTeXBlock
                                    , styleToLaTeX
                                    , formatHtmlInline
                                    , formatHtmlBlock
                                    , styleToCss
                                    , pygments
                                    , espresso
                                    , zenburn
                                    , tango
                                    , kate
                                    , monochrome
                                    , breezeDark
                                    , haddock
                                    , Style
                                    , fromListingsLanguage
                                    , toListingsLanguage
                                    ) where
    import Control.Monad
    import qualified Data.Map as M
    import Data.Maybe (fromMaybe)
    import qualified Data.Text as T
    import Skylighting
    import Text.Pandoc.Definition
    import Text.Pandoc.Shared (safeRead)

    highlightingStyles :: [(T.Text, Style)]
    highlightingStyles :: [(Text, Style)]
    highlightingStyles =
      [("pygments", Style
    pygments),
       ("tango", Style
    tango),
       ("espresso", Style
    espresso),
       ("zenburn", Style
    zenburn),
       ("kate", Style
    kate),
       ("monochrome", Style
    monochrome),
       ("breezedark", Style
    breezeDark),
       ("haddock", Style
    haddock)]

    languages :: [T.Text]
    languages :: [Text]
    languages = [Text -> Text
    T.toLower (Syntax -> Text
    sName Syntax
    s) | Syntax
    s <- Map Text Syntax -> [Syntax]
    forall k a. Map k a -> [a]
    M.elems Map Text Syntax
    defaultSyntaxMap]

    languagesByExtension :: T.Text -> [T.Text]
    languagesByExtension :: Text -> [Text]
    languagesByExtension ext :: Text
    ext =
      [Text -> Text
    T.toLower (Syntax -> Text
    sName Syntax
    s) | Syntax
    s <- Map Text Syntax -> String -> [Syntax]
    syntaxesByExtension Map Text Syntax
    defaultSyntaxMap (Text -> String
    T.unpack Text
    ext)]

    highlight :: SyntaxMap
              -> (FormatOptions -> [SourceLine] -> a) -- ^ Formatter
              -> Attr   -- ^ Attributes of the CodeBlock
              -> T.Text -- ^ Raw contents of the CodeBlock
              -> Either T.Text a
    highlight :: Map Text Syntax
    -> (FormatOptions -> [SourceLine] -> a)
    -> Attr
    -> Text
    -> Either Text a
    highlight syntaxmap :: Map Text Syntax
    syntaxmap formatter :: FormatOptions -> [SourceLine] -> a
    formatter (ident :: Text
    ident, classes :: [Text]
    classes, keyvals :: [(Text, Text)]
    keyvals) rawCode :: Text
    rawCode =
      let firstNum :: Int
    firstNum = Int -> Maybe Int -> Int
    forall a. a -> Maybe a -> a
    fromMaybe 1 (Text -> Maybe Int
    forall (m :: * -> *) a. (MonadPlus m, Read a) => Text -> m a
    safeRead (Text -> Maybe Text -> Text
    forall a. a -> Maybe a -> a
    fromMaybe "1" (Maybe Text -> Text) -> Maybe Text -> Text
    forall a b. (a -> b) -> a -> b
    $ Text -> [(Text, Text)] -> Maybe Text
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup "startFrom" [(Text, Text)]
    keyvals))
          fmtOpts :: FormatOptions
    fmtOpts = FormatOptions
    defaultFormatOpts{
                      startNumber :: Int
    startNumber = Int
    firstNum,
                      lineAnchors :: Bool
    lineAnchors = (Text -> Bool) -> [Text] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem`
                            ["line-anchors", "lineAnchors"]) [Text]
    classes,
                      numberLines :: Bool
    numberLines = (Text -> Bool) -> [Text] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem`
                            ["number","numberLines", "number-lines"]) [Text]
    classes,
                      lineIdPrefix :: Text
    lineIdPrefix = if Text -> Bool
    T.null Text
    ident
                                        then Text
    forall a. Monoid a => a
    mempty
                                        else Text
    ident Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> "-" }
          tokenizeOpts :: TokenizerConfig
    tokenizeOpts = TokenizerConfig :: Map Text Syntax -> Bool -> TokenizerConfig
    TokenizerConfig{ syntaxMap :: Map Text Syntax
    syntaxMap = Map Text Syntax
    syntaxmap
                                        , traceOutput :: Bool
    traceOutput = Bool
    False }
      in  case [Maybe Syntax] -> Maybe Syntax
    forall (t :: * -> *) (m :: * -> *) a.
    (Foldable t, MonadPlus m) =>
    t (m a) -> m a
    msum ((Text -> Maybe Syntax) -> [Text] -> [Maybe Syntax]
    forall a b. (a -> b) -> [a] -> [b]
    map (Text -> Map Text Syntax -> Maybe Syntax
    `lookupSyntax` Map Text Syntax
    syntaxmap) [Text]
    classes) of
                Nothing
                  | FormatOptions -> Bool
    numberLines FormatOptions
    fmtOpts -> a -> Either Text a
    forall a b. b -> Either a b
    Right
                                  (a -> Either Text a) -> a -> Either Text a
    forall a b. (a -> b) -> a -> b
    $ FormatOptions -> [SourceLine] -> a
    formatter FormatOptions
    fmtOpts{ codeClasses :: [Text]
    codeClasses = [],
                                                       containerClasses :: [Text]
    containerClasses = [Text]
    classes }
                                  ([SourceLine] -> a) -> [SourceLine] -> a
    forall a b. (a -> b) -> a -> b
    $ (Text -> SourceLine) -> [Text] -> [SourceLine]
    forall a b. (a -> b) -> [a] -> [b]
    map (\ln :: Text
    ln -> [(TokenType
    NormalTok, Text
    ln)])
                                  ([Text] -> [SourceLine]) -> [Text] -> [SourceLine]
    forall a b. (a -> b) -> a -> b
    $ Text -> [Text]
    T.lines Text
    rawCode
                  | Bool
    otherwise  -> Text -> Either Text a
    forall a b. a -> Either a b
    Left ""
                Just syntax :: Syntax
    syntax  -> (String -> Either Text a)
    -> (a -> Either Text a) -> Either String a -> Either Text a
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (Text -> Either Text a
    forall a b. a -> Either a b
    Left (Text -> Either Text a)
    -> (String -> Text) -> String -> Either Text a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text
    T.pack) a -> Either Text a
    forall a b. b -> Either a b
    Right (Either String a -> Either Text a)
    -> Either String a -> Either Text a
    forall a b. (a -> b) -> a -> b
    $
                  FormatOptions -> [SourceLine] -> a
    formatter FormatOptions
    fmtOpts{ codeClasses :: [Text]
    codeClasses =
                                       [Text -> Text
    T.toLower (Syntax -> Text
    sShortname Syntax
    syntax)],
                                      containerClasses :: [Text]
    containerClasses = [Text]
    classes } ([SourceLine] -> a)
    -> Either String [SourceLine] -> Either String a
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
                    TokenizerConfig -> Syntax -> Text -> Either String [SourceLine]
    tokenize TokenizerConfig
    tokenizeOpts Syntax
    syntax Text
    rawCode

    -- Functions for correlating latex listings package's language names
    -- with skylighting language names:

    langToListingsMap :: M.Map T.Text T.Text
    langToListingsMap :: Map Text Text
    langToListingsMap = [(Text, Text)] -> Map Text Text
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList [(Text, Text)]
    langsList

    listingsToLangMap :: M.Map T.Text T.Text
    listingsToLangMap :: Map Text Text
    listingsToLangMap = [(Text, Text)] -> Map Text Text
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList ([(Text, Text)] -> Map Text Text)
    -> [(Text, Text)] -> Map Text Text
    forall a b. (a -> b) -> a -> b
    $ ((Text, Text) -> (Text, Text)) -> [(Text, Text)] -> [(Text, Text)]
    forall a b. (a -> b) -> [a] -> [b]
    map (Text, Text) -> (Text, Text)
    forall b a. (b, a) -> (a, b)
    switch [(Text, Text)]
    langsList
      where switch :: (b, a) -> (a, b)
    switch (a :: b
    a,b :: a
    b) = (a
    b,b
    a)

    langsList :: [(T.Text, T.Text)]
    langsList :: [(Text, Text)]
    langsList =
      [("abap","ABAP"),
      ("acm","ACM"),
      ("acmscript","ACMscript"),
      ("acsl","ACSL"),
      ("ada","Ada"),
      ("algol","Algol"),
      ("ant","Ant"),
      ("assembler","Assembler"),
      ("gnuassembler","Assembler"),
      ("awk","Awk"),
      ("bash","bash"),
      ("monobasic","Basic"),
      ("purebasic","Basic"),
      ("c","C"),
      ("cs","C"),
      ("objectivec","C"),
      ("cpp","C++"),
      ("c++","C++"),
      ("ocaml","Caml"),
      ("cil","CIL"),
      ("clean","Clean"),
      ("cobol","Cobol"),
      ("comal80","Comal80"),
      ("command.com","command.com"),
      ("comsol","Comsol"),
      ("csh","csh"),
      ("delphi","Delphi"),
      ("eiffel","Eiffel"),
      ("elan","Elan"),
      ("elisp","elisp"),
      ("erlang","erlang"),
      ("euphoria","Euphoria"),
      ("fortran","Fortran"),
      ("gap","GAP"),
      ("gcl","GCL"),
      ("gnuplot","Gnuplot"),
      ("go","Go"),
      ("hansl","hansl"),
      ("haskell","Haskell"),
      ("html","HTML"),
      ("idl","IDL"),
      ("inform","inform"),
      ("java","Java"),
      ("jvmis","JVMIS"),
      ("ksh","ksh"),
      ("lingo","Lingo"),
      ("lisp","Lisp"),
      ("commonlisp","Lisp"),
      ("llvm","LLVM"),
      ("logo","Logo"),
      ("lua","Lua"),
      ("make","make"),
      ("makefile","make"),
      ("mathematica","Mathematica"),
      ("matlab","Matlab"),
      ("mercury","Mercury"),
      ("metapost","MetaPost"),
      ("miranda","Miranda"),
      ("mizar","Mizar"),
      ("ml","ML"),
      ("modula2","Modula-2"),
      ("mupad","MuPAD"),
      ("nastran","NASTRAN"),
      ("oberon2","Oberon-2"),
      ("ocl","OCL"),
      ("octave","Octave"),
      ("oorexx","OORexx"),
      ("oz","Oz"),
      ("pascal","Pascal"),
      ("perl","Perl"),
      ("php","PHP"),
      ("pli","PL/I"),
      ("plasm","Plasm"),
      ("postscript","PostScript"),
      ("pov","POV"),
      ("prolog","Prolog"),
      ("promela","Promela"),
      ("pstricks","PSTricks"),
      ("python","Python"),
      ("r","R"),
      ("reduce","Reduce"),
      ("rexx","Rexx"),
      ("rsl","RSL"),
      ("ruby","Ruby"),
      ("s","S"),
      ("sas","SAS"),
      ("scala","Scala"),
      ("scilab","Scilab"),
      ("sh","sh"),
      ("shelxl","SHELXL"),
      ("simula","Simula"),
      ("sparql","SPARQL"),
      ("sql","SQL"),
      ("swift","Swift"),
      ("tcl","tcl"),
      ("tex","TeX"),
      ("latex","TeX"),
      ("vbscript","VBScript"),
      ("verilog","Verilog"),
      ("vhdl","VHDL"),
      ("vrml","VRML"),
      ("xml","XML"),
      ("xslt","XSLT")]

    -- | Determine listings language name from skylighting language name.
    toListingsLanguage :: T.Text -> Maybe T.Text
    toListingsLanguage :: Text -> Maybe Text
    toListingsLanguage lang :: Text
    lang = Text -> Map Text Text -> Maybe Text
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup (Text -> Text
    T.toLower Text
    lang) Map Text Text
    langToListingsMap

    -- | Determine skylighting language name from listings language name.
    fromListingsLanguage :: T.Text -> Maybe T.Text
    fromListingsLanguage :: Text -> Maybe Text
    fromListingsLanguage lang :: Text
    lang = Text -> Map Text Text -> Maybe Text
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup Text
    lang Map Text Text
    listingsToLangMap