From 46d8b42da5d42b981bc56c49416cec15abaf2d09 Mon Sep 17 00:00:00 2001
From: John MacFarlane <jgm@berkeley.edu>
Date: Sun, 2 Oct 2016 21:51:34 +0200
Subject: [PATCH] AsciiDoc writer: avoid unnecessary use of "unconstrained"
 emphasis.

In AsciiDoc, you must use a special form of emphasis (double `__`)
for intraword emphasis.  Pandoc was previously using this more
than necessary.

Closes #3068.
---
 src/Text/Pandoc/Writers/AsciiDoc.hs | 24 +++++++++++++++++-------
 tests/writer.asciidoc               |  8 ++++----
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index 4ac6aa093..0dfbd705e 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -51,6 +51,7 @@ import Control.Monad.State
 import qualified Data.Map as M
 import Data.Aeson (Value(String), fromJSON, toJSON, Result(..))
 import qualified Data.Text as T
+import Data.Char (isSpace, isPunctuation)
 
 data WriterState = WriterState { defListMarker :: String
                                , orderedListLevel :: Int
@@ -321,6 +322,8 @@ blockListToAsciiDoc :: WriterOptions -- ^ Options
                     -> State WriterState Doc
 blockListToAsciiDoc opts blocks = cat `fmap` mapM (blockToAsciiDoc opts) blocks
 
+data SpacyLocation = End | Start
+
 -- | Convert list of Pandoc inline elements to asciidoc.
 inlineListToAsciiDoc :: WriterOptions -> [Inline] -> State WriterState Doc
 inlineListToAsciiDoc opts lst = do
@@ -331,14 +334,14 @@ inlineListToAsciiDoc opts lst = do
   return result
  where go [] = return empty
        go (y:x:xs)
-         | not (isSpacy y) = do
-           y' <- if isSpacy x
+         | not (isSpacy End y) = do
+           y' <- if isSpacy Start x
                     then inlineToAsciiDoc opts y
                     else withIntraword $ inlineToAsciiDoc opts y
            x' <- withIntraword $ inlineToAsciiDoc opts x
            xs' <- go xs
            return (y' <> x' <> xs')
-         | not (isSpacy x) = do
+         | not (isSpacy Start x) = do
            y' <- withIntraword $ inlineToAsciiDoc opts y
            xs' <- go (x:xs)
            return (y' <> xs')
@@ -346,10 +349,17 @@ inlineListToAsciiDoc opts lst = do
            x' <- inlineToAsciiDoc opts x
            xs' <- go xs
            return (x' <> xs')
-       isSpacy Space = True
-       isSpacy LineBreak = True
-       isSpacy SoftBreak = True
-       isSpacy _ = False
+       isSpacy :: SpacyLocation -> Inline -> Bool
+       isSpacy _ Space = True
+       isSpacy _ LineBreak = True
+       isSpacy _ SoftBreak = True
+       -- Note that \W characters count as spacy in AsciiDoc
+       -- for purposes of determining interword:
+       isSpacy End (Str xs) = case reverse xs of
+                                   c:_ -> isPunctuation c || isSpace c
+                                   _   -> False
+       isSpacy Start (Str (c:_)) = isPunctuation c || isSpace c
+       isSpacy _ _ = False
 
 setIntraword :: Bool -> State WriterState ()
 setIntraword b = modify $ \st -> st{ intraword = b }
diff --git a/tests/writer.asciidoc b/tests/writer.asciidoc
index 8d0973675..2bf62e36f 100644
--- a/tests/writer.asciidoc
+++ b/tests/writer.asciidoc
@@ -435,11 +435,11 @@ Hr’s:
 Inline Markup
 -------------
 
-This is __emphasized__, and so __is this__.
+This is _emphasized_, and so _is this_.
 
-This is **strong**, and so **is this**.
+This is *strong*, and so *is this*.
 
-An __link:/url[emphasized link]__.
+An _link:/url[emphasized link]_.
 
 *_This is strong and em._*
 
@@ -451,7 +451,7 @@ So is *_this_* word.
 
 This is code: `>`, `$`, `\`, `\$`, `<html>`.
 
-[line-through]*This is __strikeout__.*
+[line-through]*This is _strikeout_.*
 
 Superscripts: a^bc^d a^_hello_^ a^hello there^.