{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Patat.Presentation.Display.CodeBlock
( prettyCodeBlock
) where
import Data.Maybe (mapMaybe)
import qualified Data.Text as T
import Patat.Presentation.Display.Table (themed)
import qualified Patat.PrettyPrint as PP
import Patat.Theme
import Prelude
import qualified Skylighting as Skylighting
highlight :: [T.Text] -> T.Text -> [Skylighting.SourceLine]
highlight :: [Text] -> Text -> [SourceLine]
highlight [Text]
classes Text
rawCodeBlock = case forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Text -> Maybe Syntax
getSyntax [Text]
classes of
[] -> Text -> [SourceLine]
zeroHighlight Text
rawCodeBlock
(Syntax
syn : [Syntax]
_) ->
case TokenizerConfig -> Syntax -> Text -> Either String [SourceLine]
Skylighting.tokenize TokenizerConfig
config Syntax
syn Text
rawCodeBlock of
Left String
_ -> Text -> [SourceLine]
zeroHighlight Text
rawCodeBlock
Right [SourceLine]
sl -> [SourceLine]
sl
where
getSyntax :: T.Text -> Maybe Skylighting.Syntax
getSyntax :: Text -> Maybe Syntax
getSyntax Text
c = Text -> SyntaxMap -> Maybe Syntax
Skylighting.lookupSyntax Text
c SyntaxMap
syntaxMap
config :: Skylighting.TokenizerConfig
config :: TokenizerConfig
config = Skylighting.TokenizerConfig
{ syntaxMap :: SyntaxMap
Skylighting.syntaxMap = SyntaxMap
syntaxMap
, traceOutput :: Bool
Skylighting.traceOutput = Bool
False
}
syntaxMap :: Skylighting.SyntaxMap
syntaxMap :: SyntaxMap
syntaxMap = SyntaxMap
Skylighting.defaultSyntaxMap
zeroHighlight :: T.Text -> [Skylighting.SourceLine]
zeroHighlight :: Text -> [SourceLine]
zeroHighlight Text
txt =
[[(TokenType
Skylighting.NormalTok, Text
line)] | Text
line <- Text -> [Text]
T.lines Text
txt]
prettyCodeBlock :: Theme -> [T.Text] -> T.Text -> PP.Doc
prettyCodeBlock :: Theme -> [Text] -> Text -> Doc
prettyCodeBlock theme :: Theme
theme@Theme {Maybe Text
Maybe SyntaxHighlighting
Maybe Style
themeSyntaxHighlighting :: Theme -> Maybe SyntaxHighlighting
themeImageTarget :: Theme -> Maybe Style
themeImageText :: Theme -> Maybe Style
themeMath :: Theme -> Maybe Style
themeQuoted :: Theme -> Maybe Style
themeStrikeout :: Theme -> Maybe Style
themeLinkTarget :: Theme -> Maybe Style
themeLinkText :: Theme -> Maybe Style
themeCode :: Theme -> Maybe Style
themeUnderline :: Theme -> Maybe Style
themeStrong :: Theme -> Maybe Style
themeEmph :: Theme -> Maybe Style
themeLineBlock :: Theme -> Maybe Style
themeTableSeparator :: Theme -> Maybe Style
themeTableHeader :: Theme -> Maybe Style
themeDefinitionList :: Theme -> Maybe Style
themeDefinitionTerm :: Theme -> Maybe Style
themeBlockQuote :: Theme -> Maybe Style
themeOrderedList :: Theme -> Maybe Style
themeBulletListMarkers :: Theme -> Maybe Text
themeBulletList :: Theme -> Maybe Style
themeCodeBlock :: Theme -> Maybe Style
themeHeader :: Theme -> Maybe Style
themeBorders :: Theme -> Maybe Style
themeSyntaxHighlighting :: Maybe SyntaxHighlighting
themeImageTarget :: Maybe Style
themeImageText :: Maybe Style
themeMath :: Maybe Style
themeQuoted :: Maybe Style
themeStrikeout :: Maybe Style
themeLinkTarget :: Maybe Style
themeLinkText :: Maybe Style
themeCode :: Maybe Style
themeUnderline :: Maybe Style
themeStrong :: Maybe Style
themeEmph :: Maybe Style
themeLineBlock :: Maybe Style
themeTableSeparator :: Maybe Style
themeTableHeader :: Maybe Style
themeDefinitionList :: Maybe Style
themeDefinitionTerm :: Maybe Style
themeBlockQuote :: Maybe Style
themeOrderedList :: Maybe Style
themeBulletListMarkers :: Maybe Text
themeBulletList :: Maybe Style
themeCodeBlock :: Maybe Style
themeHeader :: Maybe Style
themeBorders :: Maybe Style
..} [Text]
classes Text
rawCodeBlock =
[Doc] -> Doc
PP.vcat (forall a b. (a -> b) -> [a] -> [b]
map SourceLine -> Doc
blockified [SourceLine]
sourceLines) forall a. Semigroup a => a -> a -> a
<>
Doc
PP.hardline
where
sourceLines :: [Skylighting.SourceLine]
sourceLines :: [SourceLine]
sourceLines =
[[]] forall a. [a] -> [a] -> [a]
++ [Text] -> Text -> [SourceLine]
highlight [Text]
classes Text
rawCodeBlock forall a. [a] -> [a] -> [a]
++ [[]]
prettySourceLine :: Skylighting.SourceLine -> PP.Doc
prettySourceLine :: SourceLine -> Doc
prettySourceLine = forall a. Monoid a => [a] -> a
mconcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Token -> Doc
prettyToken
prettyToken :: Skylighting.Token -> PP.Doc
prettyToken :: Token -> Doc
prettyToken (TokenType
tokenType, Text
str) =
Maybe Style -> Doc -> Doc
themed (Theme -> TokenType -> Maybe Style
syntaxHighlight Theme
theme TokenType
tokenType) (String -> Doc
PP.string forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
str)
sourceLineLength :: Skylighting.SourceLine -> Int
sourceLineLength :: SourceLine -> Int
sourceLineLength SourceLine
line = forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Text -> Int
T.length Text
str | (TokenType
_, Text
str) <- SourceLine
line]
blockWidth :: Int
blockWidth :: Int
blockWidth = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall a. Ord a => a -> a -> a
max Int
0 (forall a b. (a -> b) -> [a] -> [b]
map SourceLine -> Int
sourceLineLength [SourceLine]
sourceLines)
blockified :: Skylighting.SourceLine -> PP.Doc
blockified :: SourceLine -> Doc
blockified SourceLine
line =
let len :: Int
len = SourceLine -> Int
sourceLineLength SourceLine
line
indent :: Trimmable Doc
indent = forall a. a -> Trimmable a
PP.NotTrimmable Doc
" " in
Trimmable Doc -> Trimmable Doc -> Doc -> Doc
PP.indent Trimmable Doc
indent Trimmable Doc
indent forall a b. (a -> b) -> a -> b
$
Maybe Style -> Doc -> Doc
themed Maybe Style
themeCodeBlock forall a b. (a -> b) -> a -> b
$
Doc
" " forall a. Semigroup a => a -> a -> a
<>
SourceLine -> Doc
prettySourceLine SourceLine
line forall a. Semigroup a => a -> a -> a
<>
String -> Doc
PP.string (forall a. Int -> a -> [a]
replicate (Int
blockWidth forall a. Num a => a -> a -> a
- Int
len) Char
' ') forall a. Semigroup a => a -> a -> a
<> Doc
" "