From 751b5ad010794ec51699bfb89de91b38c85d3297 Mon Sep 17 00:00:00 2001
From: Henri Menke <henri@icp.uni-stuttgart.de>
Date: Fri, 26 Jan 2018 08:56:28 +1300
Subject: [PATCH] ConTeXt writer: new section syntax and --section-divs (#4295)

Fixes #2609.

This PR introduces the new-style section headings: `\section[my-header]{My Header}` -> `\section[title={My Header},reference={my-header}]`.

On top of this, the ConTeXt writer now supports the `--section-divs` option to write sections in the fenced style, with `\startsection` and `\stopsection`.
---
 src/Text/Pandoc/Writers/ConTeXt.hs | 54 ++++++++++++++++--------
 test/Tests/Writers/ConTeXt.hs      | 25 ++++++++++-
 test/command/3968.md               |  5 ++-
 test/writer.context                | 67 ++++++++++++++++--------------
 test/writers-lang-and-dir.context  |  8 ++--
 5 files changed, 103 insertions(+), 56 deletions(-)

diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
index bca00b55a..f94c12d89 100644
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -159,8 +159,9 @@ elementToConTeXt :: PandocMonad m => WriterOptions -> Element -> WM m Doc
 elementToConTeXt _ (Blk block) = blockToConTeXt block
 elementToConTeXt opts (Sec level _ attr title' elements) = do
   header' <- sectionHeader attr level title'
+  footer' <- sectionFooter attr level
   innerContents <- mapM (elementToConTeXt opts) elements
-  return $ vcat (header' : innerContents)
+  return $ header' $$ vcat innerContents $$ footer'
 
 -- | Convert Pandoc block element to ConTeXt.
 blockToConTeXt :: PandocMonad m => Block -> WM m Doc
@@ -485,32 +486,51 @@ sectionHeader :: PandocMonad m
               -> Int
               -> [Inline]
               -> WM m Doc
-sectionHeader (ident,classes,_) hdrLevel lst = do
+sectionHeader (ident,classes,kvs) hdrLevel lst = do
+  opts <- gets stOptions
   contents <- inlineListToConTeXt lst
-  st <- get
-  let opts = stOptions st
+  levelText <- sectionLevelToText opts (ident,classes,kvs) hdrLevel
+  let ident' = if null ident
+               then empty
+               else "reference=" <> braces (text (toLabel ident))
+  let contents' = if contents == empty
+                  then empty
+                  else "title=" <> braces contents
+  let options = if keys == empty || levelText == empty
+                then empty
+                else brackets keys
+        where keys = hcat $ intersperse "," $ filter (empty /=) [contents', ident']
+  let starter = if writerSectionDivs opts
+                then "\\start"
+                else "\\"
+  return $ starter <> levelText <> options <> blankline
+
+-- | Craft the section footer
+sectionFooter :: PandocMonad m => Attr -> Int -> WM m Doc
+sectionFooter attr hdrLevel = do
+  opts <- gets stOptions
+  levelText <- sectionLevelToText opts attr hdrLevel
+  return $ if writerSectionDivs opts
+           then "\\stop" <> levelText <> blankline
+           else empty
+
+-- | Generate a textual representation of the section level
+sectionLevelToText :: PandocMonad m => WriterOptions -> Attr -> Int -> WM m Doc
+sectionLevelToText opts (_,classes,_) hdrLevel = do
   let level' = case writerTopLevelDivision opts of
                  TopLevelPart    -> hdrLevel - 2
                  TopLevelChapter -> hdrLevel - 1
                  TopLevelSection -> hdrLevel
                  TopLevelDefault -> hdrLevel
-  let ident' = if null ident
-                  then empty
-                  else brackets (text (toLabel ident))
   let (section, chapter) = if "unnumbered" `elem` classes
                               then (text "subject", text "title")
                               else (text "section", text "chapter")
   return $ case level' of
-             -1                   -> text "\\part" <> ident' <> braces contents
-             0                    -> char '\\' <> chapter <> ident' <>
-                                           braces contents
-             n | n >= 1 && n <= 5 -> char '\\'
-                                     <> text (concat (replicate (n - 1) "sub"))
-                                     <> section
-                                     <> ident'
-                                     <> braces contents
-                                     <> blankline
-             _                    -> contents <> blankline
+             -1         -> text "part"
+             0          -> chapter
+             n | n >= 1 -> text (concat (replicate (n - 1) "sub"))
+                           <> section
+             _          -> empty -- cannot happen
 
 fromBCP47 :: PandocMonad m => Maybe String -> WM m (Maybe String)
 fromBCP47 mbs = fromBCP47' <$> toLang mbs
diff --git a/test/Tests/Writers/ConTeXt.hs b/test/Tests/Writers/ConTeXt.hs
index 678321519..812aab4a6 100644
--- a/test/Tests/Writers/ConTeXt.hs
+++ b/test/Tests/Writers/ConTeXt.hs
@@ -18,6 +18,9 @@ context' = unpack . purely (writeConTeXt def{ writerWrapText = WrapNone }) . toP
 contextNtb :: (ToPandoc a) => a -> String
 contextNtb = unpack . purely (writeConTeXt def{ writerExtensions = enableExtension Ext_ntb pandocExtensions }) . toPandoc
 
+contextDiv :: (ToPandoc a) => a -> String
+contextDiv = unpack . purely (writeConTeXt def{ writerSectionDivs = True }) . toPandoc
+
 {-
   "my test" =: X =?> Y
 
@@ -47,7 +50,27 @@ tests = [ testGroup "inline code"
           ]
         , testGroup "headers"
           [ "level 1" =:
-            headerWith ("my-header",[],[]) 1 "My header" =?> "\\section[my-header]{My header}"
+            headerWith ("my-header",[],[]) 1 "My header" =?> "\\section[title={My header},reference={my-header}]"
+          , test contextDiv "section-divs" $
+                   (   headerWith ("header1", [], []) 1 (text "Header1")
+                    <> headerWith ("header2", [], []) 2 (text "Header2")
+                    <> headerWith ("header3", [], []) 3 (text "Header3")
+                    <> headerWith ("header4", [], []) 4 (text "Header4")
+                    <> headerWith ("header5", [], []) 5 (text "Header5")
+                    <> headerWith ("header6", [], []) 6 (text "Header6"))
+                   =?>
+              unlines [ "\\startsection[title={Header1},reference={header1}]\n"
+                      , "\\startsubsection[title={Header2},reference={header2}]\n"
+                      , "\\startsubsubsection[title={Header3},reference={header3}]\n"
+                      , "\\startsubsubsubsection[title={Header4},reference={header4}]\n"
+                      , "\\startsubsubsubsubsection[title={Header5},reference={header5}]\n"
+                      , "\\startsubsubsubsubsubsection[title={Header6},reference={header6}]\n"
+                      , "\\stopsubsubsubsubsubsection\n"
+                      , "\\stopsubsubsubsubsection\n"
+                      , "\\stopsubsubsubsection\n"
+                      , "\\stopsubsubsection\n"
+                      , "\\stopsubsection\n"
+                      , "\\stopsection" ]
           ]
         , testGroup "bullet lists"
           [ "nested" =:
diff --git a/test/command/3968.md b/test/command/3968.md
index 24f0900a9..c76cfcba4 100644
--- a/test/command/3968.md
+++ b/test/command/3968.md
@@ -4,6 +4,7 @@
 
 ## Section
 ^D
-\chapter[chapter]{Chapter}
-\section[section]{Section}
+\chapter[title={Chapter},reference={chapter}]
+
+\section[title={Section},reference={section}]
 ```
diff --git a/test/writer.context b/test/writer.context
index e7af684f8..0cbbc7df4 100644
--- a/test/writer.context
+++ b/test/writer.context
@@ -72,32 +72,34 @@ markdown test suite.
 
 \thinrule
 
-\section[headers]{Headers}
+\section[title={Headers},reference={headers}]
 
-\subsection[level-2-with-an-embedded-link]{Level 2 with an
-\useURL[url1][/url][][embedded link]\from[url1]}
+\subsection[title={Level 2 with an \useURL[url1][/url][][embedded
+link]\from[url1]},reference={level-2-with-an-embedded-link}]
 
-\subsubsection[level-3-with-emphasis]{Level 3 with {\em emphasis}}
+\subsubsection[title={Level 3 with
+{\em emphasis}},reference={level-3-with-emphasis}]
 
-\subsubsubsection[level-4]{Level 4}
+\subsubsubsection[title={Level 4},reference={level-4}]
 
-\subsubsubsubsection[level-5]{Level 5}
+\subsubsubsubsection[title={Level 5},reference={level-5}]
 
-\section[level-1]{Level 1}
+\section[title={Level 1},reference={level-1}]
 
-\subsection[level-2-with-emphasis]{Level 2 with {\em emphasis}}
+\subsection[title={Level 2 with
+{\em emphasis}},reference={level-2-with-emphasis}]
 
-\subsubsection[level-3]{Level 3}
+\subsubsection[title={Level 3},reference={level-3}]
 
 with no blank line
 
-\subsection[level-2]{Level 2}
+\subsection[title={Level 2},reference={level-2}]
 
 with no blank line
 
 \thinrule
 
-\section[paragraphs]{Paragraphs}
+\section[title={Paragraphs},reference={paragraphs}]
 
 Here's a regular paragraph.
 
@@ -112,7 +114,7 @@ here.
 
 \thinrule
 
-\section[block-quotes]{Block Quotes}
+\section[title={Block Quotes},reference={block-quotes}]
 
 E-mail style:
 
@@ -155,7 +157,7 @@ And a following paragraph.
 
 \thinrule
 
-\section[code-blocks]{Code Blocks}
+\section[title={Code Blocks},reference={code-blocks}]
 
 Code:
 
@@ -179,9 +181,9 @@ These should not be escaped:  \$ \\ \> \[ \{
 
 \thinrule
 
-\section[lists]{Lists}
+\section[title={Lists},reference={lists}]
 
-\subsection[unordered]{Unordered}
+\subsection[title={Unordered},reference={unordered}]
 
 Asterisks tight:
 
@@ -249,7 +251,7 @@ Minuses loose:
   Minus 3
 \stopitemize
 
-\subsection[ordered]{Ordered}
+\subsection[title={Ordered},reference={ordered}]
 
 Tight:
 
@@ -308,7 +310,7 @@ Multiple paragraphs:
   Item 3.
 \stopitemize
 
-\subsection[nested]{Nested}
+\subsection[title={Nested},reference={nested}]
 
 \startitemize[packed]
 \item
@@ -362,7 +364,7 @@ Same thing but with paragraphs:
   Third
 \stopitemize
 
-\subsection[tabs-and-spaces]{Tabs and spaces}
+\subsection[title={Tabs and spaces},reference={tabs-and-spaces}]
 
 \startitemize
 \item
@@ -378,7 +380,7 @@ Same thing but with paragraphs:
   \stopitemize
 \stopitemize
 
-\subsection[fancy-list-markers]{Fancy list markers}
+\subsection[title={Fancy list markers},reference={fancy-list-markers}]
 
 \startitemize[n][start=2,left=(,stopper=),width=2.0em]
 \item
@@ -442,7 +444,7 @@ B. Williams
 
 \thinrule
 
-\section[definition-lists]{Definition Lists}
+\section[title={Definition Lists},reference={definition-lists}]
 
 Tight using spaces:
 
@@ -553,7 +555,7 @@ Blank line after term, indented marker, alternate markers:
   \stopitemize
 \stopdescription
 
-\section[html-blocks]{HTML Blocks}
+\section[title={HTML Blocks},reference={html-blocks}]
 
 Simple block on one line:
 
@@ -613,7 +615,7 @@ Hr's:
 
 \thinrule
 
-\section[inline-markup]{Inline Markup}
+\section[title={Inline Markup},reference={inline-markup}]
 
 This is {\em emphasized}, and so {\em is this}.
 
@@ -642,7 +644,8 @@ spaces: a^b c^d, a\lettertilde{}b c\lettertilde{}d.
 
 \thinrule
 
-\section[smart-quotes-ellipses-dashes]{Smart quotes, ellipses, dashes}
+\section[title={Smart quotes, ellipses,
+dashes},reference={smart-quotes-ellipses-dashes}]
 
 \quotation{Hello,} said the spider. \quotation{\quote{Shelob} is my name.}
 
@@ -665,7 +668,7 @@ Ellipses\ldots{}and\ldots{}and\ldots{}.
 
 \thinrule
 
-\section[latex]{LaTeX}
+\section[title={LaTeX},reference={latex}]
 
 \startitemize[packed]
 \item
@@ -705,7 +708,7 @@ Here's a LaTeX table:
 
 \thinrule
 
-\section[special-characters]{Special Characters}
+\section[title={Special Characters},reference={special-characters}]
 
 Here is some unicode:
 
@@ -766,9 +769,9 @@ Minus: -
 
 \thinrule
 
-\section[links]{Links}
+\section[title={Links},reference={links}]
 
-\subsection[explicit]{Explicit}
+\subsection[title={Explicit},reference={explicit}]
 
 Just a \useURL[url4][/url/][][URL]\from[url4].
 
@@ -788,7 +791,7 @@ Just a \useURL[url4][/url/][][URL]\from[url4].
 
 \useURL[url12][][][Empty]\from[url12].
 
-\subsection[reference]{Reference}
+\subsection[title={Reference},reference={reference}]
 
 Foo \useURL[url13][/url/][][bar]\from[url13].
 
@@ -812,7 +815,7 @@ Foo \useURL[url19][/url/][][bar]\from[url19].
 
 Foo \useURL[url20][/url/][][biz]\from[url20].
 
-\subsection[with-ampersands]{With ampersands}
+\subsection[title={With ampersands},reference={with-ampersands}]
 
 Here's a \useURL[url21][http://example.com/?foo=1&bar=2][][link with an
 ampersand in the URL]\from[url21].
@@ -825,7 +828,7 @@ Here's an \useURL[url23][/script?foo=1&bar=2][][inline link]\from[url23].
 Here's an \useURL[url24][/script?foo=1&bar=2][][inline link in pointy
 braces]\from[url24].
 
-\subsection[autolinks]{Autolinks}
+\subsection[title={Autolinks},reference={autolinks}]
 
 With an ampersand: \useURL[url25][http://example.com/?foo=1&bar=2]\from[url25]
 
@@ -853,7 +856,7 @@ or here: <http://example.com/>
 
 \thinrule
 
-\section[images]{Images}
+\section[title={Images},reference={images}]
 
 From \quotation{Voyage dans la Lune} by Georges Melies (1902):
 
@@ -863,7 +866,7 @@ Here is a movie {\externalfigure[movie.jpg]} icon.
 
 \thinrule
 
-\section[footnotes]{Footnotes}
+\section[title={Footnotes},reference={footnotes}]
 
 Here is a footnote reference,\footnote{Here is the footnote. It can go
   anywhere after the footnote reference. It need not be placed at the end of
diff --git a/test/writers-lang-and-dir.context b/test/writers-lang-and-dir.context
index 19c45a4c9..a1c87bb27 100644
--- a/test/writers-lang-and-dir.context
+++ b/test/writers-lang-and-dir.context
@@ -57,7 +57,7 @@
 
 \starttext
 
-\section[empty-divs-and-spans]{Empty Divs and Spans}
+\section[title={Empty Divs and Spans},reference={empty-divs-and-spans}]
 
 Some text and
 
@@ -67,7 +67,7 @@ and more text.
 
 Next paragraph with a span and a word-thatincludesaspanright?
 
-\section[directionality]{Directionality}
+\section[title={Directionality},reference={directionality}]
 
 Some text and
 
@@ -86,7 +86,7 @@ and a ltr div. with a {\righttoleft rtl span}.
 Next paragraph with a {\righttoleft rtl span} and a
 word-that-includesa{\lefttoright ltrspan}right?
 
-\section[languages]{Languages}
+\section[title={Languages},reference={languages}]
 
 Some text and
 
@@ -102,7 +102,7 @@ word-that-includesa\start\language[de-ch]Swiss German span\stop right?
 
 Some \start\language[es]Spanish text\stop .
 
-\section[combined]{Combined}
+\section[title={Combined},reference={combined}]
 
 Some text and