{-# LANGUAGE OverloadedStrings   #-}
{- |
   Module      : Text.Pandoc.Writers.LaTeX.Util
   Copyright   : Copyright (C) 2006-2023 John MacFarlane
   License     : GNU GPL, version 2 or above

   Maintainer  : John MacFarlane <jgm@berkeley.edu>
   Stability   : alpha
   Portability : portable
-}
module Text.Pandoc.Writers.LaTeX.Util (
    stringToLaTeX
  , StringContext(..)
  , toLabel
  , inCmd
  , wrapDiv
  , hypertarget
  , labelFor
  , getListingsLanguage
  , mbBraced
  )
where

import Control.Applicative ((<|>))
import Control.Monad (when)
import Text.Pandoc.Class (PandocMonad, toLang)
import Text.Pandoc.Options (WriterOptions(..), isEnabled)
import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState(..))
import Text.Pandoc.Writers.LaTeX.Lang (toBabel)
import Text.Pandoc.Highlighting (toListingsLanguage)
import Text.DocLayout
import Text.Pandoc.Definition
import Text.Pandoc.ImageSize (showFl)
import Control.Monad.State.Strict (gets, modify)
import Data.Text (Text)
import qualified Data.Text as T
import Text.Pandoc.Extensions (Extension(Ext_smart))
import Data.Char (isLetter, isSpace, isDigit, isAscii, ord, isAlphaNum)
import Text.Printf (printf)
import Text.Pandoc.Shared (safeRead)
import qualified Data.Text.Normalize as Normalize
import Data.List (uncons)

data StringContext = TextString
                   | URLString
                   | CodeString
                   deriving (StringContext -> StringContext -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: StringContext -> StringContext -> Bool
$c/= :: StringContext -> StringContext -> Bool
== :: StringContext -> StringContext -> Bool
$c== :: StringContext -> StringContext -> Bool
Eq)

-- escape things as needed for LaTeX
stringToLaTeX :: PandocMonad m => StringContext -> Text -> LW m Text
stringToLaTeX :: forall (m :: * -> *).
PandocMonad m =>
StringContext -> Text -> LW m Text
stringToLaTeX StringContext
context Text
zs = do
  WriterOptions
opts <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets WriterState -> WriterOptions
stOptions
  forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ((Char -> Bool) -> Text -> Bool
T.any (forall a. Eq a => a -> a -> Bool
== Char
'\x200c') Text
zs) forall a b. (a -> b) -> a -> b
$
    forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\WriterState
s -> WriterState
s { stZwnj :: Bool
stZwnj = Bool
True })
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack forall a b. (a -> b) -> a -> b
$
    forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (WriterOptions -> StringContext -> Char -> String -> String
go WriterOptions
opts StringContext
context) forall a. Monoid a => a
mempty forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack forall a b. (a -> b) -> a -> b
$
    if WriterOptions -> Bool
writerPreferAscii WriterOptions
opts
       then NormalizationMode -> Text -> Text
Normalize.normalize NormalizationMode
Normalize.NFD Text
zs
       else Text
zs
 where
  go :: WriterOptions -> StringContext -> Char -> String -> String
  go :: WriterOptions -> StringContext -> Char -> String -> String
go WriterOptions
opts StringContext
ctx Char
x String
xs   =
    let ligatures :: Bool
ligatures = forall a. HasSyntaxExtensions a => Extension -> a -> Bool
isEnabled Extension
Ext_smart WriterOptions
opts Bool -> Bool -> Bool
&& StringContext
ctx forall a. Eq a => a -> a -> Bool
== StringContext
TextString
        isUrl :: Bool
isUrl = StringContext
ctx forall a. Eq a => a -> a -> Bool
== StringContext
URLString
        mbAccentCmd :: Maybe String
mbAccentCmd =
          if WriterOptions -> Bool
writerPreferAscii WriterOptions
opts Bool -> Bool -> Bool
&& StringContext
ctx forall a. Eq a => a -> a -> Bool
== StringContext
TextString
             then forall a. [a] -> Maybe (a, [a])
