git.iko.soy/typeable/pandoc
on master help sign in
T.P.Shared: remove `backslashEscapes`, `escapeStringUsing`.

[API change] These are inefficient association list lookups. Replace with more efficient functions in the writers that used them (with 10-25% performance improvements in haddock, org, rtf, texinfo writers).

commita1a57bce4e32cc26b968bcc2847a8e8da30f725b authorJohn MacFarlane <jgm@berkeley.edu> dateSat 20 Mar 2021, 00:02 (6 years ago) parentceadf33
8 files changed+77−47
src/Text/Pandoc/Shared.hs−13 src/Text/Pandoc/Writers/AsciiDoc.hs+8−3 src/Text/Pandoc/Writers/ConTeXt.hs+5−1 src/Text/Pandoc/Writers/Haddock.hs+13−2 src/Text/Pandoc/Writers/LaTeX.hs+13−1 src/Text/Pandoc/Writers/Org.hs+9−6 src/Text/Pandoc/Writers/RTF.hs+16−10 src/Text/Pandoc/Writers/Texinfo.hs+13−11
src/Text/Pandoc/Shared.hs−13
@@ -26,8 +26,6 @@ module Text.Pandoc.Shared (
2626 findM,
2727 -- * Text processing
2828 tshow,
29− backslashEscapes,
30− escapeStringUsing,
3129 elemText,
3230 notElemText,
3331 stripTrailingNewlines,
@@ -184,17 +182,6 @@ findM p = foldr go (pure Nothing)
184182tshow :: Show a => a -> T.Text
185183tshow = T.pack . show
186184
187−-- | Returns an association list of backslash escapes for the
188−-- designated characters.
189−backslashEscapes :: [Char] -- ^ list of special characters to escape
190− -> [(Char, T.Text)]
191−backslashEscapes = map (\ch -> (ch, T.pack ['\\',ch]))
192−
193−-- | Escape a string of characters, using an association list of
194−-- characters and strings.
195−escapeStringUsing :: [(Char, T.Text)] -> T.Text -> T.Text
196−escapeStringUsing tbl = T.concatMap $ \c -> fromMaybe (T.singleton c) $ lookup c tbl
197−
198185-- | @True@ exactly when the @Char@ appears in the @Text@.
199186elemText :: Char -> T.Text -> Bool
200187elemText c = T.any (== c)
src/Text/Pandoc/Writers/AsciiDoc.hs+8−3
@@ -105,8 +105,11 @@ pandocToAsciiDoc opts (Pandoc meta blocks) = do
105105
106106-- | Escape special characters for AsciiDoc.
107107escapeString :: Text -> Text
108−escapeString = escapeStringUsing escs
109− where escs = backslashEscapes "{"
108+escapeString t
109+ | T.any (== '{') t = T.concatMap escChar t
110+ | otherwise = t
111+ where escChar '{' = "\\{"
112+ escChar c = T.singleton c
110113
111114-- | Ordered list start parser for use in Para below.
112115olMarker :: Parser Text ParserState Char
@@ -496,7 +499,9 @@ inlineToAsciiDoc opts (Quoted qt lst) = do
496499 | otherwise -> [Str "``"] ++ lst ++ [Str "''"]
497500inlineToAsciiDoc _ (Code _ str) = do
498501 isAsciidoctor <- gets asciidoctorVariant
499− let contents = literal (escapeStringUsing (backslashEscapes "`") str)
502+ let escChar '`' = "\\'"
503+ escChar c = T.singleton c
504+ let contents = literal (T.concatMap escChar str)
500505 return $
501506 if isAsciidoctor
502507 then text "`+" <> contents <> "+`"
src/Text/Pandoc/Writers/ConTeXt.hs+5−1
@@ -434,9 +434,13 @@ inlineToConTeXt (Link _ txt (src, _)) = do
434434 put $ st {stNextRef = next + 1}
435435 let ref = "url" <> tshow next
436436 contents <- inlineListToConTeXt txt
437+ let escChar '#' = "\\#"
438+ escChar '%' = "\\%"
439+ escChar c = T.singleton c
440+ let escContextURL = T.concatMap escChar
437441 return $ "\\useURL"
438442 <> brackets (literal ref)
439− <> brackets (literal $ escapeStringUsing [('#',"\\#"),('%',"\\%")] src)
443+ <> brackets (literal $ escContextURL src)
440444 <> (if isAutolink
441445 then empty
442446 else brackets empty <> brackets contents)
src/Text/Pandoc/Writers/Haddock.hs+13−2
@@ -15,6 +15,7 @@ Haddock: <http://www.haskell.org/haddock/doc/html/>
1515-}
1616module Text.Pandoc.Writers.Haddock (writeHaddock) where
1717import Control.Monad.State.Strict
18+import Data.Char (isAlphaNum)
1819import Data.Default
1920import Data.Text (Text)
2021import qualified Data.Text as T
@@ -71,8 +72,18 @@ notesToHaddock opts notes =
7172
7273-- | Escape special characters for Haddock.
7374escapeString :: Text -> Text
74−escapeString = escapeStringUsing haddockEscapes
75− where haddockEscapes = backslashEscapes "\\/'`\"@<"
75+escapeString t
76+ | T.all isAlphaNum t = t
77+ | otherwise = T.concatMap escChar t
78+ where
79+ escChar '\\' = "\\\\"
80+ escChar '/' = "\\/"
81+ escChar '\'' = "\\'"
82+ escChar '`' = "\\`"
83+ escChar '"' = "\\\""
84+ escChar '@' = "\\@"
85+ escChar '<' = "\\<"
86+ escChar c = T.singleton c
7687
7788-- | Convert Pandoc block element to haddock.
7889blockToHaddock :: PandocMonad m
src/Text/Pandoc/Writers/LaTeX.hs+13−1
@@ -825,7 +825,19 @@ inlineToLaTeX (Code (_,classes,kvs) str) = do
825825 let chr = case "!\"'()*,-./:;?@" \\ T.unpack str of
826826 (c:_) -> c
827827 [] -> '!'
828− let str' = escapeStringUsing (backslashEscapes "\\{}%~_&#^") str
828+ let isEscapable '\\' = True
829+ isEscapable '{' = True
830+ isEscapable '}' = True
831+ isEscapable '%' = True
832+ isEscapable '~' = True
833+ isEscapable '_' = True
834+ isEscapable '&' = True
835+ isEscapable '#' = True
836+ isEscapable '^' = True
837+ isEscapable _ = False
838+ let escChar c | isEscapable c = T.pack ['\\',c]
839+ | otherwise = T.singleton c
840+ let str' = T.concatMap escChar str
829841 -- we always put lstinline in a dummy 'passthrough' command
830842 -- (defined in the default template) so that we don't have
831843 -- to change the way we escape characters depending on whether
src/Text/Pandoc/Writers/Org.hs+9−6
@@ -84,12 +84,15 @@ noteToOrg num note = do
8484
8585-- | Escape special characters for Org.
8686escapeString :: Text -> Text
87−escapeString = escapeStringUsing
88− [ ('\x2014',"---")
89− , ('\x2013',"--")
90− , ('\x2019',"'")
91− , ('\x2026',"...")
92− ]
87+escapeString t
88+ | T.all (\c -> c < '\x2013' || c > '\x2026') t = t
89+ | otherwise = T.concatMap escChar t
90+ where
91+ escChar '\x2013' = "--"
92+ escChar '\x2014' = "---"
93+ escChar '\x2019' = "'"
94+ escChar '\x2026' = "..."
95+ escChar c = T.singleton c
9396
9497isRawFormat :: Format -> Bool
9598isRawFormat f =
src/Text/Pandoc/Writers/RTF.hs+16−10
@@ -16,7 +16,7 @@ module Text.Pandoc.Writers.RTF ( writeRTF
1616import Control.Monad.Except (catchError, throwError)
1717import Control.Monad
1818import qualified Data.ByteString as B
19−import Data.Char (chr, isDigit, ord)
19+import Data.Char (chr, isDigit, ord, isAlphaNum)
2020import qualified Data.Map as M
2121import Data.Text (Text)
2222import qualified Data.Text as T
@@ -137,15 +137,21 @@ handleUnicode = T.concatMap $ \c ->
137137
138138-- | Escape special characters.
139139escapeSpecial :: Text -> Text
140−escapeSpecial = escapeStringUsing $
141− [ ('\t',"\\tab ")
142− , ('\8216',"\\u8216'")
143− , ('\8217',"\\u8217'")
144− , ('\8220',"\\u8220\"")
145− , ('\8221',"\\u8221\"")
146− , ('\8211',"\\u8211-")
147− , ('\8212',"\\u8212-")
148− ] <> backslashEscapes "{\\}"
140+escapeSpecial t
141+ | T.all isAlphaNum t = t
142+ | otherwise = T.concatMap escChar t
143+ where
144+ escChar '\t' = "\\tab "
145+ escChar '\8216' = "\\u8216'"
146+ escChar '\8217' = "\\u8217'"
147+ escChar '\8220' = "\\u8220\""
148+ escChar '\8221' = "\\u8221\""
149+ escChar '\8211' = "\\u8211-"
150+ escChar '\8212' = "\\u8212-"
151+ escChar '{' = "\\{"
152+ escChar '}' = "\\}"
153+ escChar '\\' = "\\\\"
154+ escChar c = T.singleton c
149155
150156-- | Escape strings as needed for rich text format.
151157stringToRTF :: Text -> Text
src/Text/Pandoc/Writers/Texinfo.hs+13−11
@@ -14,7 +14,7 @@ Conversion of 'Pandoc' format into Texinfo.
1414module Text.Pandoc.Writers.Texinfo ( writeTexinfo ) where
1515import Control.Monad.Except (throwError)
1616import Control.Monad.State.Strict
17−import Data.Char (chr, ord)
17+import Data.Char (chr, ord, isAlphaNum)
1818import Data.List (maximumBy, transpose, foldl')
1919import Data.List.NonEmpty (nonEmpty)
2020import Data.Ord (comparing)
@@ -85,16 +85,18 @@ pandocToTexinfo options (Pandoc meta blocks) = do
8585
8686-- | Escape things as needed for Texinfo.
8787stringToTexinfo :: Text -> Text
88−stringToTexinfo = escapeStringUsing texinfoEscapes
89− where texinfoEscapes = [ ('{', "@{")
90− , ('}', "@}")
91− , ('@', "@@")
92− , ('\160', "@ ")
93− , ('\x2014', "---")
94− , ('\x2013', "--")
95− , ('\x2026', "@dots{}")
96− , ('\x2019', "'")
97− ]
88+stringToTexinfo t
89+ | T.all isAlphaNum t = t
90+ | otherwise = T.concatMap escChar t
91+ where escChar '{' = "@{"
92+ escChar '}' = "@}"
93+ escChar '@' = "@@"
94+ escChar '\160' = "@ "
95+ escChar '\x2014' = "---"
96+ escChar '\x2013' = "--"
97+ escChar '\x2026' = "@dots{}"
98+ escChar '\x2019' = "'"
99+ escChar c = T.singleton c
98100
99101escapeCommas :: PandocMonad m => TI m (Doc Text) -> TI m (Doc Text)
100102escapeCommas parser = do