From 9c2b659eeb196145f62d8eae0072c279a7c2d751 Mon Sep 17 00:00:00 2001
From: Vaibhav Sagar <vaibhavsagar@gmail.com>
Date: Tue, 28 Apr 2020 22:53:06 +0800
Subject: Support new Underline element in readers and writers (#6277)

Deprecate `underlineSpan` in Shared in favor of `Text.Pandoc.Builder.underline`.
---
 src/Text/Pandoc/Lua/Marshaling/AST.hs              |  2 ++
 src/Text/Pandoc/Readers/Docx.hs                    |  2 +-
 src/Text/Pandoc/Readers/DokuWiki.hs                |  4 ++--
 src/Text/Pandoc/Readers/HTML.hs                    |  4 ++--
 src/Text/Pandoc/Readers/JATS.hs                    |  4 ++--
 src/Text/Pandoc/Readers/LaTeX.hs                   |  6 +++---
 src/Text/Pandoc/Readers/Markdown.hs                | 15 +++++++++++++--
 src/Text/Pandoc/Readers/Muse.hs                    |  6 +++---
 src/Text/Pandoc/Readers/Odt/ContentReader.hs       |  2 +-
 src/Text/Pandoc/Readers/Org/Inlines.hs             |  3 +--
 src/Text/Pandoc/Readers/Textile.hs                 |  4 ++--
 src/Text/Pandoc/Readers/Txt2Tags.hs                |  5 ++---
 src/Text/Pandoc/Shared.hs                          |  5 +++--
 src/Text/Pandoc/Writers/AsciiDoc.hs                |  3 +++
 src/Text/Pandoc/Writers/CommonMark.hs              |  5 +++++
 src/Text/Pandoc/Writers/ConTeXt.hs                 |  3 +++
 src/Text/Pandoc/Writers/Custom.hs                  |  2 ++
 src/Text/Pandoc/Writers/Docbook.hs                 |  2 ++
 src/Text/Pandoc/Writers/Docx.hs                    |  6 +++---
 src/Text/Pandoc/Writers/DokuWiki.hs                |  4 ++++
 src/Text/Pandoc/Writers/FB2.hs                     |  2 ++
 src/Text/Pandoc/Writers/HTML.hs                    |  1 +
 src/Text/Pandoc/Writers/Haddock.hs                 |  3 +++
 src/Text/Pandoc/Writers/ICML.hs                    |  3 +++
 src/Text/Pandoc/Writers/JATS.hs                    |  2 ++
 src/Text/Pandoc/Writers/Jira.hs                    |  1 +
 src/Text/Pandoc/Writers/LaTeX.hs                   |  1 +
 src/Text/Pandoc/Writers/Man.hs                     |  3 +++
 src/Text/Pandoc/Writers/Markdown.hs                | 15 +++++++++++++++
 src/Text/Pandoc/Writers/MediaWiki.hs               |  4 ++++
 src/Text/Pandoc/Writers/Ms.hs                      |  2 ++
 src/Text/Pandoc/Writers/Muse.hs                    |  7 +++++++
 src/Text/Pandoc/Writers/OpenDocument.hs            |  5 +++++
 src/Text/Pandoc/Writers/Org.hs                     |  3 +++
 src/Text/Pandoc/Writers/Powerpoint/Presentation.hs |  3 +++
 src/Text/Pandoc/Writers/RST.hs                     |  7 +++++++
 src/Text/Pandoc/Writers/RTF.hs                     |  3 +++
 src/Text/Pandoc/Writers/TEI.hs                     |  2 ++
 src/Text/Pandoc/Writers/Texinfo.hs                 |  4 ++++
 src/Text/Pandoc/Writers/Textile.hs                 |  6 ++++++
 src/Text/Pandoc/Writers/XWiki.hs                   |  4 ++++
 src/Text/Pandoc/Writers/ZimWiki.hs                 |  4 ++++
 42 files changed, 144 insertions(+), 28 deletions(-)

(limited to 'src')

diff --git a/src/Text/Pandoc/Lua/Marshaling/AST.hs b/src/Text/Pandoc/Lua/Marshaling/AST.hs
index 8d7e83dc1..359ed6c30 100644
--- a/src/Text/Pandoc/Lua/Marshaling/AST.hs
+++ b/src/Text/Pandoc/Lua/Marshaling/AST.hs
@@ -303,6 +303,7 @@ pushInline = \case
   Cite citations lst       -> pushViaConstructor "Cite" lst citations
   Code attr lst            -> pushViaConstructor "Code" lst (LuaAttr attr)
   Emph inlns               -> pushViaConstructor "Emph" inlns
+  Underline inlns          -> pushViaConstructor "Underline" inlns
   Image attr alt (src,tit) -> pushViaConstructor "Image" alt src tit (LuaAttr attr)
   LineBreak                -> pushViaConstructor "LineBreak"
   Link attr lst (src,tit)  -> pushViaConstructor "Link" lst src tit (LuaAttr attr)
@@ -328,6 +329,7 @@ peekInline idx = defineHowTo "get Inline value" $ do
     "Cite"       -> uncurry Cite <$> elementContent
     "Code"       -> withAttr Code <$> elementContent
     "Emph"       -> Emph <$> elementContent
+    "Underline"  -> Underline <$> elementContent
     "Image"      -> (\(LuaAttr attr, lst, tgt) -> Image attr lst tgt)
                     <$> elementContent
     "Link"       -> (\(LuaAttr attr, lst, tgt) -> Link attr lst tgt)
diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs
index bb86c91b0..ddec0bdf8 100644
--- a/src/Text/Pandoc/Readers/Docx.hs
+++ b/src/Text/Pandoc/Readers/Docx.hs
@@ -299,7 +299,7 @@ runStyleToTransform rPr
       return $ subscript . transform
   | Just "single" <- rUnderline rPr = do
       transform <- runStyleToTransform rPr{rUnderline = Nothing}
-      return $ underlineSpan . transform
+      return $ Pandoc.underline . transform
   | otherwise = return id
 
 runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
diff --git a/src/Text/Pandoc/Readers/DokuWiki.hs b/src/Text/Pandoc/Readers/DokuWiki.hs
index 8b48789b3..722701ee2 100644
--- a/src/Text/Pandoc/Readers/DokuWiki.hs
+++ b/src/Text/Pandoc/Readers/DokuWiki.hs
@@ -29,7 +29,7 @@ import Text.Pandoc.Definition
 import Text.Pandoc.Error (PandocError (PandocParsecError))
 import Text.Pandoc.Options
 import Text.Pandoc.Parsing hiding (enclosed, nested)
-import Text.Pandoc.Shared (crFilter, trim, underlineSpan, stringify, tshow)
+import Text.Pandoc.Shared (crFilter, trim, stringify, tshow)
 
 -- | Read DokuWiki from an input string and return a Pandoc document.
 readDokuWiki :: PandocMonad m
@@ -162,7 +162,7 @@ italic :: PandocMonad m => DWParser m B.Inlines
 italic = try $ B.emph <$> enclosed (string "//") nestedInlines
 
 underlined :: PandocMonad m => DWParser m B.Inlines
-underlined = try $ underlineSpan <$> enclosed (string "__") nestedInlines
+underlined = try $ B.underline <$> enclosed (string "__") nestedInlines
 
 nowiki :: PandocMonad m => DWParser m B.Inlines
 nowiki = try $ B.text <$ string "<nowiki>" <*> manyTillChar anyChar (try $ string "</nowiki>")
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
index 1ab35bf7a..a643ed41f 100644
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -61,7 +61,7 @@ import Text.Pandoc.Options (
 import Text.Pandoc.Parsing hiding ((<|>))
 import Text.Pandoc.Shared (addMetaField, blocksToInlines', crFilter, escapeURI,
                            extractSpaces, htmlSpanLikeElements, elemText, splitTextBy,
-                           onlySimpleTableCells, safeRead, underlineSpan, tshow)
+                           onlySimpleTableCells, safeRead, tshow)
 import Text.Pandoc.Walk
 import Text.Parsec.Error
 import Text.TeXMath (readMathML, writeTeX)
@@ -749,7 +749,7 @@ pStrikeout =
             return $ B.strikeout contents)
 
 pUnderline :: PandocMonad m => TagParser m Inlines