uncons String
xs forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(Char
c,String
_) -> Char -> Maybe String
lookupAccent Char
c
             else forall a. Maybe a
Nothing
        emits :: String -> String
emits String
s =
          case Maybe String
mbAccentCmd of
               Just String
cmd ->
                 String
cmd forall a. Semigroup a => a -> a -> a
<> String
"{" forall a. Semigroup a => a -> a -> a
<> String
s forall a. Semigroup a => a -> a -> a
<> String
"}" forall a. Semigroup a => a -> a -> a
<> forall a. Int -> [a] -> [a]
drop Int
1 String
xs -- drop combining accent
               Maybe String
Nothing  -> String
s forall a. Semigroup a => a -> a -> a
<> String
xs
        emitc :: Char -> String
emitc Char
c =
          case Maybe String
mbAccentCmd of
               Just String
cmd ->
                 String
cmd forall a. Semigroup a => a -> a -> a
<> String
"{" forall a. Semigroup a => a -> a -> a
<> [Char
c] forall a. Semigroup a => a -> a -> a
<> String
"}" forall a. Semigroup a => a -> a -> a
<> forall a. Int -> [a] -> [a]
drop Int
1 String
xs -- drop combining accent
               Maybe String
Nothing  -> Char
c forall a. a -> [a] -> [a]
: String
xs
        emitcseq :: String -> String
emitcseq String
cs =
          case String
xs of
            Char
c:String
_ | Char -> Bool
isLetter Char
c
                , StringContext
ctx forall a. Eq a => a -> a -> Bool
== StringContext
TextString
                             -> String
cs forall a. Semigroup a => a -> a -> a
<> String
" " forall a. Semigroup a => a -> a -> a
<> String
xs
                | Char -> Bool
isSpace Char
c  -> String
cs forall a. Semigroup a => a -> a -> a
<> String
"{}" forall a. Semigroup a => a -> a -> a
<> String
xs
                | StringContext
ctx forall a. Eq a => a -> a -> Bool
== StringContext
TextString
                             -> String
cs forall a. Semigroup a => a -> a -> a
<> String
xs
            String
_ -> String
cs forall a. Semigroup a => a -> a -> a
<> String
"{}" forall a. Semigroup a => a -> a -> a
<> String
xs
        emitquote :: String -> String
emitquote String
cs =
          case String
xs of
            Char
'`':String
_  -> String
cs forall a. Semigroup a => a -> a -> a
<> String
"\\," forall a. Semigroup a => a -> a -> a
<> String
xs -- add thin space
            Char
'\'':String
_ -> String
cs forall a. Semigroup a => a -> a -> a
<> String
"\\," forall a. Semigroup a => a -> a -> a
<> String
xs -- add thin space
            String
_      -> String
cs forall a. Semigroup a => a -> a -> a
<> String
xs
    in case Char
x of
         Char
_ | Bool
isUrl ->
           case Char
x of
             Char
'\\' -> Char -> String
emitc Char
'/' -- NB / works as path sep even on Windows
             Char
'#' -> String -> String
emits String
"\\#" -- #9014
             Char
'%' -> String -> String
emits String
"\\%" -- #9014
             Char
'{' -> String -> String
emits String
"\\%7B"
             Char
'}' -> String -> String
emits String
"\\%7D"
             Char
'|' -> String -> String
emits String
"\\%7C"
             Char
'^' -> String -> String
emits String
"\\%5E"
             Char
'[' -> String -> String
emits String
"\\%5B"
             Char
']' -> String -> String
emits String
"\\%5D"
             Char
'`' -> String -> String
emits String
"\\%60"
             Char
_ -> Char -> String
emitc Char
x
         Char
'{' -> String -> String
emits String
"\\{"
         Char
'}' -> String -> String
emits String
"\\}"
         Char
'?' | Bool
ligatures ->  -- avoid ?` ligature
           case String
xs of
             Char
'`':String
_ -> String -> String
emits String
"?{}"
             String
_     -> Char -> String
emitc Char
x
         Char
'!' | Bool
ligatures ->  -- avoid !` ligature
           case String
xs of
             Char
'`':String
_ -> String -> String
emits String
"!{}"
             String
