{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{- |
   Module      : Text.Pandoc.Highlighting
   Copyright   : Copyright (C) 2008-2019 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 Prelude
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