-pUnderline = pInlinesInTags "u" underlineSpan <|> pInlinesInTags "ins" underlineSpan
+pUnderline = pInlinesInTags "u" B.underline <|> pInlinesInTags "ins" B.underline
 
 pLineBreak :: PandocMonad m => TagParser m Inlines
 pLineBreak = do
diff --git a/src/Text/Pandoc/Readers/JATS.hs b/src/Text/Pandoc/Readers/JATS.hs
index f78630ec0..d7f87f695 100644
--- a/src/Text/Pandoc/Readers/JATS.hs
+++ b/src/Text/Pandoc/Readers/JATS.hs
@@ -26,7 +26,7 @@ import Text.HTML.TagSoup.Entity (lookupEntity)
 import Text.Pandoc.Builder
 import Text.Pandoc.Class.PandocMonad (PandocMonad)
 import Text.Pandoc.Options
-import Text.Pandoc.Shared (underlineSpan, crFilter, safeRead)
+import Text.Pandoc.Shared (crFilter, safeRead)
 import Text.TeXMath (readMathML, writeTeX)
 import Text.XML.Light
 import qualified Data.Set as S (fromList, member)
@@ -456,7 +456,7 @@ parseInline (Elem e) =
         "strike" -> strikeout <$> innerInlines
         "sub" -> subscript <$> innerInlines
         "sup" -> superscript <$> innerInlines
-        "underline" -> underlineSpan <$> innerInlines
+        "underline" -> underline <$> innerInlines
         "break" -> return linebreak
         "sc" -> smallcaps <$> innerInlines
 
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index b6bc039df..245c4957f 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -909,7 +909,7 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
   , ("slash", lit "/")
   , ("textbf", extractSpaces strong <$> tok)
   , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
-  , ("underline", underlineSpan <$> tok)
+  , ("underline", underline <$> tok)
   , ("ldots", lit "…")
   , ("vdots", lit "\8942")
   , ("dots", lit "…")
@@ -1171,9 +1171,9 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
   -- include
   , ("input", rawInlineOr "input" $ include "input")
   -- soul package
-  , ("ul", underlineSpan <$> tok)
+  , ("ul", underline <$> tok)
   -- ulem package
-  , ("uline", underlineSpan <$> tok)
+  , ("uline", underline <$> tok)
   -- plain tex stuff that should just be passed through as raw tex
   , ("ifdim", ifdim)
   ]
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 72a0975fd..3b363263d 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -1751,7 +1751,9 @@ bracketedSpan = try $ do
   attr <- attributes
   return $ if isSmallCaps attr
               then B.smallcaps <$> lab