_     -> Char -> String
emitc Char
x
         Char
'`' | StringContext
ctx forall a. Eq a => a -> a -> Bool
== StringContext
CodeString -> String -> String
emitcseq String
"\\textasciigrave"
         Char
'$' -> String -> String
emits String
"\\$"
         Char
'%' -> String -> String
emits String
"\\%"
         Char
'&' -> String -> String
emits String
"\\&"
         Char
'_' -> String -> String
emits String
"\\_"
         Char
'#' -> String -> String
emits String
"\\#"
         Char
'-' -> case String
xs of
                     -- prevent adjacent hyphens from forming ligatures
                     (Char
'-':String
_) -> String -> String
emits String
"-\\/"
                     String
_       -> Char -> String
emitc Char
'-'
         Char
'~' -> String -> String
emitcseq String
"\\textasciitilde"
         Char
'^' -> String -> String
emits String
"\\^{}"
         Char
'\\' -> String -> String
emitcseq String
"\\textbackslash"
         Char
'|'  -> String -> String
emitcseq String
"\\textbar"
         Char
'<'  -> String -> String
emitcseq String
"\\textless"
         Char
'>'  -> String -> String
emitcseq String
"\\textgreater"
         Char
'['  -> String -> String
emits String
"{[}"  -- to avoid interpretation as
         Char
']'  -> String -> String
emits String
"{]}"  -- optional arguments
         Char
'\'' -> String -> String
emitcseq String
"\\textquotesingle"
         Char
'\160' -> String -> String
emits String
"~"
         Char
'\x200B' -> String -> String
emits String
"\\hspace{0pt}"  -- zero-width space
         Char
'\x202F' -> String -> String
emits String
"\\,"
         Char
'\x2026' | Bool
ligatures -> String -> String
emitcseq String
"\\ldots"
         Char
'\x2018' | Bool
ligatures -> String -> String
emitquote String
"`"
         Char
'\x2019' | Bool
ligatures -> String -> String
emitquote String
"'"
         Char
'\x201C' | Bool
ligatures -> String -> String
emitquote String
"``"
         Char
'\x201D' | Bool
ligatures -> String -> String
emitquote String
"''"
         Char
'\x2014' | Bool
ligatures -> String -> String
emits String
"---"
         Char
'\x2013' | Bool
ligatures -> String -> String
emits String
"--"
         Char
_ | WriterOptions -> Bool
writerPreferAscii WriterOptions
opts
             -> case Char
x of
                  Char
'ı' -> String -> String
emitcseq String
"\\i"
                  Char
'ȷ' -> String -> String
emitcseq String
"\\j"
                  Char
'å' -> String -> String
emitcseq String
"\\aa"
                  Char
'Å' -> String -> String
emitcseq String
"\\AA"
                  Char
'ß' -> String -> String
emitcseq String
"\\ss"
                  Char
'ø' -> String -> String
emitcseq String
"\\o"
                  Char
'Ø' -> String -> String
emitcseq String
"\\O"
                  Char
'Ł' -> String -> String
emitcseq String
"\\L"
                  Char
'ł' -> String -> String
emitcseq String
"\\l"
                  Char
'æ' -> String -> String
emitcseq String
"\\ae"
                  Char
'Æ' -> String -> String
emitcseq String
"\\AE"
                  Char
'œ' -> String -> String
emitcseq String
"\\oe"
                  Char
'Œ' -> String -> String
emitcseq String
"\\OE"
                  Char
'£' -> String -> String
emitcseq String
"\\pounds"
                  Char
'€' -> String -> String
emitcseq String
"\\euro"
                  Char
'©' -> String -> String
emitcseq String
"\\copyright"
                  Char
_   -> Char -> String
emitc Char
x
           | Bool
otherwise -> Char -> String
emitc Char
x

