@@ -39,8 +39,8 @@ import Prelude
3939import Control.Applicative ((<|>))
4040import Control.Monad.State.Strict
4141import Data.Aeson (FromJSON, object, (.=))
42−import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isPunctuation, ord,
43− toLower)
42+import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isSpace,
43+ isPunctuation, ord, toLower)
4444import Data.List (foldl', intercalate, intersperse, isInfixOf, nubBy,
4545 stripPrefix, (\\), uncons)
4646import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, isNothing)
@@ -345,10 +345,20 @@ stringToLaTeX context zs = do
345345 Just cmd -> ((cmd ++ "{" ++ [c] ++ "}") ++)
346346 <$> go opts ctx (drop 1 xs) -- drop combining accent
347347 Nothing -> (c:) <$> go opts ctx xs
348+ let emitcseq cs = do
349+ rest <- go opts ctx xs
350+ case rest of
351+ c:_ | isLetter c
352+ , ctx == TextString
353+ -> return (cs <> " " <> rest)
354+ | isSpace c -> return (cs <> "{}" <> rest)
355+ | ctx == TextString
356+ -> return (cs <> rest)
357+ _ -> return (cs <> "{}" <> rest)
348358 case x of
349359 '{' -> emits "\\{"
350360 '}' -> emits "\\}"
351− '`' | ctx == CodeString -> emits "\\textasciigrave{}"
361+ '`' | ctx == CodeString -> emitcseq "\\textasciigrave"
352362 '$' | not isUrl -> emits "\\$"
353363 '%' -> emits "\\%"
354364 '&' -> emits "\\&"
@@ -358,19 +368,19 @@ stringToLaTeX context zs = do
358368 -- prevent adjacent hyphens from forming ligatures
359369 ('-':_) -> emits "-\\/"
360370 _ -> emitc '-'
361− '~' | not isUrl -> emits "\\textasciitilde{}"
371+ '~' | not isUrl -> emitcseq "\\textasciitilde"
362372 '^' -> emits "\\^{}"
363373 '\\'| isUrl -> emitc '/' -- NB. / works as path sep even on Windows
364− | otherwise -> emits "\\textbackslash{}"
365− '|' | not isUrl -> emits "\\textbar{}"
366− '<' -> emits "\\textless{}"
367− '>' -> emits "\\textgreater{}"
374+ | otherwise -> emitcseq "\\textbackslash"
375+ '|' | not isUrl -> emitcseq "\\textbar"
376+ '<' -> emitcseq "\\textless"
377+ '>' -> emitcseq "\\textgreater"
368378 '[' -> emits "{[}" -- to avoid interpretation as
369379 ']' -> emits "{]}" -- optional arguments
370− '\'' | ctx == CodeString -> emits "\\textquotesingle{}"
380+ '\'' | ctx == CodeString -> emitcseq "\\textquotesingle"
371381 '\160' -> emits "~"
372382 '\x202F' -> emits "\\,"
373− '\x2026' -> emits "\\ldots{}"
383+ '\x2026' -> emitcseq "\\ldots"
374384 '\x2018' | ligatures -> emits "`"
375385 '\x2019' | ligatures -> emits "'"
376386 '\x201C' | ligatures -> emits "``"
@@ -379,22 +389,22 @@ stringToLaTeX context zs = do
379389 '\x2013' | ligatures -> emits "--"
380390 _ | writerPreferAscii opts
381391 -> case x of
382− 'ı' -> emits "\\i "
383− 'ȷ' -> emits "\\j "
384− 'å' -> emits "\\aa "
385− 'Å' -> emits "\\AA "
386− 'ß' -> emits "\\ss "
387− 'ø' -> emits "\\o "
388− 'Ø' -> emits "\\O "
389− 'Ł' -> emits "\\L "
390− 'ł' -> emits "\\l "
391− 'æ' -> emits "\\ae "
392− 'Æ' -> emits "\\AE "
393− 'œ' -> emits "\\oe "
394− 'Œ' -> emits "\\OE "
395− '£' -> emits "\\pounds "
396− '€' -> emits "\\euro "
397− '©' -> emits "\\copyright "
392+ 'ı' -> emitcseq "\\i"
393+ 'ȷ' -> emitcseq "\\j"
394+ 'å' -> emitcseq "\\aa"
395+ 'Å' -> emitcseq "\\AA"
396+ 'ß' -> emitcseq "\\ss"
397+ 'ø' -> emitcseq "\\o"
398+ 'Ø' -> emitcseq "\\O"
399+ 'Ł' -> emitcseq "\\L"
400+ 'ł' -> emitcseq "\\l"
401+ 'æ' -> emitcseq "\\ae"
402+ 'Æ' -> emitcseq "\\AE"
403+ 'œ' -> emitcseq "\\oe"
404+ 'Œ' -> emitcseq "\\OE"
405+ '£' -> emitcseq "\\pounds"
406+ '€' -> emitcseq "\\euro"
407+ '©' -> emitcseq "\\copyright"
398408 _ -> emitc x
399409 | otherwise -> emitc x
400410