-              else B.spanWith attr <$> lab
+              else if isUnderline attr
+                      then B.underline <$> lab
+                      else B.spanWith attr <$> lab
 
 -- | We treat a span as SmallCaps if class is "smallcaps" (and
 -- no other attributes are set or if style is "font-variant:small-caps"
@@ -1765,6 +1767,13 @@ isSmallCaps ("",[],kvs) =
        Nothing -> False
 isSmallCaps _ = False
 
+-- | We treat a span as Underline if class is "ul" or
+-- "underline" (and no other attributes are set).
+isUnderline :: Attr -> Bool
+isUnderline ("",["ul"],[]) = True
+isUnderline ("",["underline"],[]) = True
+isUnderline _ = False
+
 regLink :: PandocMonad m
         => (Attr -> Text -> Text -> Inlines -> Inlines)
         -> F Inlines
@@ -1913,7 +1922,9 @@ spanHtml = try $ do
   let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
   return $ if isSmallCaps (ident, classes, keyvals)
               then B.smallcaps <$> contents
-              else B.spanWith (ident, classes, keyvals) <$> contents
+              else if isUnderline (ident, classes, keyvals)
+                      then B.underline <$> contents
+                      else B.spanWith (ident, classes, keyvals) <$> contents
 
 divHtml :: PandocMonad m => MarkdownParser m (F Blocks)
 divHtml = try $ do
diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs
index 987028910..751a37808 100644
--- a/src/Text/Pandoc/Readers/Muse.hs
+++ b/src/Text/Pandoc/Readers/Muse.hs
@@ -29,7 +29,7 @@ import qualified Data.Set as Set
 import Data.Maybe (fromMaybe, isNothing, maybeToList)
 import Data.Text (Text)
 import qualified Data.Text as T
-import Text.Pandoc.Builder (Blocks, Inlines)
+import Text.Pandoc.Builder (Blocks, Inlines, underline)
 import qualified Text.Pandoc.Builder as B
 import Text.Pandoc.Class.PandocMonad (PandocMonad (..))
 import Text.Pandoc.Definition
@@ -37,7 +37,7 @@ import Text.Pandoc.Error (PandocError (PandocParsecError))
 import Text.Pandoc.Logging
 import Text.Pandoc.Options
 import Text.Pandoc.Parsing hiding (F)
-import Text.Pandoc.Shared (crFilter, trimr, underlineSpan, tshow)
+import Text.Pandoc.Shared (crFilter, trimr, tshow)
 
 -- | Read Muse from an input string and return a Pandoc document.
 readMuse :: PandocMonad m
@@ -849,7 +849,7 @@ emph = fmap B.emph <$> emphasisBetween (char '*' <* notFollowedBy (char '*'))
 -- | Parse underline inline markup, indicated by @_@.
 -- Supported only in Emacs Muse mode, not Text::Amuse.
 underlined :: PandocMonad m => MuseParser m (F Inlines)
-underlined = fmap underlineSpan
+underlined = fmap underline
   <$  guardDisabled Ext_amuse -- Supported only by Emacs Muse
   <*> emphasisBetween (char '_')
 
diff --git a/src/Text/Pandoc/Readers/Odt/ContentReader.hs b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
index cbf7236d0..74120f96a 100644
--- a/src/Text/Pandoc/Readers/Odt/ContentReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
@@ -37,7 +37,7 @@ import Data.Semigroup (First(..), Option(..))
 import Text.TeXMath (readMathML, writeTeX)
 import qualified Text.XML.Light as XML
 
-import Text.Pandoc.Builder
+import Text.Pandoc.Builder hiding (underline)
 import Text.Pandoc.MediaBag (MediaBag, insertMedia)
 import Text.Pandoc.Shared
 import Text.Pandoc.Extensions (extensionsFromList, Extension(..))
diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs
index 9ac74f192..1055cd0db 100644
--- a/src/Text/Pandoc/Readers/Org/Inlines.hs
+++ b/src/Text/Pandoc/Readers/Org/Inlines.hs
@@ -27,7 +27,6 @@ import Text.Pandoc.Class.PandocMonad (PandocMonad)
 import Text.Pandoc.Definition
 import Text.Pandoc.Options
 import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
-import Text.Pandoc.Shared (underlineSpan)
 import Text.TeXMath (DisplayType (..), readTeX, writePandoc)
 import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
 
@@ -567,7 +566,7 @@ strikeout :: PandocMonad m => OrgParser m (F Inlines)
 strikeout = fmap B.strikeout    <$> emphasisBetween '+'
 
 underline :: PandocMonad m => OrgParser m (F Inlines)
-underline = fmap underlineSpan  <$> emphasisBetween '_'
+underline = fmap B.underline    <$> emphasisBetween '_'
 
 verbatim  :: PandocMonad m => OrgParser m (F Inlines)
 verbatim  = return . B.code     <$> verbatimBetween '='
diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs
index fef192fd3..598420a0d 100644
--- a/src/Text/Pandoc/Readers/Textile.hs
+++ b/src/Text/Pandoc/Readers/Textile.hs
@@ -52,7 +52,7 @@ import Text.Pandoc.Options
 import Text.Pandoc.Parsing
 import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isInlineTag)
 import Text.Pandoc.Readers.LaTeX (rawLaTeXBlock, rawLaTeXInline)
-import Text.Pandoc.Shared (crFilter, trim, underlineSpan, tshow)
+import Text.Pandoc.Shared (crFilter, trim, tshow)
 
 -- | Parse a Textile text and return a Pandoc document.
 readTextile :: PandocMonad m
@@ -451,7 +451,7 @@ inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
                       , simpleInline (string "__") B.emph
                       , simpleInline (char '*') B.strong
                       , simpleInline (char '_') B.emph