lookupAccent :: Char -> Maybe String
lookupAccent :: Char -> Maybe String
lookupAccent Char
'\779'  = forall a. a -> Maybe a
Just String
"\\H"
lookupAccent Char
'\768'  = forall a. a -> Maybe a
Just String
"\\`"
lookupAccent Char
'\769'  = forall a. a -> Maybe a
Just String
"\\'"
lookupAccent Char
'\770'  = forall a. a -> Maybe a
Just String
"\\^"
lookupAccent Char
'\771'  = forall a. a -> Maybe a
Just String
"\\~"
lookupAccent Char
'\776'  = forall a. a -> Maybe a
Just String
"\\\""
lookupAccent Char
'\775'  = forall a. a -> Maybe a
Just String
"\\."
lookupAccent Char
'\772'  = forall a. a -> Maybe a
Just String
"\\="
lookupAccent Char
'\781'  = forall a. a -> Maybe a
Just String
"\\|"
lookupAccent Char
'\817'  = forall a. a -> Maybe a
Just String
"\\b"
lookupAccent Char
'\807'  = forall a. a -> Maybe a
Just String
"\\c"
lookupAccent Char
'\783'  = forall a. a -> Maybe a
Just String
"\\G"
lookupAccent Char
'\777'  = forall a. a -> Maybe a
Just String
"\\h"
lookupAccent Char
'\803'  = forall a. a -> Maybe a
Just String
"\\d"
lookupAccent Char
'\785'  = forall a. a -> Maybe a
Just String
"\\f"
lookupAccent Char
'\778'  = forall a. a -> Maybe a
Just String
"\\r"
lookupAccent Char
'\865'  = forall a. a -> Maybe a
Just String
"\\t"
lookupAccent Char
'\782'  = forall a. a -> Maybe a
Just String
"\\U"
lookupAccent Char
'\780'  = forall a. a -> Maybe a
Just String
"\\v"
lookupAccent Char
'\774'  = forall a. a -> Maybe a
Just String
"\\u"
lookupAccent Char
'\808'  = forall a. a -> Maybe a
Just String
"\\k"
lookupAccent Char
'\8413' = forall a. a -> Maybe a
Just String
"\\textcircled"
lookupAccent Char
_       = forall a. Maybe a
Nothing

