git.iko.soy/typeable/pandoc
on master help sign in
Move common groff functions to Text.Pandoc.Writers.Groff

(unexported module). These are used in both the man and ms writers. Moved groffEscape out of Text.Pandoc.Writers.Shared [cancels earlier API change from adding it, which was after last release]. This fixes strong/code combination on man (should be `\f[CB]` not `\f[BC]`), mentioned in #4973. Updated tests. Closes #4975.

commitf48960b75fe2d7ae532ec17a060109c92b893f57 authorJohn MacFarlane <jgm@berkeley.edu> dateWed 17 Oct 2018, 17:23 (8 years ago) parentb3feaba
11 files changed+221−215
pandoc.cabal+1 src/Text/Pandoc/Writers/Groff.hs+149 src/Text/Pandoc/Writers/Man.hs+2−56 src/Text/Pandoc/Writers/Ms.hs+3−85 src/Text/Pandoc/Writers/Shared.hs+1−10 test/command/3568.md+1−1 test/command/4550.md+1−1 test/tables.man+4−4 test/tables.ms+4−4 test/writer.man+38−37 test/writer.ms+17−17
pandoc.cabal+1
@@ -532,6 +532,7 @@ library
532532 Text.Pandoc.Readers.Org.ParserState,
533533 Text.Pandoc.Readers.Org.Parsing,
534534 Text.Pandoc.Readers.Org.Shared,
535+ Text.Pandoc.Writers.Groff,
535536 Text.Pandoc.Writers.Powerpoint.Presentation,
536537 Text.Pandoc.Writers.Powerpoint.Output,
537538 Text.Pandoc.Lua.Filter,
src/Text/Pandoc/Writers/Groff.hsnew file+149
@@ -0,0 +1,149 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-
3+Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
19+
20+{- |
21+ Module : Text.Pandoc.Writers.Groff
22+ Copyright : Copyright (C) 2007-2018 John MacFarlane
23+ License : GNU GPL, version 2 or above
24+
25+ Maintainer : John MacFarlane <jgm@berkeley.edu>
26+ Stability : alpha
27+ Portability : portable
28+
29+Common functions for groff writers (man, ms).
30+-}
31+
32+module Text.Pandoc.Writers.Groff (
33+ WriterState(..)
34+ , defaultWriterState
35+ , MS
36+ , Note
37+ , escapeChar
38+ , escapeString
39+ , escapeCode
40+ , groffEscape
41+ , withFontFeature
42+ ) where
43+import Prelude
44+import qualified Data.Text as T
45+import Data.Char (isAscii, ord)
46+import Control.Monad.State.Strict
47+import Data.List (intercalate)
48+import qualified Data.Map as Map
49+import Data.Maybe (fromMaybe)
50+import Text.Pandoc.Class (PandocMonad)
51+import Text.Pandoc.Definition
52+import Text.Pandoc.Pretty
53+import Text.Printf (printf)
54+
55+data WriterState = WriterState { stHasInlineMath :: Bool
56+ , stFirstPara :: Bool
57+ , stNotes :: [Note]
58+ , stSmallCaps :: Bool
59+ , stHighlighting :: Bool
60+ , stInHeader :: Bool
61+ , stFontFeatures :: Map.Map Char Bool
62+ , stHasTables :: Bool
63+ }
64+
65+defaultWriterState :: WriterState
66+defaultWriterState = WriterState{ stHasInlineMath = False
67+ , stFirstPara = True
68+ , stNotes = []
69+ , stSmallCaps = False
70+ , stHighlighting = False
71+ , stInHeader = False
72+ , stFontFeatures = Map.fromList [
73+ ('I',False)
74+ , ('B',False)
75+ , ('C',False)
76+ ]
77+ , stHasTables = False
78+ }
79+
80+type Note = [Block]
81+
82+type MS = StateT WriterState
83+
84+-- | Association list of characters to escape.
85+groffEscapes :: Map.Map Char String
86+groffEscapes = Map.fromList
87+ [ ('\160', "\\~")
88+ , ('\'', "\\[aq]")
89+ , ('`', "\\`")
90+ , ('"', "\\[dq]")
91+ , ('\x201C', "\\[lq]")
92+ , ('\x201D', "\\[rq]")
93+ , ('\x2018', "\\[oq]")
94+ , ('\x2019', "\\[cq]")
95+ , ('\x2014', "\\[em]")
96+ , ('\x2013', "\\[en]")
97+ , ('\x2026', "\\&...")
98+ , ('~', "\\[ti]")
99+ , ('^', "\\[ha]")
100+ , ('@', "\\@")
101+ , ('\\', "\\\\")
102+ ]
103+
104+escapeChar :: Char -> String
105+escapeChar c = fromMaybe [c] (Map.lookup c groffEscapes)
106+
107+-- | Escape special characters for groff.
108+escapeString :: String -> String
109+escapeString = concatMap escapeChar
110+
111+-- | Escape a literal (code) section for groff.
112+escapeCode :: String -> String
113+escapeCode = intercalate "\n" . map escapeLine . lines
114+ where escapeCodeChar ' ' = "\\ "
115+ escapeCodeChar '\t' = "\\\t"
116+ escapeCodeChar c = escapeChar c
117+ escapeLine codeline =
118+ case concatMap escapeCodeChar codeline of
119+ a@('.':_) -> "\\&" ++ a
120+ b -> b
121+
122+-- | Escape non-ASCII characters using groff \u[..] sequences.
123+groffEscape :: T.Text -> T.Text
124+groffEscape = T.concatMap toUchar
125+ where toUchar c
126+ | isAscii c = T.singleton c
127+ | otherwise = T.pack $ printf "\\[u%04X]" (ord c)
128+
129+fontChange :: PandocMonad m => MS m Doc
130+fontChange = do
131+ features <- gets stFontFeatures
132+ inHeader <- gets stInHeader
133+ let filling = ['C' | fromMaybe False $ Map.lookup 'C' features] ++
134+ ['B' | inHeader ||
135+ fromMaybe False (Map.lookup 'B' features)] ++
136+ ['I' | fromMaybe False $ Map.lookup 'I' features]
137+ return $
138+ if null filling
139+ then text "\\f[R]"
140+ else text $ "\\f[" ++ filling ++ "]"
141+
142+withFontFeature :: PandocMonad m => Char -> MS m Doc -> MS m Doc
143+withFontFeature c action = do
144+ modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
145+ begin <- fontChange
146+ d <- action
147+ modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
148+ end <- fontChange
149+ return $ begin <> d <> end
src/Text/Pandoc/Writers/Man.hs+2−56
@@ -33,8 +33,7 @@ Conversion of 'Pandoc' documents to groff man page format.
3333module Text.Pandoc.Writers.Man ( writeMan) where
3434import Prelude
3535import Control.Monad.State.Strict
36−import Data.List (intercalate, intersperse, sort, stripPrefix)
37−import qualified Data.Map as Map
36+import Data.List (intersperse, stripPrefix)
3837import Data.Maybe (fromMaybe)
3938import Data.Text (Text)
4039import qualified Data.Text as T
@@ -48,22 +47,9 @@ import Text.Pandoc.Shared
4847import Text.Pandoc.Templates
4948import Text.Pandoc.Writers.Math
5049import Text.Pandoc.Writers.Shared
50+import Text.Pandoc.Writers.Groff
5151import Text.Printf (printf)
5252
53−type Notes = [[Block]]
54−data WriterState = WriterState { stNotes :: Notes
55− , stFontFeatures :: Map.Map Char Bool
56− , stHasTables :: Bool }
57−
58−defaultWriterState :: WriterState
59−defaultWriterState = WriterState { stNotes = []
60− , stFontFeatures = Map.fromList [
61− ('I',False)
62− , ('B',False)
63− , ('C',False)
64− ]
65− , stHasTables = False }
66−
6753-- | Convert Pandoc to Man.
6854writeMan :: PandocMonad m => WriterOptions -> Pandoc -> m Text
6955writeMan opts document =
@@ -127,28 +113,6 @@ noteToMan opts num note = do
127113 let marker = cr <> text ".SS " <> brackets (text (show num))
128114 return $ marker $$ contents
129115
130−-- | Association list of characters to escape.
131−manEscapes :: [(Char, String)]
132−manEscapes = [ ('\160', "\\ ")
133− , ('\'', "\\[aq]")
134− , ('’', "'")
135− , ('\x2014', "\\[em]")
136− , ('\x2013', "\\[en]")
137− , ('\x2026', "\\&...")
138− ] ++ backslashEscapes "-@\\"
139−
140−-- | Escape special characters for Man.
141−escapeString :: String -> String
142−escapeString = escapeStringUsing manEscapes
143−
144−-- | Escape a literal (code) section for Man.
145−escapeCode :: String -> String
146−escapeCode = intercalate "\n" . map escapeLine . lines where
147− escapeLine codeline =
148− case escapeStringUsing (manEscapes ++ backslashEscapes "\t ") codeline of
149− a@('.':_) -> "\\&" ++ a
150− b -> b
151−
152116-- We split inline lists into sentences, and print one sentence per
153117-- line. groff/troff treats the line-ending period differently.
154118-- See http://code.google.com/p/pandoc/issues/detail?id=148.
@@ -373,21 +337,3 @@ inlineToMan _ (Note contents) = do
373337 notes <- gets stNotes
374338 let ref = show (length notes)
375339 return $ char '[' <> text ref <> char ']'
376−
377−fontChange :: PandocMonad m => StateT WriterState m Doc
378−fontChange = do
379− features <- gets stFontFeatures
380− let filling = sort [c | (c,True) <- Map.toList features]
381− return $ text $ "\\f[" ++ (if null filling then "R" else filling) ++ "]"
382−
383−withFontFeature :: PandocMonad m
384− => Char
385− -> StateT WriterState m Doc
386− -> StateT WriterState m Doc
387−withFontFeature c action = do
388− modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
389− begin <- fontChange
390− d <- action
391− modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
392− end <- fontChange
393− return $ begin <> d <> end
src/Text/Pandoc/Writers/Ms.hs+3−85
@@ -60,36 +60,10 @@ import Text.Pandoc.Shared
6060import Text.Pandoc.Templates
6161import Text.Pandoc.Writers.Math
6262import Text.Pandoc.Writers.Shared
63+import Text.Pandoc.Writers.Groff
6364import Text.Printf (printf)
6465import Text.TeXMath (writeEqn)
6566
66−data WriterState = WriterState { stHasInlineMath :: Bool
67− , stFirstPara :: Bool
68− , stNotes :: [Note]
69− , stSmallCaps :: Bool
70− , stHighlighting :: Bool
71− , stInHeader :: Bool
72− , stFontFeatures :: Map.Map Char Bool
73− }
74−
75−defaultWriterState :: WriterState
76−defaultWriterState = WriterState{ stHasInlineMath = False
77− , stFirstPara = True
78− , stNotes = []
79− , stSmallCaps = False
80− , stHighlighting = False
81− , stInHeader = False
82− , stFontFeatures = Map.fromList [
83− ('I',False)
84− , ('B',False)
85− , ('C',False)
86− ]
87− }
88−
89−type Note = [Block]
90−
91−type MS = StateT WriterState
92−
9367-- | Convert Pandoc to Ms.
9468writeMs :: PandocMonad m => WriterOptions -> Pandoc -> m Text
9569writeMs opts document =
@@ -132,24 +106,8 @@ pandocToMs opts (Pandoc meta blocks) = do
132106 Nothing -> return main
133107 Just tpl -> renderTemplate' tpl context
134108
135−-- | Association list of characters to escape.
136−msEscapes :: Map.Map Char String
137−msEscapes = Map.fromList
138− [ ('\160', "\\~")
139− , ('\'', "\\[aq]")
140− , ('`', "\\`")
141− , ('"', "\\[dq]")
142− , ('\x2014', "\\[em]")
143− , ('\x2013', "\\[en]")
144− , ('\x2026', "\\&...")
145− , ('~', "\\[ti]")
146− , ('^', "\\[ha]")
147− , ('@', "\\@")
148− , ('\\', "\\\\")
149− ]
150−
151−escapeChar :: Char -> String
152−escapeChar c = fromMaybe [c] (Map.lookup c msEscapes)
109+escapeUri :: String -> String
110+escapeUri = escapeURIString (\c -> c /= '@' && isAllowedInURI c)
153111
154112-- | Escape | character, used to mark inline math, inside math.
155113escapeBar :: String -> String
@@ -157,13 +115,6 @@ escapeBar = concatMap go
157115 where go '|' = "\\[u007C]"
158116 go c = [c]
159117
160−-- | Escape special characters for Ms.
161−escapeString :: String -> String
162−escapeString = concatMap escapeChar
163−
164−escapeUri :: String -> String
165−escapeUri = escapeURIString (\c -> c /= '@' && isAllowedInURI c)
166−
167118toSmallCaps :: String -> String
168119toSmallCaps [] = []
169120toSmallCaps (c:cs)
@@ -174,17 +125,6 @@ toSmallCaps (c:cs)
174125 in escapeString uppers ++ toSmallCaps rest
175126 | otherwise = escapeChar c ++ toSmallCaps cs
176127
177−-- | Escape a literal (code) section for Ms.
178−escapeCode :: String -> String
179−escapeCode = intercalate "\n" . map escapeLine . lines
180− where escapeCodeChar ' ' = "\\ "
181− escapeCodeChar '\t' = "\\\t"
182− escapeCodeChar c = escapeChar c
183− escapeLine codeline =
184− case concatMap escapeCodeChar codeline of
185− a@('.':_) -> "\\&" ++ a
186− b -> b
187−
188128-- We split inline lists into sentences, and print one sentence per
189129-- line. groff/troff treats the line-ending period differently.
190130-- See http://code.google.com/p/pandoc/issues/detail?id=148.
@@ -535,28 +475,6 @@ handleNote opts bs = do
535475 contents <- blockListToMs opts bs'
536476 return $ cr <> text ".FS" $$ contents $$ text ".FE" <> cr
537477
538−fontChange :: PandocMonad m => MS m Doc
539−fontChange = do
540− features <- gets stFontFeatures
541− inHeader <- gets stInHeader
542− let filling = ['C' | fromMaybe False $ Map.lookup 'C' features] ++
543− ['B' | inHeader ||
544− fromMaybe False (Map.lookup 'B' features)] ++
545− ['I' | fromMaybe False $ Map.lookup 'I' features]
546− return $
547− if null filling
548− then text "\\f[R]"
549− else text $ "\\f[" ++ filling ++ "]"
550−
551−withFontFeature :: PandocMonad m => Char -> MS m Doc -> MS m Doc
552−withFontFeature c action = do
553− modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
554− begin <- fontChange
555− d <- action
556− modify $ \st -> st{ stFontFeatures = Map.adjust not c $ stFontFeatures st }
557− end <- fontChange
558− return $ begin <> d <> end
559−
560478setFirstPara :: PandocMonad m => MS m ()
561479setFirstPara = modify $ \st -> st{ stFirstPara = True }
562480
src/Text/Pandoc/Writers/Shared.hs+1−10
@@ -47,7 +47,6 @@ module Text.Pandoc.Writers.Shared (
4747 , lookupMetaInlines
4848 , lookupMetaString
4949 , stripLeadingTrailingSpace
50− , groffEscape
5150 , toSubscript
5251 , toSuperscript
5352 )
@@ -56,7 +55,7 @@ import Prelude
5655import Control.Monad (zipWithM)
5756import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object),
5857 encode, fromJSON)
59−import Data.Char (chr, ord, isAscii, isSpace)
58+import Data.Char (chr, ord, isSpace)
6059import qualified Data.HashMap.Strict as H
6160import Data.List (groupBy, intersperse, transpose)
6261import qualified Data.Map as M
@@ -70,7 +69,6 @@ import Text.Pandoc.Pretty
7069import Text.Pandoc.Shared (stringify)
7170import Text.Pandoc.UTF8 (toStringLazy)
7271import Text.Pandoc.XML (escapeStringForXML)
73−import Text.Printf (printf)
7472
7573-- | Create JSON value for template from a 'Meta' and an association list
7674-- of variables, specified at the command line or in the writer.
@@ -387,13 +385,6 @@ lookupMetaString key meta =
387385 Just (MetaBool b) -> show b
388386 _ -> ""
389387
390−-- | Escape non-ASCII characters using groff \u[..] sequences.
391−groffEscape :: T.Text -> T.Text
392−groffEscape = T.concatMap toUchar
393− where toUchar c
394− | isAscii c = T.singleton c
395− | otherwise = T.pack $ printf "\\[u%04X]" (ord c)
396−
397388
398389toSuperscript :: Char -> Maybe Char
399390toSuperscript '1' = Just '\x00B9'
test/command/3568.md+1−1
@@ -10,7 +10,7 @@ normal `code` normal.
1010normal \f[I]italic \f[BI]bold in the middle\f[I] only italic\f[R]
1111normal.
1212.PP
13−normal \f[B]bold \f[BC]code\f[B] more bold\f[R] normal.
13+normal \f[B]bold \f[CB]code\f[B] more bold\f[R] normal.
1414.PP
1515normal \f[C]code\f[R] normal.
1616```
test/command/4550.md+1−1
@@ -3,5 +3,5 @@
33A ‘simple’ example
44^D
55.LP
6−A ‘simple’ example
6+A \[oq]simple\[cq] example
77```
test/tables.man+4−4
@@ -135,7 +135,7 @@ T}
135135.PP
136136Multiline table with caption:
137137.PP
138−Here's the caption. It may span multiple lines.
138+Here\[cq]s the caption. It may span multiple lines.
139139.TS
140140tab(@);
141141cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
@@ -165,7 +165,7 @@ row
165165T}@T{
1661665.0
167167T}@T{
168−Here's another one.
168+Here\[cq]s another one.
169169Note the blank line between rows.
170170T}
171171.TE
@@ -201,7 +201,7 @@ row
201201T}@T{
2022025.0
203203T}@T{
204−Here's another one.
204+Here\[cq]s another one.
205205Note the blank line between rows.
206206T}
207207.TE
@@ -261,7 +261,7 @@ row
261261T}@T{
2622625.0
263263T}@T{
264−Here's another one.
264+Here\[cq]s another one.
265265Note the blank line between rows.
266266T}
267267.TE
test/tables.ms+4−4
@@ -135,7 +135,7 @@ T}
135135.LP
136136Multiline table with caption:
137137.PP
138−Here’s the caption. It may span multiple lines.
138+Here\[cq]s the caption. It may span multiple lines.
139139.TS
140140delim(@@) tab( );
141141cw(10.5n) lw(9.6n) rw(11.4n) lw(24.5n).
@@ -165,7 +165,7 @@ row
165165T} T{
1661665.0
167167T} T{
168−Here’s another one.
168+Here\[cq]s another one.
169169Note the blank line between rows.
170170T}
171171.TE
@@ -201,7 +201,7 @@ row
201201T} T{
2022025.0
203203T} T{
204−Here’s another one.
204+Here\[cq]s another one.
205205Note the blank line between rows.
206206T}
207207.TE
@@ -261,7 +261,7 @@ row
261261T} T{
2622625.0
263263T} T{
264−Here’s another one.
264+Here\[cq]s another one.
265265Note the blank line between rows.
266266T}
267267.TE
test/writer.man+38−37
@@ -2,7 +2,7 @@
22.hy
33.PP
44This is a set of tests for pandoc.
5−Most of them are adapted from John Gruber's markdown test suite.
5+Most of them are adapted from John Gruber\[cq]s markdown test suite.
66.PP
77 * * * * *
88.SH Headers
@@ -22,15 +22,15 @@ with no blank line
2222 * * * * *
2323.SH Paragraphs
2424.PP
25−Here's a regular paragraph.
25+Here\[cq]s a regular paragraph.
2626.PP
2727In Markdown 1.0.0 and earlier.
2828Version 8.
2929This line turns into a list item.
30−Because a hard\-wrapped line in the middle of a paragraph looked like a list
30+Because a hard-wrapped line in the middle of a paragraph looked like a list
3131item.
3232.PP
33−Here's one with a bullet.
33+Here\[cq]s one with a bullet.
3434* criminey.
3535.PP
3636There should be a hard line break
@@ -42,7 +42,7 @@ here.
4242 * * * * *
4343.SH Block Quotes
4444.PP
45−E\-mail style:
45+E-mail style:
4646.RS
4747.PP
4848This is a block quote.
@@ -55,7 +55,7 @@ Code in a block quote:
5555.nf
5656\f[C]
5757sub\ status\ {
58−\ \ \ \ print\ "working";
58+\ \ \ \ print\ \[dq]working\[dq];
5959}
6060\f[R]
6161.fi
@@ -88,10 +88,10 @@ Code:
8888.IP
8989.nf
9090\f[C]
91−\-\-\-\-\ (should\ be\ four\ hyphens)
91+----\ (should\ be\ four\ hyphens)
9292
9393sub\ status\ {
94−\ \ \ \ print\ "working";
94+\ \ \ \ print\ \[dq]working\[dq];
9595}
9696
9797this\ code\ block\ is\ indented\ by\ one\ tab
@@ -200,7 +200,7 @@ Item 1, graf one.
200200.PP
201201Item 1.
202202graf two.
203−The quick brown fox jumped over the lazy dog's back.
203+The quick brown fox jumped over the lazy dog\[cq]s back.
204204.RE
205205.IP "2." 3
206206Item 2.
@@ -218,7 +218,7 @@ Tab
218218.RE
219219.RE
220220.PP
221−Here's another:
221+Here\[cq]s another:
222222.IP "1." 3
223223First
224224.IP "2." 3
@@ -308,7 +308,7 @@ Nested.
308308.PP
309309Should not be a list item:
310310.PP
311−M.A.\ 2007
311+M.A.\~2007
312312.PP
313313B.
314314Williams
@@ -459,7 +459,7 @@ Interpreted markdown in a table:
459459This is \f[I]emphasized\f[R]
460460And this is \f[B]strong\f[R]
461461.PP
462−Here's a simple block:
462+Here\[cq]s a simple block:
463463.PP
464464foo
465465.PP
@@ -492,7 +492,7 @@ Code block:
492492.IP
493493.nf
494494\f[C]
495−<!\-\-\ Comment\ \-\->
495+<!--\ Comment\ -->
496496\f[R]
497497.fi
498498.PP
@@ -506,7 +506,7 @@ Code:
506506\f[R]
507507.fi
508508.PP
509−Hr's:
509+Hr\[cq]s:
510510.PP
511511 * * * * *
512512.SH Inline Markup
@@ -530,12 +530,12 @@ This is code: \f[C]>\f[R], \f[C]$\f[R], \f[C]\\\f[R], \f[C]\\$\f[R],
530530.PP
531531[STRIKEOUT:This is \f[I]strikeout\f[R].]
532532.PP
533−Superscripts: a^bc^d a^\f[I]hello\f[R]^ a^hello\ there^.
533+Superscripts: a^bc^d a^\f[I]hello\f[R]^ a^hello\~there^.
534534.PP
535−Subscripts: H~2~O, H~23~O, H~many\ of\ them~O.
535+Subscripts: H~2~O, H~23~O, H~many\~of\~them~O.
536536.PP
537537These should not be superscripts or subscripts, because of the unescaped
538−spaces: a^b c^d, a~b c~d.
538+spaces: a\[ha]b c\[ha]d, a\[ti]b c\[ti]d.
539539.PP
540540 * * * * *
541541.SH Smart quotes, ellipses, dashes
@@ -548,7 +548,7 @@ spaces: a^b c^d, a~b c~d.
548548`Oak,' `elm,' and `beech' are names of trees.
549549So is `pine.'
550550.PP
551−`He said, \[lq]I want to go.\[rq]' Were you alive in the 70's?
551+`He said, \[lq]I want to go.\[rq]' Were you alive in the 70\[cq]s?
552552.PP
553553Here is some quoted `\f[C]code\f[R]' and a \[lq]quoted
554554link (http://example.com/?foo=1&bar=2)\[rq].
@@ -571,19 +571,19 @@ Ellipses\&...and\&...and\&....
571571.IP \[bu] 2
572572223
573573.IP \[bu] 2
574−\f[I]p\f[R]\-Tree
574+\f[I]p\f[R]-Tree
575575.IP \[bu] 2
576−Here's some display math:
576+Here\[cq]s some display math:
577577.RS
578−$$\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)\-f(x)}{h}$$
578+$$\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}$$
579579.RE
580580.IP \[bu] 2
581−Here's one that has a line break in it:
581+Here\[cq]s one that has a line break in it:
582582\f[I]α\f[R] + \f[I]ω\f[R] × \f[I]x\f[R]^2^.
583583.PP
584−These shouldn't be math:
584+These shouldn\[cq]t be math:
585585.IP \[bu] 2
586−To get the famous equation, write \f[C]$e\ =\ mc^2$\f[R].
586+To get the famous equation, write \f[C]$e\ =\ mc\[ha]2$\f[R].
587587.IP \[bu] 2
588588$22,000 is a \f[I]lot\f[R] of money.
589589So is $34,000.
@@ -593,7 +593,7 @@ Shoes ($20) and socks ($5).
593593.IP \[bu] 2
594594Escaped \f[C]$\f[R]: $73 \f[I]this should be emphasized\f[R] 23$.
595595.PP
596−Here's a LaTeX table:
596+Here\[cq]s a LaTeX table:
597597.PP
598598 * * * * *
599599.SH Special Characters
@@ -622,7 +622,7 @@ This & that.
622622.PP
623623Backslash: \\
624624.PP
625−Backtick: `
625+Backtick: \`
626626.PP
627627Asterisk: *
628628.PP
@@ -640,7 +640,7 @@ Left paren: (
640640.PP
641641Right paren: )
642642.PP
643−Greater\-than: >
643+Greater-than: >
644644.PP
645645Hash: #
646646.PP
@@ -650,7 +650,7 @@ Bang: !
650650.PP
651651Plus: +
652652.PP
653−Minus: \-
653+Minus: -
654654.PP
655655 * * * * *
656656.SH Links
@@ -700,13 +700,14 @@ Foo bar (/url/).
700700Foo biz (/url/).
701701.SS With ampersands
702702.PP
703−Here's a link with an ampersand in the URL (http://example.com/?foo=1&bar=2).
703+Here\[cq]s a link with an ampersand in the
704+URL (http://example.com/?foo=1&bar=2).
704705.PP
705−Here's a link with an amersand in the link text: AT&T (http://att.com/).
706+Here\[cq]s a link with an amersand in the link text: AT&T (http://att.com/).
706707.PP
707−Here's an inline link (/script?foo=1&bar=2).
708+Here\[cq]s an inline link (/script?foo=1&bar=2).
708709.PP
709−Here's an inline link in pointy braces (/script?foo=1&bar=2).
710+Here\[cq]s an inline link in pointy braces (/script?foo=1&bar=2).
710711.SS Autolinks
711712.PP
712713With an ampersand: <http://example.com/?foo=1&bar=2>
@@ -717,13 +718,13 @@ In a list?
717718.IP \[bu] 2
718719It should.
719720.PP
720−An e\-mail address: <nobody@nowhere.net>
721+An e-mail address: <nobody@nowhere.net>
721722.RS
722723.PP
723724Blockquoted: <http://example.com/>
724725.RE
725726.PP
726−Auto\-links should not occur here: \f[C]<http://example.com/>\f[R]
727+Auto-links should not occur here: \f[C]<http://example.com/>\f[R]
727728.IP
728729.nf
729730\f[C]
@@ -744,8 +745,8 @@ Here is a movie [IMAGE: movie (movie.jpg)] icon.
744745.SH Footnotes
745746.PP
746747Here is a footnote reference,[1] and another.[2] This should \f[I]not\f[R] be
747−a footnote reference, because it contains a space.[^my note] Here is an inline
748−note.[3]
748+a footnote reference, because it contains a space.[\[ha]my note] Here is an
749+inline note.[3]
749750.RS
750751.PP
751752Notes can go in quotes.[4]
@@ -762,7 +763,7 @@ It can go anywhere after the footnote reference.
762763It need not be placed at the end of the document.
763764.SS [2]
764765.PP
765−Here's the long note.
766+Here\[cq]s the long note.
766767This one contains multiple blocks.
767768.PP
768769Subsequent blocks are indented to show that they belong to the footnote (as
test/writer.ms+17−17
@@ -75,7 +75,7 @@ July 17, 2006
7575.1C
7676.LP
7777This is a set of tests for pandoc.
78−Most of them are adapted from John Gruber’s markdown test suite.
78+Most of them are adapted from John Gruber\[cq]s markdown test suite.
7979.HLINE
8080.SH 1
8181Headers
@@ -126,7 +126,7 @@ Paragraphs
126126.pdfhref O 1 "Paragraphs"
127127.pdfhref M "paragraphs"
128128.LP
129−Here’s a regular paragraph.
129+Here\[cq]s a regular paragraph.
130130.PP
131131In Markdown 1.0.0 and earlier.
132132Version 8.
@@ -134,7 +134,7 @@ This line turns into a list item.
134134Because a hard-wrapped line in the middle of a paragraph looked like a list
135135item.
136136.PP
137−Here’s one with a bullet.
137+Here\[cq]s one with a bullet.
138138* criminey.
139139.PP
140140There should be a hard line break
@@ -314,7 +314,7 @@ Item 1, graf one.
314314.PP
315315Item 1.
316316graf two.
317−The quick brown fox jumped over the lazy dog’s back.
317+The quick brown fox jumped over the lazy dog\[cq]s back.
318318.RE
319319.IP " 2." 4
320320Item 2.
@@ -335,7 +335,7 @@ Tab
335335.RE
336336.RE
337337.LP
338−Here’s another:
338+Here\[cq]s another:
339339.IP " 1." 4
340340First
341341.IP " 2." 4
@@ -570,7 +570,7 @@ Interpreted markdown in a table:
570570This is \f[I]emphasized\f[R]
571571And this is \f[B]strong\f[R]
572572.PP
573−Here’s a simple block:
573+Here\[cq]s a simple block:
574574.LP
575575foo
576576.LP
@@ -617,7 +617,7 @@ Code:
617617\f[]
618618.fi
619619.LP
620−Hr’s:
620+Hr\[cq]s:
621621.HLINE
622622.SH 1
623623Inline Markup
@@ -666,7 +666,7 @@ Smart quotes, ellipses, dashes
666666`Oak,' `elm,' and `beech' are names of trees.
667667So is `pine.'
668668.PP
669−`He said, \[lq]I want to go.\[rq]' Were you alive in the 70’s?
669+`He said, \[lq]I want to go.\[rq]' Were you alive in the 70\[cq]s?
670670.PP
671671Here is some quoted `\f[C]code\f[R]' and a \[lq]\c
672672.pdfhref W -D "http://example.com/?foo=1&bar=2" -A "\c" \
@@ -695,14 +695,14 @@ LaTeX
695695.IP \[bu] 3
696696@p@-Tree
697697.IP \[bu] 3
698−Here’s some display math:
698+Here\[cq]s some display math:
699699.EQ
700700d over {d x} f ( x ) = lim sub {h -> 0} {f ( x + h ) \[u2212] f ( x )} over h
701701.EN
702702.IP \[bu] 3
703−Here’s one that has a line break in it: @alpha + omega times x sup 2@.
703+Here\[cq]s one that has a line break in it: @alpha + omega times x sup 2@.
704704.LP
705−These shouldn’t be math:
705+These shouldn\[cq]t be math:
706706.IP \[bu] 3
707707To get the famous equation, write \f[C]$e\ =\ mc\[ha]2$\f[R].
708708.IP \[bu] 3
@@ -714,7 +714,7 @@ Shoes ($20) and socks ($5).
714714.IP \[bu] 3
715715Escaped \f[C]$\f[R]: $73 \f[I]this should be emphasized\f[R] 23$.
716716.LP
717−Here’s a LaTeX table:
717+Here\[cq]s a LaTeX table:
718718.HLINE
719719.SH 1
720720Special Characters
@@ -885,22 +885,22 @@ With ampersands
885885.pdfhref O 2 "With ampersands"
886886.pdfhref M "with-ampersands"
887887.LP
888−Here’s a \c
888+Here\[cq]s a \c
889889.pdfhref W -D "http://example.com/?foo=1&bar=2" -A "\c" \
890890 -- "link with an ampersand in the URL"
891891\&.
892892.PP
893−Here’s a link with an amersand in the link text: \c
893+Here\[cq]s a link with an amersand in the link text: \c
894894.pdfhref W -D "http://att.com/" -A "\c" \
895895 -- "AT&T"
896896\&.
897897.PP
898−Here’s an \c
898+Here\[cq]s an \c
899899.pdfhref W -D "/script?foo=1&bar=2" -A "\c" \
900900 -- "inline link"
901901\&.
902902.PP
903−Here’s an \c
903+Here\[cq]s an \c
904904.pdfhref W -D "/script?foo=1&bar=2" -A "\c" \
905905 -- "inline link in pointy braces"
906906\&.
@@ -967,7 +967,7 @@ It need not be placed at the end of the document.
967967.FE
968968and another.\**
969969.FS
970−Here’s the long note.
970+Here\[cq]s the long note.
971971This one contains multiple blocks.
972972.PP
973973Subsequent blocks are indented to show that they belong to the footnote (as