-                      , simpleInline (char '+') underlineSpan
+                      , simpleInline (char '+') B.underline
                       , simpleInline (char '-' <* notFollowedBy (char '-')) B.strikeout
                       , simpleInline (char '^') B.superscript
                       , simpleInline (char '~') B.subscript
diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs
index c5c87e471..245df6f08 100644
--- a/src/Text/Pandoc/Readers/Txt2Tags.hs
+++ b/src/Text/Pandoc/Readers/Txt2Tags.hs
@@ -31,8 +31,7 @@ import Data.Time (defaultTimeLocale)
 import Text.Pandoc.Definition
 import Text.Pandoc.Options
 import Text.Pandoc.Parsing hiding (space, spaces, uri)
-import Text.Pandoc.Shared (compactify, compactifyDL, crFilter, escapeURI,
-                           underlineSpan)
+import Text.Pandoc.Shared (compactify, compactifyDL, crFilter, escapeURI)
 
 type T2T = ParserT Text ParserState (Reader T2TMeta)
 
@@ -378,7 +377,7 @@ bold :: T2T Inlines
 bold = inlineMarkup inline B.strong '*' B.str
 
 underline :: T2T Inlines
-underline = inlineMarkup inline underlineSpan '_' B.str
+underline = inlineMarkup inline B.underline '_' B.str
 
 strike :: T2T Inlines
 strike = inlineMarkup inline B.strikeout '-' B.str
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
index 1593106de..dc1adb42b 100644
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -750,11 +750,12 @@ eastAsianLineBreakFilter = bottomUp go
         go xs
           = xs
 
--- | Builder for underline.
+{-# DEPRECATED underlineSpan "Use Text.Pandoc.Builder.underline instead" #-}
+-- | Builder for underline (deprecated).
 -- This probably belongs in Builder.hs in pandoc-types.
 -- Will be replaced once Underline is an element.
 underlineSpan :: Inlines -> Inlines
-underlineSpan = B.spanWith ("", ["underline"], [])
+underlineSpan = B.underline
 
 -- | Set of HTML elements that are represented as Span with a class equal as
 -- the element tag itself.
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index 41f60f92e..94bbfb915 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -433,6 +433,9 @@ inlineToAsciiDoc opts (Emph lst) = do
   isIntraword <- gets intraword
   let marker = if isIntraword then "__" else "_"
   return $ marker <> contents <> marker
+inlineToAsciiDoc opts (Underline lst) = do
+  contents <- inlineListToAsciiDoc opts lst
+  return $ "+++" <> contents <> "+++"
 inlineToAsciiDoc opts (Strong lst) = do
   contents <- inlineListToAsciiDoc opts lst
   isIntraword <- gets intraword
diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs
index bab74c77c..ca6a4e334 100644
--- a/src/Text/Pandoc/Writers/CommonMark.hs
+++ b/src/Text/Pandoc/Writers/CommonMark.hs
@@ -237,6 +237,11 @@ inlineToNodes opts SoftBreak
   | writerWrapText opts == WrapNone     = (node (TEXT " ") [] :)
   | otherwise                           = (node SOFTBREAK [] :)
 inlineToNodes opts (Emph xs) = (node EMPH (inlinesToNodes opts xs) :)
+inlineToNodes opts (Underline xs)
+  | isEnabled Ext_raw_html opts =
+    ((node (HTML_INLINE (T.pack "<u>")) [] : inlinesToNodes opts xs ++
+      [node (HTML_INLINE (T.pack "</u>")) []]) ++ )
+  | otherwise = (node EMPH (inlinesToNodes opts xs) :)
 inlineToNodes opts (Strong xs) = (node STRONG (inlinesToNodes opts xs) :)
 inlineToNodes opts (Strikeout xs)
   | isEnabled Ext_strikeout opts = (node (CUSTOM_INLINE "~~" "~~") (inlinesToNodes opts xs) :)
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
index 6066f9bb2..7bae37a79 100644
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -368,6 +368,9 @@ inlineToConTeXt :: PandocMonad m
 inlineToConTeXt (Emph lst) = do
   contents <- inlineListToConTeXt lst
   return $ braces $ "\\em " <> contents
+inlineToConTeXt (Underline lst) = do
+  contents <- inlineListToConTeXt lst
+  return $ "\\underbar" <> braces contents
 inlineToConTeXt (Strong lst) = do
   contents <- inlineListToConTeXt lst
   return $ braces $ "\\bf " <> contents
diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs
index 50a013dfd..8da611b61 100644
--- a/src/Text/Pandoc/Writers/Custom.hs
+++ b/src/Text/Pandoc/Writers/Custom.hs
@@ -186,6 +186,8 @@ inlineToCustom SoftBreak = Lua.callFunc "SoftBreak"
 
 inlineToCustom (Emph lst) = Lua.callFunc "Emph" (Stringify lst)
 
+inlineToCustom (Underline lst) = Lua.callFunc "Underline" (Stringify lst)
+
 inlineToCustom (Strong lst) = Lua.callFunc "Strong" (Stringify lst)
 
 inlineToCustom (Strikeout lst) = Lua.callFunc "Strikeout" (Stringify lst)
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
index 2f033b19e..d3517159f 100644
--- a/src/Text/Pandoc/Writers/Docbook.hs
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -323,6 +323,8 @@ inlineToDocbook :: PandocMonad m => WriterOptions -> Inline -> DB m (Doc Text)
 inlineToDocbook _ (Str str) = return $ literal $ escapeStringForXML str
 inlineToDocbook opts (Emph lst) =
   inTagsSimple "emphasis" <$> inlinesToDocbook opts lst
+inlineToDocbook opts (Underline lst) =
+  inTags False "emphasis" [("role", "underline")] <$> inlinesToDocbook opts lst
 inlineToDocbook opts (Strong lst) =
   inTags False "emphasis" [("role", "strong")] <$> inlinesToDocbook opts lst
 inlineToDocbook opts (Strikeout lst) =
diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
index 2caba59cc..c43f6f70f 100644
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -1158,9 +1158,6 @@ inlineToOpenXML' _ (Str str) =
   formattedString str
 inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ")
 inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ")
-inlineToOpenXML' opts (Span (_,["underline"],_) ils) =
-  withTextProp (mknode "w:u" [("w:val","single")] ()) $
-    inlinesToOpenXML opts ils
 inlineToOpenXML' _ (Span (ident,["comment-start"],kvs) ils) = do
   -- prefer the "id" in kvs, since that is the one produced by the docx
   -- reader.
@@ -1234,6 +1231,9 @@ inlineToOpenXML' opts (Strong lst) =
   withTextProp (mknode "w:b" [] ()) $ inlinesToOpenXML opts lst
 inlineToOpenXML' opts (Emph lst) =
   withTextProp (mknode "w:i" [] ()) $ inlinesToOpenXML opts lst
+inlineToOpenXML' opts (Underline lst) =
+  withTextProp (mknode "w:u" [("w:val","single")] ()) $
+    inlinesToOpenXML opts lst
 inlineToOpenXML' opts (Subscript lst) =
   withTextProp (mknode "w:vertAlign" [("w:val","subscript")] ())
   $ inlinesToOpenXML opts lst
diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs
index b01d9a7bb..364c4956e 100644
--- a/src/Text/Pandoc/Writers/DokuWiki.hs
+++ b/src/Text/Pandoc/Writers/DokuWiki.hs
@@ -402,6 +402,10 @@ inlineToDokuWiki opts (Emph lst) = do
   contents <- inlineListToDokuWiki opts lst
   return $ "//" <> contents <> "//"
 
+inlineToDokuWiki opts (Underline lst) = do
+  contents <- inlineListToDokuWiki opts lst
+  return $ "__" <> contents <> "__"
+
 inlineToDokuWiki opts (Strong lst) = do
   contents <- inlineListToDokuWiki opts lst
   return $ "**" <> contents <> "**"
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
index 5e6f1861e..746e56436 100644
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -406,6 +406,7 @@ toXml :: PandocMonad m => Inline -> FBM m [Content]
 toXml (Str s) = return [txt s]
 toXml (Span _ ils) = cMapM toXml ils
 toXml (Emph ss) = list `liftM` wrap "emphasis" ss
+toXml (Underline ss) = list `liftM` wrap "underline" ss
 toXml (Strong ss) = list `liftM` wrap "strong" ss
 toXml (Strikeout ss) = list `liftM` wrap "strikethrough" ss
 toXml (Superscript ss) = list `liftM` wrap "sup" ss
@@ -529,6 +530,7 @@ list = (:[])
 plain :: Inline -> String
 plain (Str s)               = T.unpack s
 plain (Emph ss)             = cMap plain ss
+plain (Underline ss)        = cMap plain ss
 plain (Span _ ss)           = cMap plain ss
 plain (Strong ss)           = cMap plain ss
 plain (Strikeout ss)        = cMap plain ss
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
index 4d718bfa7..1f0ee5410 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -1049,6 +1049,7 @@ inlineToHtml opts inline = do
                                          ]
 
     (Emph lst)       -> H.em <$> inlineListToHtml opts lst
