-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Expand file tree
/
Copy pathMath.hs
More file actions
102 lines (93 loc) · 3.86 KB
/
Copy pathMath.hs
File metadata and controls
102 lines (93 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Parsing.Math
Copyright : © 2006-2024 John MacFarlane
License : GPL-2.0-or-later
Maintainer : John MacFarlane <jgm@berkeley.edu>
Parsing of LaTeX math.
-}
module Text.Pandoc.Parsing.Math
( mathDisplay
, mathInline
)
where
import Control.Monad (mzero, when)
import Data.Text (Text)
import Text.Parsec ((<|>), ParsecT, Stream(..), notFollowedBy, many1, try)
import Text.Pandoc.Options
( Extension(Ext_tex_math_dollars, Ext_tex_math_single_backslash,
Ext_tex_math_double_backslash) )
import Text.Pandoc.Parsing.Capabilities (HasReaderOptions, guardEnabled)
import Text.Pandoc.Parsing.General
import Text.Pandoc.Shared (trimMath)
import Text.Pandoc.Sources
(UpdateSourcePos, anyChar, char, digit, newline, satisfy, space, string)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TB
mathInlineWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParsecT s st m Text
mathInlineWith op cl = try $ do
textStr op
when (op == "$") $ notFollowedBy space
words' <- many1Till (
(T.singleton <$>
satisfy (\c -> not (isSpaceChar c || c == '\\')))
<|> (char '\\' >>
-- This next clause is needed because \text{..} can
-- contain $, \(\), etc.
(try (string "text" >>
(("\\text" <>) <$> inBalancedBraces 0 ""))
<|> (\c -> T.pack ['\\',c]) <$> anyChar))
<|> ("\n" <$ blankline <* notFollowedBy' blankline <* notFollowedBy (char '$'))
<|> (T.pack <$> many1 spaceChar <* notFollowedBy (char '$'))
) (try $ textStr cl)
notFollowedBy digit -- to prevent capture of $5
return $ trimMath $ T.concat words'
where
inBalancedBraces :: (Stream s m Char, UpdateSourcePos s Char)
=> Int -> Text -> ParsecT s st m Text
inBalancedBraces n t =
TL.toStrict . TB.toLazyText <$>
go n False (TB.fromText t) (not (T.null t))
-- go depth lastWasBackslash accumulator started
go :: (Stream s m Char, UpdateSourcePos s Char)
=> Int -> Bool -> TB.Builder -> Bool -> ParsecT s st m TB.Builder
go 0 _ acc False = do
c <- anyChar
if c == '{'
then go 1 False (acc <> TB.singleton '{') True
else mzero
go 0 _ acc True = return acc
go depth True acc _ = do
c <- anyChar
go depth False (acc <> TB.singleton c) True
go depth False acc _ = do
c <- anyChar
let acc' = acc <> TB.singleton c
case c of
'\\' -> go depth True acc' True
'}' -> go (depth - 1) False acc' True
'{' -> go (depth + 1) False acc' True
_ -> go depth False acc' True
mathDisplayWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParsecT s st m Text
mathDisplayWith op cl = try $ fmap T.pack $ do
textStr op
many1Till (satisfy (/= '\n') <|> (newline <* notFollowedBy' blankline))
(try $ textStr cl)
mathDisplay :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
=> ParsecT s st m Text
mathDisplay =
(guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
<|> (guardEnabled Ext_tex_math_single_backslash >>
mathDisplayWith "\\[" "\\]")
<|> (guardEnabled Ext_tex_math_double_backslash >>
mathDisplayWith "\\\\[" "\\\\]")
mathInline :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
=> ParsecT s st m Text
mathInline =
(guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
<|> (guardEnabled Ext_tex_math_single_backslash >>
mathInlineWith "\\(" "\\)")
<|> (guardEnabled Ext_tex_math_double_backslash >>
mathInlineWith "\\\\(" "\\\\)")