toLabel :: PandocMonad m => Text -> LW m Text
toLabel :: forall (m :: * -> *). PandocMonad m => Text -> LW m Text
toLabel Text
z = Text -> Text
go forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` forall (m :: * -> *).
PandocMonad m =>
StringContext -> Text -> LW m Text
stringToLaTeX StringContext
URLString Text
z
 where
   go :: Text -> Text
go = (Char -> Text) -> Text -> Text
T.concatMap forall a b. (a -> b) -> a -> b
$ \Char
x -> case Char
x of
     Char
_ | (Char -> Bool
isLetter Char
x Bool -> Bool -> Bool
|| Char -> Bool
isDigit Char
x) Bool -> Bool -> Bool
&& Char -> Bool
isAscii Char
x -> Char -> Text
T.singleton Char
x
       | (Char -> Bool) -> Text -> Bool
T.any (forall a. Eq a => a -> a -> Bool
== Char
x) Text
"_-+=:;." -> Char -> Text
T.singleton Char
x
       | Bool
otherwise -> String -> Text
T.pack forall a b. (a -> b) -> a -> b
$ String
"ux" forall a. Semigroup a => a -> a -> a
<> forall r. PrintfType r => String -> r
printf String
"%x" (Char -> Int
ord Char
x)

-- | Puts contents into LaTeX command.
inCmd :: Text -> Doc Text -> Doc Text
inCmd :: Text -> Doc Text -> Doc Text
inCmd Text
cmd Doc Text
contents = forall a. HasChars a => Char -> Doc a
char Char
'\\' forall a. Semigroup a => a -> a -> a
<> forall a. HasChars a => a -> Doc a
literal Text
cmd forall a. Semigroup a => a -> a -> a
<> forall a. HasChars a => Doc a -> Doc a
braces Doc Text
contents

mapAlignment :: Text -> Text
mapAlignment :: Text -> Text
mapAlignment Text
a = case Text
a of
                   Text
"top" -> Text
"T"
                   Text
"top-baseline" -> Text
"t"
                   Text
"bottom" -> Text
"b"
                   Text
"center" -> Text
"c"
                   Text
_ -> Text
a

wrapDiv :: PandocMonad m => Attr -> Doc Text -> LW m (Doc Text)
wrapDiv :: forall (m :: * -> *).
PandocMonad m =>
Attr -> Doc Text -> LW m (Doc Text)
wrapDiv (Text
_,[Text]
classes,[(Text, Text)]
kvs) Doc Text
t = do
  Bool
beamer <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets WriterState -> Bool
stBeamer
  let align :: Doc Text -> Doc Text -> Doc Text
align Doc Text
dir Doc Text
txt = Text -> Doc Text -> Doc Text
inCmd Text
"begin" Doc Text
dir forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
txt forall a. Doc a -> Doc a -> Doc a
$$ Text -> Doc Text -> Doc Text
inCmd Text
"end" Doc Text
dir
  Maybe Lang
lang <- forall (m :: * -> *). PandocMonad m => Maybe Text -> m (Maybe Lang)
toLang forall a b. (a -> b) -> a -> b
$ forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
"lang" [(Text, Text)]
kvs
  let wrapColumns :: Doc Text -> Doc Text
wrapColumns = if Bool
beamer Bool -> Bool -> Bool
&& Text
"columns" forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
classes
                    then \Doc Text
contents ->
                           let valign :: Text
valign = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"T" Text -> Text
mapAlignment (forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
"align" [(Text, Text)]
kvs)
                               totalwidth :: [Text]
totalwidth = forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\Text
x -> [Text
"totalwidth=" forall a. Semigroup a => a -> a -> a
<> Text
x])
                                 (forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
"totalwidth" [(Text, Text)]
kvs)
                               onlytextwidth :: [Text]
onlytextwidth = forall a. (a -> Bool) -> [a] -> [a]
filter (Text
"onlytextwidth" forall a. Eq a => a -> a -> Bool
==) [Text]
classes
                               options :: Doc Text
options = forall a. HasChars a => String -> Doc a
text forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
T.intercalate Text
"," forall a b. (a -> b) -> a -> b
$
                                 Text
valign forall a. a -> [a] -> [a]
: [Text]
totalwidth forall a. [a] -> [a] -> [a]
++ [Text]
onlytextwidth
                           in Text -> Doc Text -> Doc Text
inCmd Text
"begin" Doc Text
"columns" forall a. Semigroup a => a -> a -> a
<> forall a. HasChars a => Doc a -> Doc a
brackets Doc Text
options
                              forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
contents
                              forall a. Doc a -> Doc a -> Doc a
$$ Text -> Doc Text -> Doc Text
inCmd Text
"end" Doc Text
"columns"
                    else forall a. a -> a
id
      wrapColumn :: Doc Text -> Doc Text
wrapColumn  = if Bool
beamer Bool -> Bool -> Bool
&& Text
"column" forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
classes
                    then \Doc Text
contents ->
                           let valign :: Doc Text
valign =
                                 forall b a. b -> (a -> b) -> Maybe a -> b
maybe Doc Text
""
                                 (forall a. HasChars a => Doc a -> Doc a
brackets forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. HasChars a => String -> Doc a
text forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
mapAlignment)
                                 (forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
"align" [(Text, Text)]
kvs)
                               w :: Text
w = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"0.48" Text -> Text
fromPct (forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
"width" [(Text, Text)]
kvs)
                           in  Text -> Doc Text -> Doc Text
inCmd Text
"begin" Doc Text
"column" forall a. Semigroup a => a -> a -> a
<>
                               Doc Text
valign forall a. Semigroup a => a -> a -> a
<>
                               forall a. HasChars a => Doc a -> Doc a
braces (forall a. HasChars a => a -> Doc a
literal Text
w forall a. Semigroup a => a -> a -> a
<> Doc Text
"\\textwidth")
                               forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
contents
                               forall a. Doc a -> Doc a -> Doc a
$$ Text -> Doc Text -> Doc Text
inCmd Text
"end" Doc Text
"column"
                    else forall a. a -> a
id
      fromPct :: Text -> Text
fromPct Text
xs =
        case Text -> Maybe (Text, Char)
T.unsnoc Text
xs of
          Just (Text
ds, Char
'%') -> case forall (m :: * -> *) a. (MonadPlus m, Read a) => Text -> m a
safeRead Text
ds of
                              Just Double
digits -> forall a. RealFloat a => a -> Text
showFl (Double
digits forall a. Fractional a => a -> a -> a
/ Double
100 :: Double)
                              Maybe Double
Nothing -> Text
xs
          Maybe (Text, Char)
_              -> Text
xs
      wrapDir :: Doc Text -> Doc Text
wrapDir = case forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Text
"dir" [(Text, Text)]
kvs of
                  Just Text
"rtl" -> Doc Text -> Doc Text -> Doc Text
align Doc Text
"RTL"
                  Just Text
"ltr" -> Doc Text -> Doc Text -> Doc Text
align Doc Text
"LTR"
                  Maybe Text
_          -> forall a. a -> a
id
      wrapLang :: Doc Text -> Doc Text
wrapLang Doc Text
txt = case Maybe Lang
lang forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Lang -> Maybe Text
toBabel of
                       Just Text
l -> Text -> Doc Text -> Doc Text
inCmd Text
"begin" Doc Text
"otherlanguage"
                                            forall a. Semigroup a => a -> a -> a
<> (forall a. HasChars a => Doc a -> Doc a
braces (forall a. HasChars a => a -> Doc a
literal Text
l))
                                       forall a. Doc a -> Doc a -> Doc a
$$ forall a. Doc a
blankline forall a. Semigroup a => a -> a -> a
<> Doc Text
txt forall a. Semigroup a => a -> a -> a
<> forall a. Doc a
blankline
                                       forall a. Doc a -> Doc a -> Doc a
$$ Text -> Doc Text -> Doc Text
inCmd Text
"end" Doc Text
"otherlanguage"
                       Maybe Text
Nothing  -> Doc Text
txt
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Doc Text -> Doc Text
wrapColumns forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc Text -> Doc Text
wrapColumn forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc Text -> Doc Text
wrapDir forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc Text -> Doc Text
wrapLang forall a b. (a -> b) -> a -> b
$ Doc Text
t

hypertarget :: PandocMonad m => Text -> LW m (Doc Text)
hypertarget :: forall (m :: * -> *). PandocMonad m => Text -> LW m (Doc Text)
hypertarget Text
"" = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Monoid a => a
mempty
hypertarget Text
ident = do
  Doc Text
label <- forall (m :: * -> *). PandocMonad m => Text -> LW m (Doc Text)
labelFor Text
ident
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. HasChars a => String -> Doc a
text String
"\\phantomsection" forall a. Semigroup a => a -> a -> a
<> Doc Text
label

labelFor :: PandocMonad m => Text -> LW m (Doc Text)
labelFor :: forall (m :: * -> *). PandocMonad m => Text -> LW m (Doc Text)
labelFor Text
""    = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Doc a
empty
labelFor Text
ident = do
  Doc Text
ref <- forall a. HasChars a => a -> Doc a
literal forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` forall (m :: * -> *). PandocMonad m => Text -> LW m Text
toLabel Text
ident
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. HasChars a => String -> Doc a
text String
"\\label" forall a. Semigroup a => a -> a -> a
<> forall a. HasChars a => Doc a -> Doc a
braces Doc Text
ref

-- Determine listings language from list of class attributes.
getListingsLanguage :: [Text] -> Maybe Text
getListingsLanguage :: [Text] -> Maybe Text
getListingsLanguage [Text]
xs
  = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
(<|>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Text
toListingsLanguage) forall a. Maybe a
Nothing [Text]
xs

mbBraced :: Text -> Text
mbBraced :: Text -> Text
mbBraced Text
x = if Bool -> Bool
not ((Char -> Bool) -> Text -> Bool
T.all Char -> Bool
isAlphaNum Text
x)
                then Text
"{" forall a. Semigroup a => a -> a -> a
<> Text
x forall a. Semigroup a => a -> a -> a
<> Text
"}"
                else Text
x