+    (Underline lst)  -> H.u <$> inlineListToHtml opts lst
     (Strong lst)     -> H.strong <$> inlineListToHtml opts lst
     (Code attr@(ids,cs,kvs) str)
                      -> case hlCode of
diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs
index 687c76b17..9d8c5ec41 100644
--- a/src/Text/Pandoc/Writers/Haddock.hs
+++ b/src/Text/Pandoc/Writers/Haddock.hs
@@ -209,6 +209,9 @@ inlineToHaddock opts (Span (ident,_,_) ils) = do
 inlineToHaddock opts (Emph lst) = do
   contents <- inlineListToHaddock opts lst
   return $ "/" <> contents <> "/"
+-- Underline is not supported, treat the same as Emph
+inlineToHaddock opts (Underline lst) =
+  inlineToHaddock opts (Emph lst)
 inlineToHaddock opts (Strong lst) = do
   contents <- inlineListToHaddock opts lst
   return $ "__" <> contents <> "__"
diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs
index 57066d303..45970ad94 100644
--- a/src/Text/Pandoc/Writers/ICML.hs
+++ b/src/Text/Pandoc/Writers/ICML.hs
@@ -60,6 +60,7 @@ defaultWriterState = WriterState{
 
 -- inline names (appear in InDesign's character styles pane)
 emphName        :: Text
+underlineName   :: Text
 strongName      :: Text
 strikeoutName   :: Text
 superscriptName :: Text
@@ -68,6 +69,7 @@ smallCapsName   :: Text
 codeName        :: Text
 linkName        :: Text
 emphName        = "Italic"
+underlineName   = "Underline"
 strongName      = "Bold"
 strikeoutName   = "Strikeout"
 superscriptName = "Superscript"
@@ -427,6 +429,7 @@ inlinesToICML opts style lst = vcat `fmap` mapM (inlineToICML opts style) (merge
 inlineToICML :: PandocMonad m => WriterOptions -> Style -> Inline -> WS m (Doc Text)
 inlineToICML _    style (Str str) = charStyle style $ literal $ escapeStringForXML str
 inlineToICML opts style (Emph lst) = inlinesToICML opts (emphName:style) lst
+inlineToICML opts style (Underline lst) = inlinesToICML opts (underlineName:style) lst
 inlineToICML opts style (Strong lst) = inlinesToICML opts (strongName:style) lst
 inlineToICML opts style (Strikeout lst) = inlinesToICML opts (strikeoutName:style) lst
 inlineToICML opts style (Superscript lst) = inlinesToICML opts (superscriptName:style) lst
diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs
index 47d8c00cf..50ce04e03 100644
--- a/src/Text/Pandoc/Writers/JATS.hs
+++ b/src/Text/Pandoc/Writers/JATS.hs
@@ -424,6 +424,8 @@ inlineToJATS :: PandocMonad m => WriterOptions -> Inline -> JATS m (Doc Text)
 inlineToJATS _ (Str str) = return $ text $ T.unpack $ escapeStringForXML str
 inlineToJATS opts (Emph lst) =
   inTagsSimple "italic" <$> inlinesToJATS opts lst
+inlineToJATS opts (Underline lst) =
+  inTagsSimple "underline" <$> inlinesToJATS opts lst
 inlineToJATS opts (Strong lst) =
   inTagsSimple "bold" <$> inlinesToJATS opts lst
 inlineToJATS opts (Strikeout lst) =
diff --git a/src/Text/Pandoc/Writers/Jira.hs b/src/Text/Pandoc/Writers/Jira.hs
index 1bf14c6a0..29f260b5c 100644
--- a/src/Text/Pandoc/Writers/Jira.hs
+++ b/src/Text/Pandoc/Writers/Jira.hs
@@ -193,6 +193,7 @@ toJiraInlines inlines = do
         Code _ cs          -> return . singleton $
                               Jira.Monospaced (escapeSpecialChars cs)
         Emph xs            -> styled Jira.Emphasis xs
+        Underline xs       -> styled Jira.Insert xs
         Image attr _ tgt   -> imageToJira attr (fst tgt) (snd tgt)
         LineBreak          -> pure . singleton $ Jira.Linebreak
         Link attr xs tgt   -> toJiraLink attr tgt xs
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index c3a2762d2..6ac79f00e 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -1140,6 +1140,7 @@ inlineToLaTeX (Span (id',classes,kvs) ils) = do
                then braces contents
                else foldr inCmd contents cmds)
 inlineToLaTeX (Emph lst) = inCmd "emph" <$> inlineListToLaTeX lst
+inlineToLaTeX (Underline lst) = inCmd "underline" <$> inlineListToLaTeX lst
 inlineToLaTeX (Strong lst) = inCmd "textbf" <$> inlineListToLaTeX lst
 inlineToLaTeX (Strikeout lst) = do
   -- we need to protect VERB in an mbox or we get an error
diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs
index 105906138..62449431c 100644
--- a/src/Text/Pandoc/Writers/Man.hs
+++ b/src/Text/Pandoc/Writers/Man.hs
@@ -270,6 +270,9 @@ inlineToMan :: PandocMonad m => WriterOptions -> Inline -> StateT WriterState m
 inlineToMan opts (Span _ ils) = inlineListToMan opts ils
 inlineToMan opts (Emph lst) =
   withFontFeature 'I' (inlineListToMan opts lst)
+-- Underline is not supported, so treat the same as Emph
+inlineToMan opts (Underline lst) =
+  withFontFeature 'I' (inlineListToMan opts lst)
 inlineToMan opts (Strong lst) =
   withFontFeature 'B' (inlineListToMan opts lst)
 inlineToMan opts (Strikeout lst) = do
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
index fb9888b24..c6a9d9d80 100644
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -1045,6 +1045,21 @@ inlineToMarkdown opts (Emph lst) = do
                       then "_" <> contents <> "_"
                       else contents
               else "*" <> contents <> "*"
+inlineToMarkdown _ (Underline []) = return empty
+inlineToMarkdown opts (Underline lst) = do
+  plain <- asks envPlain
+  contents <- inlineListToMarkdown opts lst
+  case plain of
+    True -> return contents
+    False | isEnabled Ext_bracketed_spans opts ->
+            return $ "[" <> contents <> "]" <> "{.ul}"
+          | isEnabled Ext_native_spans opts ->
+            return $ tagWithAttrs "span" ("", ["underline"], [])
+              <> contents
+              <> literal "</span>"
+          | isEnabled Ext_raw_html opts ->
+            return $ "<u>" <> contents <> "</u>"
+          | otherwise -> inlineToMarkdown opts (Emph lst)
 inlineToMarkdown _ (Strong []) = return empty
 inlineToMarkdown opts (Strong lst) = do
   plain <- asks envPlain
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
index 8d1745e8e..513693389 100644
--- a/src/Text/Pandoc/Writers/MediaWiki.hs
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -372,6 +372,10 @@ inlineToMediaWiki (Emph lst) = do
   contents <- inlineListToMediaWiki lst
   return $ "''" <> contents <> "''"
 
+inlineToMediaWiki (Underline lst) = do
+  contents <- inlineListToMediaWiki lst
+  return $ "<u>" <> contents <> "</u>"
+
 inlineToMediaWiki (Strong lst) = do
   contents <- inlineListToMediaWiki lst
   return $ "'''" <> contents <> "'''"
diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs
index 6c9d8a783..81de40045 100644
--- a/src/Text/Pandoc/Writers/Ms.hs
+++ b/src/Text/Pandoc/Writers/Ms.hs
@@ -351,6 +351,8 @@ inlineToMs :: PandocMonad m => WriterOptions -> Inline -> MS m (Doc Text)
 inlineToMs opts (Span _ ils) = inlineListToMs opts ils
 inlineToMs opts (Emph lst) =
   withFontFeature 'I' (inlineListToMs opts lst)
+inlineToMs opts (Underline lst) =
+  inlineToMs opts (Emph lst)
 inlineToMs opts (Strong lst) =
   withFontFeature 'B' (inlineListToMs opts lst)
 inlineToMs opts (Strikeout lst) = do
diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs
index 88b4c2ef9..bf3265107 100644
--- a/src/Text/Pandoc/Writers/Muse.hs
+++ b/src/Text/Pandoc/Writers/Muse.hs
@@ -594,6 +594,13 @@ inlineToMuse (Strong [Emph lst]) = do
     else if null lst' || startsWithSpace lst' || endsWithSpace lst'
            then emphasis "**<em>" "</em>**" lst'
            else emphasis "***" "***" lst'
+-- | Underline is only supported in Emacs Muse mode.
+inlineToMuse (Underline lst) = do
+  opts <- asks envOptions
+  contents <- inlineListToMuse lst
+  if isEnabled Ext_amuse opts
+     then return $ "_" <> contents <> "_"
+     else inlineToMuse (Emph lst)
 inlineToMuse (Strong lst) = do
   useTags <- gets stUseTags
   let lst' = normalizeInlineList lst
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
index 9c802118a..b868e168b 100644
--- a/src/Text/Pandoc/Writers/OpenDocument.hs
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -512,6 +512,7 @@ inlineToOpenDocument o ils
     LineBreak     -> return $ selfClosingTag "text:line-break" []
     Str         s -> return $ handleSpaces $ escapeStringForXML s
     Emph        l -> withTextStyle Italic $ inlinesToOpenDocument o l
+    Underline   l -> withTextStyle Under  $ inlinesToOpenDocument o l
     Strong      l -> withTextStyle Bold   $ inlinesToOpenDocument o l
     Strikeout   l -> withTextStyle Strike $ inlinesToOpenDocument o l
     Superscript l -> withTextStyle Sup    $ inlinesToOpenDocument o l
@@ -692,6 +693,7 @@ paraTableStyles t s (a:xs)
 
 data TextStyle = Italic
                | Bold
+               | Under
                | Strike
                | Sub
                | Sup
@@ -710,6 +712,9 @@ textStyleAttr m s
     | Bold   <- s = Map.insert "fo:font-weight" "bold" .
                     Map.insert "style:font-weight-asian" "bold" .
                     Map.insert "style:font-weight-complex" "bold" $ m
+    | Under  <- s = Map.insert "style:text-underline-style" "solid" .
+                    Map.insert "style:text-underline-width" "auto" .
+                    Map.insert "style:text-underline-color" "font-color" $ m
     | Strike <- s = Map.insert "style:text-line-through-style" "solid" m
     | Sub    <- s = Map.insert "style:text-position" "sub 58%" m
     | Sup    <- s = Map.insert "style:text-position" "super 58%" m
diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs
index 8e7f4dbf1..e7b940c57 100644
--- a/src/Text/Pandoc/Writers/Org.hs
+++ b/src/Text/Pandoc/Writers/Org.hs
@@ -329,6 +329,9 @@ inlineToOrg (Span _ lst) =
 inlineToOrg (Emph lst) = do
   contents <- inlineListToOrg lst
   return $ "/" <> contents <> "/"
+inlineToOrg (Underline lst) = do
+  contents <- inlineListToOrg lst
+  return $ "_" <> contents <> "_"
 inlineToOrg (Strong lst) = do
   contents <- inlineListToOrg lst
   return $ "*" <> contents <> "*"
diff --git a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
index 68345bcd1..d225535cd 100644
--- a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
+++ b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
@@ -323,6 +323,9 @@ inlineToParElems (Str s) = do
 inlineToParElems (Emph ils) =
   local (\r -> r{envRunProps = (envRunProps r){rPropItalics=True}}) $
   inlinesToParElems ils
+inlineToParElems (Underline ils) =
+  local (\r -> r{envRunProps = (envRunProps r){rPropUnderline=True}}) $
+  inlinesToParElems ils
 inlineToParElems (Strong ils) =
   local (\r -> r{envRunProps = (envRunProps r){rPropBold=True}}) $
   inlinesToParElems ils
diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs
index 67603728b..43bf382b7 100644
--- a/src/Text/Pandoc/Writers/RST.hs
+++ b/src/Text/Pandoc/Writers/RST.hs
@@ -415,6 +415,7 @@ transformInlines =  insertBS .
         hasContents :: Inline -> Bool
         hasContents (Str "")              = False
         hasContents (Emph [])             = False
+        hasContents (Underline [])        = False
         hasContents (Strong [])           = False
         hasContents (Strikeout [])        = False
         hasContents (Superscript [])      = False
@@ -474,6 +475,7 @@ transformInlines =  insertBS .
         okBeforeComplex _ = False
         isComplex :: Inline -> Bool
         isComplex (Emph _)        = True
+        isComplex (Underline _)   = True
         isComplex (Strong _)      = True
         isComplex (SmallCaps _)   = True
         isComplex (Strikeout _)   = True
@@ -538,6 +540,7 @@ mapNested f i = setInlineChildren i (f (dropInlineParent i))
 dropInlineParent :: Inline -> [Inline]
 dropInlineParent (Link _ i _)    = i
 dropInlineParent (Emph i)        = i
+dropInlineParent (Underline i)   = i
 dropInlineParent (Strong i)      = i
 dropInlineParent (Strikeout i)   = i
 dropInlineParent (Superscript i) = i
@@ -552,6 +555,7 @@ dropInlineParent i               = [i] -- not a parent, like Str or Space
 setInlineChildren :: Inline -> [Inline] -> Inline
 setInlineChildren (Link a _ t) i    = Link a i t
 setInlineChildren (Emph _) i        = Emph i
+setInlineChildren (Underline _) i   = Underline i
 setInlineChildren (Strong _) i      = Strong i
 setInlineChildren (Strikeout _) i   = Strikeout i
 setInlineChildren (Superscript _) i = Superscript i
@@ -582,6 +586,9 @@ inlineToRST (Span (_,_,kvs) ils) = do
 inlineToRST (Emph lst) = do
   contents <- writeInlines lst
   return $ "*" <> contents <> "*"
+-- Underline is not supported, fall back to Emph
+inlineToRST (Underline lst) =
+  inlineToRST (Emph lst)
 inlineToRST (Strong lst) = do
   contents <- writeInlines lst
   return $ "**" <> contents <> "**"
diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs
index da24e8b71..66a2539c6 100644
--- a/src/Text/Pandoc/Writers/RTF.hs
+++ b/src/Text/Pandoc/Writers/RTF.hs
@@ -351,6 +351,9 @@ inlineToRTF (Span _ lst) = inlinesToRTF lst
 inlineToRTF (Emph lst) = do
   contents <- inlinesToRTF lst
   return $ "{\\i " <> contents <> "}"
+inlineToRTF (Underline lst) = do
+  contents <- inlinesToRTF lst
+  return $ "{\\pnul " <> contents <> "}"
 inlineToRTF (Strong lst) = do
   contents <- inlinesToRTF lst
   return $ "{\\b " <> contents <> "}"
diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs
index 9ccc137eb..ddf1d76e3 100644
--- a/src/Text/Pandoc/Writers/TEI.hs
+++ b/src/Text/Pandoc/Writers/TEI.hs
@@ -231,6 +231,8 @@ inlineToTEI :: PandocMonad m => WriterOptions -> Inline -> m (Doc Text)
 inlineToTEI _ (Str str) = return $ literal $ escapeStringForXML str
 inlineToTEI opts (Emph lst) =
   inTags False "hi" [("rendition","simple:italic")] <$> inlinesToTEI opts lst
+inlineToTEI opts (Underline lst) =
+  inTags False "hi" [("rendition","simple:underline")] <$> inlinesToTEI opts lst
 inlineToTEI opts (Strong lst) =
   inTags False "hi" [("rendition", "simple:bold")] <$> inlinesToTEI opts lst
 inlineToTEI opts (Strikeout lst) =
diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs
index ef1ee7d25..c6debd9ce 100644
--- a/src/Text/Pandoc/Writers/Texinfo.hs
+++ b/src/Text/Pandoc/Writers/Texinfo.hs
@@ -392,6 +392,10 @@ inlineToTexinfo (Span _ lst) =
 inlineToTexinfo (Emph lst) =
   inCmd "emph" <$> inlineListToTexinfo lst
 
+-- Underline isn't supported, fall back to Emph
+inlineToTexinfo (Underline lst) =
+  inlineToTexinfo (Emph lst)
+
 inlineToTexinfo (Strong lst) =
   inCmd "strong" <$> inlineListToTexinfo lst
 
diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs
index e68303cfe..61ddb7497 100644
--- a/src/Text/Pandoc/Writers/Textile.hs
+++ b/src/Text/Pandoc/Writers/Textile.hs
@@ -386,6 +386,12 @@ inlineToTextile opts (Emph lst) = do
               then "<em>" <> contents <> "</em>"
               else "_" <> contents <> "_"
 
+inlineToTextile opts (Underline lst) = do
+  contents <- inlineListToTextile opts lst
+  return $ if '+' `elemText` contents
+              then "<u>" <> contents <> "</u>"
+              else "+" <> contents <> "+"
+
 inlineToTextile opts (Strong lst) = do
   contents <- inlineListToTextile opts lst
   return $ if '*' `elemText` contents
diff --git a/src/Text/Pandoc/Writers/XWiki.hs b/src/Text/Pandoc/Writers/XWiki.hs
index 486de943f..cd72d9647 100644
--- a/src/Text/Pandoc/Writers/XWiki.hs
+++ b/src/Text/Pandoc/Writers/XWiki.hs
@@ -163,6 +163,10 @@ inlineToXWiki (Emph lst) = do
   contents <- inlineListToXWiki lst
   return $ "//" <> contents <> "//"
 
+inlineToXWiki (Underline lst) = do
+  contents <- inlineListToXWiki lst
+  return $ "__" <> contents <> "__"
+
 inlineToXWiki (Strong lst) = do
   contents <- inlineListToXWiki lst
   return $ "**" <> contents <> "**"
diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs
index e311abe7b..902b093d3 100644
--- a/src/Text/Pandoc/Writers/ZimWiki.hs
+++ b/src/Text/Pandoc/Writers/ZimWiki.hs
@@ -273,6 +273,10 @@ inlineToZimWiki opts (Emph lst) = do
   contents <- inlineListToZimWiki opts lst
   return $ "//" <> contents <> "//"
 
+inlineToZimWiki opts (Underline lst) = do
+  contents <- inlineListToZimWiki opts lst
+  return $ "__" <> contents <> "__"
+
 inlineToZimWiki opts (Strong lst) = do
   contents <- inlineListToZimWiki opts lst
   return $ "**" <> contents <> "**"
-- 
cgit v1.2.3