git.iko.soy/typeable/pandoc
on 54fe3f7 help sign in
.github/workflows/ci.yml+4−12
since splitsnapshots
unifiedsplit
@@ -43,8 +43,6 @@ jobs:
43 fail-fast: true
43 fail-fast: true
44 matrix:
44 matrix:
45 versions:
45 versions:
46− - ghc: '8.0.2'
47− cabal: '2.4'
48 - ghc: '8.2.2'
46 - ghc: '8.2.2'
49 cabal: '2.4'
47 cabal: '2.4'
50 - ghc: '8.4.4'
48 - ghc: '8.4.4'
@@ -61,16 +59,10 @@ jobs:
61 # need to install older cabal/ghc versions from ppa repository
59 # need to install older cabal/ghc versions from ppa repository
62
60
63 - name: Install recent cabal/ghc
61 - name: Install recent cabal/ghc
64− run: |
62+ uses: actions/setup-haskell@v1.1
65− if [[ ! -d /opt/ghc/${{ matrix.versions.ghc }} ]]
63+ with:
66− then
67− sudo add-apt-repository ppa:hvr/ghc
68− sudo apt-get update
69− sudo apt-get install ghc-${{ matrix.versions.ghc }} cabal-install-${{ matrix.versions.cabal }}
70− fi
71− # Use a GitHub workflow command to add folders to PATH.
72− echo "::add-path::/opt/ghc/${{ matrix.versions.ghc }}/bin"
64+ ghc-version: ${{ matrix.versions.ghc }}
73− echo "::add-path::/opt/cabal/${{ matrix.versions.cabal }}/bin"
65+ cabal-version: ${{ matrix.versions.cabal }}
74
66
75 # declare/restore cached things
67 # declare/restore cached things
76 # caching doesn't work for scheduled runs yet
68 # caching doesn't work for scheduled runs yet
.github/workflows/release-candidate.yml+2−1
@@ -35,8 +35,9 @@ jobs:
35 stack_opts: "-j1"
35 stack_opts: "-j1"
36 - osarch: "windows-i386"
36 - osarch: "windows-i386"
37 arch: "x86"
37 arch: "x86"
38− choco_opts: "--x86"
38+ choco_opts: "--x86 --version 2.1.3.20190715"
39 stack_opts: "-j1 --flag hslua:lua_32bits"
39 stack_opts: "-j1 --flag hslua:lua_32bits"
40+ # we use stack 2.1.3 because 2.3.1 doesn't support i386
40
41
41 steps:
42 steps:
42 - uses: actions/checkout@v1
43 - uses: actions/checkout@v1
AUTHORS.md+1
@@ -241,6 +241,7 @@
241- Urs Liska
241- Urs Liska
242- Václav Zeman
242- Václav Zeman
243- Václav Haisman
243- Václav Haisman
244+- Vaibhav Sagar
244- Vanessa McHale
245- Vanessa McHale
245- Vasily Alferov
246- Vasily Alferov
246- Viktor Kronvall
247- Viktor Kronvall
CONTRIBUTING.md+9−3
@@ -17,8 +17,14 @@ Before you submit a bug report, search the [open issues] *and* [closed issues]
17to make sure the issue hasn't come up before. Also, check the [User's Guide] and
17to make sure the issue hasn't come up before. Also, check the [User's Guide] and
18[FAQs] for anything relevant.
18[FAQs] for anything relevant.
19
19
20−Make sure you can reproduce the bug with the [latest released version] of pandoc
20+Make sure you can reproduce the bug with the [latest released
21+version] of pandoc---or, even better, the development version,
22+since the bug may have been fixed since the last release.
23+[Nightly builds] are available, so you don't need to compile
21−(or, even better, the [development version]).
24+from source to test againt the development version.
25+(To fetch a nightly, visit the link, click the topmost "Nightly"
26+in the table, then choose your platform under "Artifacts." Note
27+that you must be logged in with a GitHub account.)
22
28
23Your report should give detailed, *reproducible* instructions, including
29Your report should give detailed, *reproducible* instructions, including
24
30
@@ -346,7 +352,7 @@ you may want to consider submitting a pull request to the
346[open issues]: https://github.com/jgm/pandoc/issues
352[open issues]: https://github.com/jgm/pandoc/issues
347[closed issues]: https://github.com/jgm/pandoc/issues?q=is%3Aissue+is%3Aclosed
353[closed issues]: https://github.com/jgm/pandoc/issues?q=is%3Aissue+is%3Aclosed
348[latest released version]: https://github.com/jgm/pandoc/releases/latest
354[latest released version]: https://github.com/jgm/pandoc/releases/latest
349−[development version]: https://github.com/pandoc-extras/pandoc-nightly/releases/latest
355+[Nightly builds]: https://github.com/jgm/pandoc/actions?query=workflow%3ANightly
350[pandoc-discuss]: http://groups.google.com/group/pandoc-discuss
356[pandoc-discuss]: http://groups.google.com/group/pandoc-discuss
351[issue tracker]: https://github.com/jgm/pandoc/issues
357[issue tracker]: https://github.com/jgm/pandoc/issues
352[User's Guide]: http://pandoc.org/MANUAL.html
358[User's Guide]: http://pandoc.org/MANUAL.html
MANUAL.txt+67−43
@@ -1,7 +1,7 @@
1---
1---
2title: Pandoc User's Guide
2title: Pandoc User's Guide
3author: John MacFarlane
3author: John MacFarlane
4−date: March 23, 2020
4+date: June 29, 2020
5---
5---
6
6
7# Synopsis
7# Synopsis
@@ -226,6 +226,7 @@ header when requesting a document from a URL:
226
226
227 ::: {#input-formats}
227 ::: {#input-formats}
228 - `commonmark` ([CommonMark] Markdown)
228 - `commonmark` ([CommonMark] Markdown)
229+ - `commonmark_x` ([CommonMark] Markdown with extensions)
229 - `creole` ([Creole 1.0])
230 - `creole` ([Creole 1.0])
230 - `csv` ([CSV] table)
231 - `csv` ([CSV] table)
231 - `docbook` ([DocBook])
232 - `docbook` ([DocBook])
@@ -277,6 +278,7 @@ header when requesting a document from a URL:
277 - `asciidoc` ([AsciiDoc]) or `asciidoctor` ([AsciiDoctor])
278 - `asciidoc` ([AsciiDoc]) or `asciidoctor` ([AsciiDoctor])
278 - `beamer` ([LaTeX beamer][`beamer`] slide show)
279 - `beamer` ([LaTeX beamer][`beamer`] slide show)
279 - `commonmark` ([CommonMark] Markdown)
280 - `commonmark` ([CommonMark] Markdown)
281+ - `commonmark_x` ([CommonMark] Markdown with extensions)
280 - `context` ([ConTeXt])
282 - `context` ([ConTeXt])
281 - `docbook` or `docbook4` ([DocBook] 4)
283 - `docbook` or `docbook4` ([DocBook] 4)
282 - `docbook5` (DocBook 5)
284 - `docbook5` (DocBook 5)
@@ -902,7 +904,7 @@ header when requesting a document from a URL:
902 downloaded). If you're behind a proxy, you also need to set
904 downloaded). If you're behind a proxy, you also need to set
903 the environment variable `http_proxy` to `http://...`.
905 the environment variable `http_proxy` to `http://...`.
904
906
905−`--no-check-certificate
907+`--no-check-certificate`
906
908
907: Disable the certificate verification to allow access to
909: Disable the certificate verification to allow access to
908 unsecure HTTP resources (for example when the certificate
910 unsecure HTTP resources (for example when the certificate
@@ -2767,53 +2769,43 @@ reading web pages formatted using MathJax, for example.
2767
2769
2768## Raw HTML/TeX
2770## Raw HTML/TeX
2769
2771
2770−The following extensions (especially how they affect Markdown
2771−input/output) are also described in more detail in their respective
2772+The following extensions are described in more detail in
2772−sections of [Pandoc's Markdown].
2773+their respective sections of [Pandoc's Markdown]:
2773
2774
2774−#### Extension: `raw_html` {#raw_html}
2775+- [`raw_html`](#extension-raw_html) allows HTML elements which
2776+ are not representable in pandoc's AST to be parsed as raw HTML.
2777+ By default, this is disabled for HTML input.
2775
2778
2776−When converting from HTML, parse elements to raw HTML which are not
2779+- [`raw_tex`](#extension-raw_tex) allows raw LaTeX, TeX, and ConTeXt
2777−representable in pandoc's AST.
2780+ to be included in a document. This extension can be enabled/disabled
2778−By default, this is disabled for HTML input.
2781+ for the following formats (in addition to `markdown`):
2779
2782
2780−#### Extension: `raw_tex` {#raw_tex}
2783+ input formats
2784+ : `latex`, `org`, `textile`, `html` (environments, `\ref`, and
2785+ `\eqref` only), `ipynb`
2781
2786
2782−Allows raw LaTeX, TeX, and ConTeXt to be included in a document.
2787+ output formats
2788+ : `textile`, `commonmark`
2783
2789
2784−This extension can be enabled/disabled for the following formats
2790+ Note: as applied to `ipynb`, `raw_html` and `raw_tex` affect not
2785−(in addition to `markdown`):
2791+ only raw TeX in markdown cells, but data with mime type
2792+ `text/html` in output cells. Since the `ipynb` reader attempts
2793+ to preserve the richest possible outputs when several options
2794+ are given, you will get best results if you disable `raw_html`
2795+ and `raw_tex` when converting to formats like `docx` which don't
2796+ allow raw `html` or `tex`.
2786
2797
2787−input formats
2798+- [`native_divs`](#extension-native_divs) causes HTML `div`
2788−: `latex`, `org`, `textile`, `html` (environments, `\ref`, and
2799+ elements to be parsed as native pandoc Div blocks.
2789− `\eqref` only), `ipynb`
2800+ If you want them to be parsed as raw HTML, use
2790−
2791−output formats
2792−: `textile`, `commonmark`
2793−
2794−Note: as applied to `ipynb`, `raw_html` and `raw_tex` affect not
2795−only raw TeX in markdown cells, but data with mime type
2796−`text/html` in output cells. Since the `ipynb` reader attempts
2797−to preserve the richest possible outputs when several options
2798−are given, you will get best results if you disable `raw_html`
2799−and `raw_tex` when converting to formats like `docx` which don't
2800−allow raw `html` or `tex`.
2801−
2802−#### Extension: `native_divs` {#native_divs}
2803−
2804−This extension is enabled by default for HTML input. This means that
2805−`div`s are parsed to pandoc native elements. (Alternatively, you
2806−can parse them to raw HTML using `-f html-native_divs+raw_html`.)
2801+ `-f html-native_divs+raw_html`.
2807−
2808−When converting HTML to Markdown, for example, you may want to drop all
2809−`div`s and `span`s:
2810−
2811− pandoc -f html-native_divs-native_spans -t markdown
2812−
2813−#### Extension: `native_spans` {#native_spans}
2814−
2815−Analogous to `native_divs` above.
2816
2802
2803+- [`native_spans`](#extension-native_spans) causes HTML `span`
2804+ elements to be parsed as native pandoc Span inlines.
2805+ If you want them to be parsed as raw HTML, use
2806+ `-f html-native_spans+raw_html`. If you want to drop all
2807+ `div`s and `span`s when converting HTML to Markdown, you
2808+ can use `pandoc -f html-native_divs-native_spans -t markdown`.
2817
2809
2818## Literate Haskell support
2810## Literate Haskell support
2819
2811
@@ -4943,6 +4935,37 @@ in pandoc, but may be enabled by adding `+EXTENSION` to the format
4943name, where `EXTENSION` is the name of the extension. Thus, for
4935name, where `EXTENSION` is the name of the extension. Thus, for
4944example, `markdown+hard_line_breaks` is Markdown with hard line breaks.
4936example, `markdown+hard_line_breaks` is Markdown with hard line breaks.
4945
4937
4938+#### Extension: `attributes` ####
4939+
4940+Allows attributes to be attached to any inline or block-level
4941+element. The syntax for the attributes is the same as that
4942+used in [`header_attributes`][Extension: `header_attributes`].
4943+
4944+- Attributes that occur immediately after an inline
4945+ element affect that element. If they follow a space, then they
4946+ belong to the space. (Hence, this option subsumes
4947+ `inline_code_attributes` and `link_attributes`.)
4948+- Attributes that occur immediately before a block
4949+ element, on a line by themselves, affect that
4950+ element.
4951+- Consecutive attribute specifiers may be used,
4952+ either for blocks or for inlines. Their attributes
4953+ will be combined.
4954+- Attributes that occur at the end of the text of
4955+ a Setext or ATX heading (separated by whitespace
4956+ from the text) affect the heading element. (Hence, this
4957+ option subsumes `header_attributes`.)
4958+- Attributes that occur after the opening fence
4959+ in a fenced code block affect the code block element. (Hence,
4960+ this option subsumes `fenced_code_attributes`.)
4961+- Attributes that occur at the end of a reference
4962+ link definition affect links that refer to that
4963+ definition.
4964+
4965+Note that pandoc's AST does not currently allow attributes
4966+to be attached to arbitrary elements. Hence a Span or Div
4967+container will be added if needed.
4968+
4946#### Extension: `old_dashes` ####
4969#### Extension: `old_dashes` ####
4947
4970
4948Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
4971Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
@@ -5141,7 +5164,8 @@ can, however, all be individually disabled. Also, `raw_tex`
5141only affects `gfm` output, not input.
5164only affects `gfm` output, not input.
5142
5165
5143`gfm` (GitHub-Flavored Markdown)
5166`gfm` (GitHub-Flavored Markdown)
5167+: `pipe_tables`, `raw_html`, `native_divs`,
5144−: `pipe_tables`, `raw_html`, `fenced_code_blocks`, `auto_identifiers`,
5168+ `fenced_code_blocks`, `auto_identifiers`,
5145 `gfm_auto_identifiers`, `backtick_code_blocks`,
5169 `gfm_auto_identifiers`, `backtick_code_blocks`,
5146 `autolink_bare_uris`, `space_in_atx_header`,
5170 `autolink_bare_uris`, `space_in_atx_header`,
5147 `intraword_underscores`, `strikeout`, `task_lists`, `emoji`,
5171 `intraword_underscores`, `strikeout`, `task_lists`, `emoji`,
Makefile+2−2
@@ -123,9 +123,9 @@ download_stats:
123
123
124pandoc-templates:
124pandoc-templates:
125 rm ../pandoc-templates/default.* ; \
125 rm ../pandoc-templates/default.* ; \
126− cp data/templates/default.* README.md styles.* ../pandoc-templates/ ; \
126+ cp data/templates/default.* data/templates/README.markdown data/templates/styles.* ../pandoc-templates/ ; \
127 pushd ../pandoc-templates/ && \
127 pushd ../pandoc-templates/ && \
128− git add default.* README.md styles.* && \
128+ git add default.* README.markdown styles.* && \
129 git commit -m "Updated templates for pandoc $(version)" && \
129 git commit -m "Updated templates for pandoc $(version)" && \
130 popd
130 popd
131
131
README.md+2−2
@@ -50,7 +50,7 @@ library. It can convert *from*
50 notebook](https://nbformat.readthedocs.io/en/latest/))
50 notebook](https://nbformat.readthedocs.io/en/latest/))
51 - `jats` ([JATS](https://jats.nlm.nih.gov) XML)
51 - `jats` ([JATS](https://jats.nlm.nih.gov) XML)
52 - `jira`
52 - `jira`
53− ([Jira](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)
53+ ([Jira](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)/Confluence
54 wiki markup)
54 wiki markup)
55 - `json` (JSON version of native AST)
55 - `json` (JSON version of native AST)
56 - `latex` ([LaTeX](https://www.latex-project.org/))
56 - `latex` ([LaTeX](https://www.latex-project.org/))
@@ -124,7 +124,7 @@ It can convert *to*
124 Publishing Tag Set)
124 Publishing Tag Set)
125 - `jats` (alias for `jats_archiving`)
125 - `jats` (alias for `jats_archiving`)
126 - `jira`
126 - `jira`
127− ([Jira](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)
127+ ([Jira](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)/Confluence
128 wiki markup)
128 wiki markup)
129 - `json` (JSON version of native AST)
129 - `json` (JSON version of native AST)
130 - `latex` ([LaTeX](https://www.latex-project.org/))
130 - `latex` ([LaTeX](https://www.latex-project.org/))
benchmark/benchmark-pandoc.hs+35−25
@@ -1,6 +1,5 @@
1{-# LANGUAGE NoImplicitPrelude #-}
1{-# LANGUAGE NoImplicitPrelude #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE TupleSections #-}
4{-
3{-
5Copyright (C) 2012-2019 John MacFarlane <jgm@berkeley.edu>
4Copyright (C) 2012-2019 John MacFarlane <jgm@berkeley.edu>
6
5
@@ -21,39 +20,49 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21import Prelude
20import Prelude
22import Text.Pandoc
21import Text.Pandoc
23import Text.Pandoc.MIME
22import Text.Pandoc.MIME
24−import Text.Pandoc.Error (PandocError(..))
25−import Control.Monad.Except (throwError)
23+import Control.Monad.Except (throwError, liftIO)
26import qualified Text.Pandoc.UTF8 as UTF8
24import qualified Text.Pandoc.UTF8 as UTF8
27import qualified Data.ByteString as B
25import qualified Data.ByteString as B
28import qualified Data.Text as T
26import qualified Data.Text as T
29import Criterion.Main
27import Criterion.Main
30import Criterion.Types (Config(..))
28import Criterion.Types (Config(..))
31import Data.List (intersect)
29import Data.List (intersect)
32−import Data.Maybe (mapMaybe)
30+import Data.Maybe (mapMaybe, catMaybes)
33import System.Environment (getArgs)
31import System.Environment (getArgs)
34import qualified Data.ByteString.Lazy as BL
32import qualified Data.ByteString.Lazy as BL
35
33
34+data Input = InputText {unInputText :: T.Text}
35+ | InputBS {unInputBS :: BL.ByteString}
36+
36readerBench :: Pandoc
37readerBench :: Pandoc
37 -> T.Text
38 -> T.Text
38− -> Maybe Benchmark
39+ -> IO (Maybe Benchmark)
39−readerBench doc name =
40+readerBench doc name = do
40− case res of
41− Right (readerFun, inp) ->
42− Just $ bench (T.unpack $ name <> " reader")
43− $ nf (\i -> either (error . show) id $ runPure (readerFun i))
41+ let (rdr, rexts) = either (error . show) id . runPure $ getReader name
44− inp
42+ res <- runIO $ do
45− Left _ -> Nothing
46− where res = runPure $ do
47− (rdr, rexts) <- getReader name
48 (wtr, wexts) <- getWriter name
43 (wtr, wexts) <- getWriter name
49 case (rdr, wtr) of
44 case (rdr, wtr) of
50 (TextReader r, TextWriter w) -> do
45 (TextReader r, TextWriter w) -> do
51− setResourcePath ["../test"]
46+ setResourcePath ["./test"]
52 inp <- w def{ writerWrapText = WrapAuto
47 inp <- w def{ writerWrapText = WrapAuto
53 , writerExtensions = wexts } doc
48 , writerExtensions = wexts } doc
49+ return (r def{ readerExtensions = rexts } . unInputText, InputText inp)
50+ (ByteStringReader r, ByteStringWriter w) -> do
51+ setResourcePath ["./test"]
52+ tmpl <- Just <$> compileDefaultTemplate name
53+ inp <- w def{ writerWrapText = WrapAuto
54+ , writerExtensions = wexts
55+ , writerTemplate = tmpl } doc
56+ liftIO $ BL.writeFile "/tmp/test.odt" inp
54− return $ (r def{ readerExtensions = rexts }, inp)
57+ return (r def{ readerExtensions = rexts } . unInputBS, InputBS inp)
55− _ -> throwError $ PandocSomeError $ "not a text format: "
58+ _ -> throwError $ PandocSomeError $ "text/bytestring format mismatch: "
56 <> name
59 <> name
60+ return $ case res of
61+ Right (readerFun, inp) ->
62+ Just $ bench (T.unpack $ name <> " reader")
63+ $ nf (\i -> either (error . show) id $ runPure (readerFun i))
64+ inp
65+ Left _ -> Nothing
57
66
58getImages :: IO [(FilePath, MimeType, BL.ByteString)]
67getImages :: IO [(FilePath, MimeType, BL.ByteString)]
59getImages = do
68getImages = do
@@ -89,22 +98,23 @@ main :: IO ()
89main = do
98main = do
90 args <- filter (\x -> T.take 1 x /= "-") . fmap T.pack <$> getArgs
99 args <- filter (\x -> T.take 1 x /= "-") . fmap T.pack <$> getArgs
91 print args
100 print args
92− let matchReader (n, TextReader _) =
101+ let matchReader (n, _) =
93 null args || ("reader" `elem` args && n `elem` args)
102 null args || ("reader" `elem` args && n `elem` args)
94− matchReader _ = False
95− let matchWriter (n, TextWriter _) =
103+ matchWriter (n, TextWriter _) =
96 null args || ("writer" `elem` args && n `elem` args)
104 null args || ("writer" `elem` args && n `elem` args)
97 matchWriter _ = False
105 matchWriter _ = False
106+ allWriters = map fst (writers :: [(T.Text, Writer PandocPure)])
98− let matchedReaders = map fst $ (filter matchReader readers
107+ matchedReaders = map fst (filter matchReader readers
99 :: [(T.Text, Reader PandocPure)])
108 :: [(T.Text, Reader PandocPure)])
100− let matchedWriters = map fst $ (filter matchWriter writers
109+ matchedWriters = map fst (filter matchWriter writers
101 :: [(T.Text, Writer PandocPure)])
110 :: [(T.Text, Writer PandocPure)])
102 inp <- UTF8.toText <$> B.readFile "test/testsuite.txt"
111 inp <- UTF8.toText <$> B.readFile "test/testsuite.txt"
103 let opts = def
112 let opts = def
104 let doc = either (error . show) id $ runPure $ readMarkdown opts inp
113 let doc = either (error . show) id $ runPure $ readMarkdown opts inp
114+ readerBs <- fmap catMaybes
105− let readerBs = mapMaybe (readerBench doc)
115+ $ mapM (readerBench doc)
106− $ filter (/="haddock")
116+ $ filter (/="haddock")
107− (matchedReaders `intersect` matchedWriters)
117+ (matchedReaders `intersect` allWriters)
108 -- we need the corresponding writer to generate
118 -- we need the corresponding writer to generate
109 -- input for the reader
119 -- input for the reader
110 let writerBs = mapMaybe (writerBench doc) matchedWriters
120 let writerBs = mapMaybe (writerBench doc) matchedWriters
cabal.project+5
@@ -12,3 +12,8 @@ source-repository-package
12 type: git
12 type: git
13 location: https://github.com/jgm/pandoc-citeproc
13 location: https://github.com/jgm/pandoc-citeproc
14 tag: 0.17.0.1
14 tag: 0.17.0.1
15+
16+ source-repository-package
17+ type: git
18+ location: https://github.com/jgm/commonmark-hs
19+ tag: 8d4442abc443ce0100cc87af797e7df9a72b9b9a
changelog.md+58−2
@@ -1,6 +1,6 @@
1# Revision history for pandoc
1# Revision history for pandoc
2
2
3−## pandoc 2.10 (YYYY-MM-DD)
3+## pandoc 2.10 (2020-06-29)
4
4
5 * Use pandoc-types 1.21. This adds two things:
5 * Use pandoc-types 1.21. This adds two things:
6
6
@@ -31,6 +31,12 @@
31 `--no-check-certificate`, which disables certificate checking when
31 `--no-check-certificate`, which disables certificate checking when
32 resources are fetched by HTTP.
32 resources are fetched by HTTP.
33
33
34+ * Unify defaults and markdown metadata parsers (#6328, Nikolay
35+ Yakimov). Clean up code in Text.Pandoc.Readers.Metadata and
36+ properly handle errors in `yamlToMeta`. This fixes parsing
37+ of Boolean fields in metadata withinin defaults files and reduces
38+ code duplication.
39+
34 * Docbook reader:
40 * Docbook reader:
35
41
36 + Implement `<procedure>` (#6442, Mathieu Boespflug).
42 + Implement `<procedure>` (#6442, Mathieu Boespflug).
@@ -39,7 +45,11 @@
39 + Implement `<replaceable>` (#6437, Mathieu Boespflug)
45 + Implement `<replaceable>` (#6437, Mathieu Boespflug)
40 + Map `<simplesect>` to unnumbered section (#6436, Mathieu Boespflug).
46 + Map `<simplesect>` to unnumbered section (#6436, Mathieu Boespflug).
41
47
48+ * JATS reader:
49+
42− * JATS reader: handle "label" element in section title (#6288).
50+ + Handle "label" element in section title (#6288).
51+ + Parse abstract element into metadata field of same name
52+ (#6480, Albert Krewinkel).
43
53
44 * Jira reader (Albert Krewinkel):
54 * Jira reader (Albert Krewinkel):
45
55
@@ -80,6 +90,9 @@
80 + Fix inline code in lists (#6284, Nikolay Yakimov).
90 + Fix inline code in lists (#6284, Nikolay Yakimov).
81 Previously inline code containing list markers was sometimes
91 Previously inline code containing list markers was sometimes
82 parsed incorrectly.
92 parsed incorrectly.
93+ + Don't require blank line after grid table (#6481).
94+ This allows grid tables to be enclosed in fenced divs with no
95+ intervening blank lines.
83
96
84 * LaTeX reader:
97 * LaTeX reader:
85
98
@@ -93,6 +106,41 @@
93 * Org reader (Albert Krewinkel):
106 * Org reader (Albert Krewinkel):
94
107
95 + Recognize images with uppercase extensions (#6472).
108 + Recognize images with uppercase extensions (#6472).
109+ + Keep unknown keyword lines as raw org. The lines of unknown
110+ keywords, like `#+SOMEWORD: value` are no longer read as metadata,
111+ but kept as raw `org` blocks. This ensures that more information
112+ is retained when round-tripping org-mode files; additionally,
113+ this change makes it possible to support non-standard org
114+ extensions via filters.
115+ + Unify keyword handling. Handling of export settings and other
116+ keywords (like `#+LINK`) has been combined and unified.
117+ + Support `LATEX_HEADER_EXTRA` and `HTML_HEAD_EXTRA`
118+ settings. These export settings are treated like their non-extra
119+ counterparts, i.e., the values are added to the `header-includes`
120+ metadata list.
121+ + Allow multiple `#+SUBTITLE` export settings. The values of all
122+ lines are read as inlines and collected in the `subtitle`
123+ metadata field.
124+ + Read `#+INSTITUTE` values as text with markup. The value is
125+ stored in the `institute` metadata field and used in the
126+ default beamer presentation template.
127+ + The behavior of the `#+AUTHOR` and `#+KEYWORD` export
128+ settings has changed: Org now allows multiple such lines
129+ and adds a space between the contents of each line. Pandoc
130+ now always parses these settings as meta inlines; setting
131+ values are no longer treated as comma-separated lists.
132+ Note that a Lua filter can be used to restore the previous
133+ behavior.
134+ + Read description lines as inlines (#6485). `#+DESCRIPTION` lines
135+ are now treated as text with markup. If multiple such
136+ lines are given, then all lines are read and separated by soft
137+ linebreaks.
138+ + Honor tex export option (#4070). The `tex` export option can be set
139+ with `#+OPTION: tex:nil` and allows three settings:
140+ `t` (the default) causes LaTeX fragments to be parsed as TeX or added
141+ as raw TeX. `nil` removes all LaTeX fragments from the document.
142+ `verbatim` treats LaTeX as text.
143+
96
144
97 * RST reader:
145 * RST reader:
98
146
@@ -244,6 +292,7 @@
244 + Use `--enable-local-file-access` in invoking `wkhtmltopdf` (#6474).
292 + Use `--enable-local-file-access` in invoking `wkhtmltopdf` (#6474).
245 `wkhtmltopdf` changed in recent versions to require this for
293 `wkhtmltopdf` changed in recent versions to require this for
246 access to local files. This fixes PDF via HTML5 with `--css`.
294 access to local files. This fixes PDF via HTML5 with `--css`.
295+ + Send verbose output to stderr, not stdout (#6483).
247
296
248 * Text.Pandoc.MIME: Fix MIME type for TrueType fonts in EPUBs
297 * Text.Pandoc.MIME: Fix MIME type for TrueType fonts in EPUBs
249 (#6464, Michael Reed).
298 (#6464, Michael Reed).
@@ -317,6 +366,8 @@
317
366
318 * Remove unnecessary hlint ignores (#6341, Joseph C. Sible).
367 * Remove unnecessary hlint ignores (#6341, Joseph C. Sible).
319
368
369+ * Remove obsolete RelaxedPolyRec extension (#6487, Nikolay Yakimov).
370+
320 * trypandoc improvements (Mike Tzou):
371 * trypandoc improvements (Mike Tzou):
321
372
322 + Add standalone option to the command text (#6210).
373 + Add standalone option to the command text (#6210).
@@ -335,6 +386,11 @@
335 + Update links to reveal.js documentation (#6386, Salim B).
386 + Update links to reveal.js documentation (#6386, Salim B).
336 + Separate adjacent verbatim code blocks (#6307, tom-audm).
387 + Separate adjacent verbatim code blocks (#6307, tom-audm).
337
388
389+ * org.md:
390+
391+ + Document behavior of `smart` extension (#4387, Albert Krewinkel).
392+ + Describe all supported export options in detail.
393+
338 * lua-filters.md:
394 * lua-filters.md:
339
395
340 + Fix description of BulletList Lua type (Levi Gruspe).
396 + Fix description of BulletList Lua type (Levi Gruspe).
data/templates/default.latex+3
@@ -339,6 +339,9 @@ $if(babel-newcommands)$
339$endif$
339$endif$
340\fi
340\fi
341$endif$
341$endif$
342+\ifluatex
343+ \usepackage{selnolig} % disable illegal ligatures
344+\fi
342$if(dir)$
345$if(dir)$
343\ifxetex
346\ifxetex
344 % Load bidi as late as possible as it modifies e.g. graphicx
347 % Load bidi as late as possible as it modifies e.g. graphicx
doc/lua-filters.md+4−4
@@ -138,7 +138,7 @@ elements.
138
138
139## Filters on element sequences
139## Filters on element sequences
140
140
141−For some filtering tasks, the it is necessary to know the order
141+For some filtering tasks, it is necessary to know the order
142in which elements occur in the document. It is not enough then to
142in which elements occur in the document. It is not enough then to
143inspect a single element at a time.
143inspect a single element at a time.
144
144
@@ -1127,7 +1127,7 @@ A [table cell]{#type-table-cell} is a list of blocks.
1127
1127
1128*[Alignment]{#type-alignment}* is a string value indicating the
1128*[Alignment]{#type-alignment}* is a string value indicating the
1129horizontal alignment of a table column. `AlignLeft`,
1129horizontal alignment of a table column. `AlignLeft`,
1130−`AlignRight`, and `AlignCenter` leads cell content tob be
1130+`AlignRight`, and `AlignCenter` leads cell content to be
1131left-aligned, right-aligned, and centered, respectively. The
1131left-aligned, right-aligned, and centered, respectively. The
1132default alignment is `AlignDefault` (often equivalent to
1132default alignment is `AlignDefault` (often equivalent to
1133centered).
1133centered).
@@ -3035,7 +3035,7 @@ methods and convenience functions.
3035[`pandoc.List:insert ([pos], value)`]{#pandoc.list:insert}
3035[`pandoc.List:insert ([pos], value)`]{#pandoc.list:insert}
3036
3036
3037: Inserts element `value` at position `pos` in list, shifting
3037: Inserts element `value` at position `pos` in list, shifting
3038− elements to the next-greater indix if necessary.
3038+ elements to the next-greater index if necessary.
3039
3039
3040 This function is identical to
3040 This function is identical to
3041 [`table.insert`](https://www.lua.org/manual/5.3/manual.html#6.6).
3041 [`table.insert`](https://www.lua.org/manual/5.3/manual.html#6.6).
@@ -3082,7 +3082,7 @@ methods and convenience functions.
3082 Parameters:
3082 Parameters:
3083
3083
3084 `pos`:
3084 `pos`:
3085− : position of the list value that will be remove; defaults
3085+ : position of the list value that will be removed; defaults
3086 to the index of the last element
3086 to the index of the last element
3087
3087
3088 Returns: the removed element
3088 Returns: the removed element
doc/org.md+15−11
@@ -14,13 +14,13 @@ The following export keywords are supported:
14
14
15- AUTHOR: comma-separated list of author(s); fully supported.
15- AUTHOR: comma-separated list of author(s); fully supported.
16
16
17−- CREATOR: output generator; passed as metadata entry, but
17+- CREATOR: output generator; passed as plain-text metadata entry
18− ignored by most output formats.
18+ `creator`, but not used by any default templates.
19
19
20- DATE: creation or publication date; well supported by pandoc.
20- DATE: creation or publication date; well supported by pandoc.
21
21
22−- EMAIL: author email address; passed as metadata entry, but not
22+- EMAIL: author email address; passed as plain-text metadata
23− included in most output formats.
23+ field `email`, but not used by any default templates.
24
24
25- LANGUAGE: currently unsupported; use `#+LANG:` instead.
25- LANGUAGE: currently unsupported; use `#+LANG:` instead.
26
26
@@ -51,11 +51,12 @@ occur.
51
51
52 Pandoc follows the LaTeX exporter in that it allows markup in
52 Pandoc follows the LaTeX exporter in that it allows markup in
53 the description. In contrast, the Org-mode HTML exporter treats
53 the description. In contrast, the Org-mode HTML exporter treats
54− reads the description as plain text.
54+ the description as plain text.
55
55
56−- LATEX_HEADER: arbitrary lines to add to the document's preamble.
56+- LATEX\_HEADER and LATEX_HEADER_EXTRA: arbitrary lines to add to
57− Contrary to Org-mode, these lines are not inserted before the
57+ the document's preamble. Contrary to Org-mode, these lines are
58− hyperref settings, but close to the end of the preamble.
58+ not inserted before the hyperref settings, but close to the end
59+ of the preamble.
59
60
60 The contents of this option are stored as a list of raw LaTeX
61 The contents of this option are stored as a list of raw LaTeX
61 lines in the `header-includes` metadata field.
62 lines in the `header-includes` metadata field.
@@ -74,10 +75,13 @@ occur.
74
75
75- SUBTITLE: the document's subtitle; fully supported.
76- SUBTITLE: the document's subtitle; fully supported.
76
77
78+ The content of this option is stored as inlines in the
79+ `subtitle` metadata field.
80+
77−- HTML_HEAD: arbitrary lines to add to the HTML document's head;
81+- HTML\_HEAD and HTML\_HEAD\_EXTRA: arbitrary lines to add to the
78− fully supported.
82+ HTML document's head; fully supported.
79
83
80− The contents of this option are stored as a list of raw HTML
84+ The contents of these options are stored as a list of raw HTML
81 lines in the `header-includes` metadata field.
85 lines in the `header-includes` metadata field.
82
86
83Pandoc-specific options
87Pandoc-specific options
man/pandoc.1+111−25
@@ -1,7 +1,7 @@
1.\"t
1.\"t
2−.\" Automatically generated by Pandoc 2.9.2
2+.\" Automatically generated by Pandoc 2.10
3.\"
3.\"
4−.TH "Pandoc User\[aq]s Guide" "" "March 23, 2020" "pandoc 2.9.2.1" ""
4+.TH "Pandoc User\[aq]s Guide" "" "June 29, 2020" "pandoc 2.10" ""
5.hy
5.hy
6.SH NAME
6.SH NAME
7pandoc - general markup converter
7pandoc - general markup converter
@@ -255,7 +255,7 @@ if you need extensions not supported in \f[C]gfm\f[R].
255.IP \[bu] 2
255.IP \[bu] 2
256\f[C]jats\f[R] (JATS XML)
256\f[C]jats\f[R] (JATS XML)
257.IP \[bu] 2
257.IP \[bu] 2
258−\f[C]jira\f[R] (Jira wiki markup)
258+\f[C]jira\f[R] (Jira/Confluence wiki markup)
259.IP \[bu] 2
259.IP \[bu] 2
260\f[C]json\f[R] (JSON version of native AST)
260\f[C]json\f[R] (JSON version of native AST)
261.IP \[bu] 2
261.IP \[bu] 2
@@ -352,7 +352,7 @@ HTML5/XHTML polyglot markup)
352.IP \[bu] 2
352.IP \[bu] 2
353\f[C]jats\f[R] (alias for \f[C]jats_archiving\f[R])
353\f[C]jats\f[R] (alias for \f[C]jats_archiving\f[R])
354.IP \[bu] 2
354.IP \[bu] 2
355−\f[C]jira\f[R] (Jira wiki markup)
355+\f[C]jira\f[R] (Jira/Confluence wiki markup)
356.IP \[bu] 2
356.IP \[bu] 2
357\f[C]json\f[R] (JSON version of native AST)
357\f[C]json\f[R] (JSON version of native AST)
358.IP \[bu] 2
358.IP \[bu] 2
@@ -481,7 +481,6 @@ eval \[dq]$(pandoc --bash-completion)\[dq]
481.TP
481.TP
482\f[B]\f[CB]--verbose\f[B]\f[R]
482\f[B]\f[CB]--verbose\f[B]\f[R]
483Give verbose debugging output.
483Give verbose debugging output.
484−Currently this only has an effect with PDF output.
485.TP
484.TP
486\f[B]\f[CB]--quiet\f[B]\f[R]
485\f[B]\f[CB]--quiet\f[B]\f[R]
487Suppress warning messages.
486Suppress warning messages.
@@ -936,6 +935,11 @@ making HTTP requests (for example, when a URL is given on the command
936line, or when resources used in a document must be downloaded).
935line, or when resources used in a document must be downloaded).
937If you\[aq]re behind a proxy, you also need to set the environment
936If you\[aq]re behind a proxy, you also need to set the environment
938variable \f[C]http_proxy\f[R] to \f[C]http://...\f[R].
937variable \f[C]http_proxy\f[R] to \f[C]http://...\f[R].
938+.TP
939+\[ga]--no-check-certificate
940+Disable the certificate verification to allow access to unsecure HTTP
941+resources (for example when the certificate is no longer valid or self
942+signed).
939.SS Options affecting specific writers
943.SS Options affecting specific writers
940.TP
944.TP
941\f[B]\f[CB]--self-contained\f[B]\f[R]
945\f[B]\f[CB]--self-contained\f[B]\f[R]
@@ -1366,7 +1370,8 @@ depending on the output format specified using \f[C]-t/--to\f[R]:
1366\f[C]-t context\f[R]: \f[C]context\f[R]
1370\f[C]-t context\f[R]: \f[C]context\f[R]
1367.IP \[bu] 2
1371.IP \[bu] 2
1368\f[C]-t html\f[R]: \f[C]wkhtmltopdf\f[R] (other options:
1372\f[C]-t html\f[R]: \f[C]wkhtmltopdf\f[R] (other options:
1369−\f[C]prince\f[R], \f[C]weasyprint\f[R])
1373+\f[C]prince\f[R], \f[C]weasyprint\f[R]; see print-css.rocks for a good
1374+introduction to PDF generation from HTML/CSS.)
1370.IP \[bu] 2
1375.IP \[bu] 2
1371\f[C]-t ms\f[R]: \f[C]pdfroff\f[R]
1376\f[C]-t ms\f[R]: \f[C]pdfroff\f[R]
1372.RE
1377.RE
@@ -2053,20 +2058,30 @@ ${ endfor }
2053.fi
2058.fi
2054.SS Partials
2059.SS Partials
2055.PP
2060.PP
2056−Partials (subtemplates stored in different files) may be included using
2061+Partials (subtemplates stored in different files) may be included by
2057−the syntax
2062+using the name of the partial, followed by \f[C]()\f[R], for example:
2063+.IP
2064+.nf
2065+\f[C]
2066+${ styles() }
2067+\f[R]
2068+.fi
2069+.PP
2070+Partials will be sought in the directory containing the main template.
2071+The file name will be assumed to have the same extension as the main
2072+template if it lacks an extension.
2073+When calling the partial, the full name including file extension can
2074+also be used:
2058.IP
2075.IP
2059.nf
2076.nf
2060\f[C]
2077\f[C]
2061−${ boilerplate() }
2078+${ styles.html() }
2062\f[R]
2079\f[R]
2063.fi
2080.fi
2064.PP
2081.PP
2065−Partials will be sought in the directory containing the main template,
2082+(If a partial is not found in the directory of the template, it will
2066−and will be assumed to have the same extension as the main template if
2067−they lack an explicit extension.
2068−(If the partials are not found here, they will also be sought in the
2069−\f[C]templates\f[R] subdirectory of the user data directory.)
2083+also be sought in the \f[C]templates\f[R] subdirectory of the user data
2084+directory.)
2070.PP
2085.PP
2071Partials may optionally be applied to variables using a colon:
2086Partials may optionally be applied to variables using a colon:
2072.IP
2087.IP
@@ -2232,6 +2247,18 @@ for a textual value, number of elements for a map or array.
2232\f[C]reverse\f[R]: Reverses a textual value or array, and has no effect
2247\f[C]reverse\f[R]: Reverses a textual value or array, and has no effect
2233on other values.
2248on other values.
2234.IP \[bu] 2
2249.IP \[bu] 2
2250+\f[C]first\f[R]: Returns the first value of an array, if applied to a
2251+non-empty array; otherwise returns the original value.
2252+.IP \[bu] 2
2253+\f[C]last\f[R]: Returns the last value of an array, if applied to a
2254+non-empty array; otherwise returns the original value.
2255+.IP \[bu] 2
2256+\f[C]rest\f[R]: Returns all but the first value of an array, if applied
2257+to a non-empty array; otherwise returns the original value.
2258+.IP \[bu] 2
2259+\f[C]allbutlast\f[R]: Returns all but the last value of an array, if
2260+applied to a non-empty array; otherwise returns the original value.
2261+.IP \[bu] 2
2235\f[C]chomp\f[R]: Removes trailing newlines (and breakable space).
2262\f[C]chomp\f[R]: Removes trailing newlines (and breakable space).
2236.IP \[bu] 2
2263.IP \[bu] 2
2237\f[C]nowrap\f[R]: Disables line wrapping on breakable spaces.
2264\f[C]nowrap\f[R]: Disables line wrapping on breakable spaces.
@@ -2398,7 +2425,8 @@ To turn off boolean flags that default to true in reveal.js, use
2398\f[C]0\f[R].
2425\f[C]0\f[R].
2399.TP
2426.TP
2400\f[B]\f[CB]revealjs-url\f[B]\f[R]
2427\f[B]\f[CB]revealjs-url\f[B]\f[R]
2401−base URL for reveal.js documents (defaults to \f[C]reveal.js\f[R])
2428+base URL for reveal.js documents (defaults to
2429+\f[C]https://unpkg.com/reveal.js\[at]\[ha]4/\f[R])
2402.TP
2430.TP
2403\f[B]\f[CB]s5-url\f[B]\f[R]
2431\f[B]\f[CB]s5-url\f[B]\f[R]
2404base URL for S5 documents (defaults to \f[C]s5/default\f[R])
2432base URL for S5 documents (defaults to \f[C]s5/default\f[R])
@@ -3247,7 +3275,7 @@ This extension can be enabled/disabled for the following formats:
3247.TP
3275.TP
3248output formats
3276output formats
3249\f[C]odt\f[R], \f[C]opendocument\f[R]
3277\f[C]odt\f[R], \f[C]opendocument\f[R]
3250−.SS Extension: \f[C]styles\f[R]
3278+.SS Extension: \f[C]styles\f[R] {#ext-styles}
3251.PP
3279.PP
3252When converting from docx, read all docx styles as divs (for paragraph
3280When converting from docx, read all docx styles as divs (for paragraph
3253styles) and spans (for character styles) regardless of whether pandoc
3281styles) and spans (for character styles) regardless of whether pandoc
@@ -4404,7 +4432,7 @@ orange|3.09
4404.PP
4432.PP
4405The cells of pipe tables cannot contain block elements like paragraphs
4433The cells of pipe tables cannot contain block elements like paragraphs
4406and lists, and cannot span multiple lines.
4434and lists, and cannot span multiple lines.
4407−If a pipe table contains a row whose printable content is wider than the
4435+If a pipe table contains a row whose Markdown content is wider than the
4408column width (see \f[C]--columns\f[R]), then the table will take up the
4436column width (see \f[C]--columns\f[R]), then the table will take up the
4409full text width and the cell contents will wrap, with the relative cell
4437full text width and the cell contents will wrap, with the relative cell
4410widths determined by the number of dashes in the line separating the
4438widths determined by the number of dashes in the line separating the
@@ -4454,7 +4482,11 @@ no author, you need a blank line:
4454\f[C]
4482\f[C]
4455%
4483%
4456% Author
4484% Author
4457−
4485+\f[R]
4486+.fi
4487+.IP
4488+.nf
4489+\f[C]
4458% My title
4490% My title
4459%
4491%
4460% June 15, 2006
4492% June 15, 2006
@@ -4479,9 +4511,17 @@ So, all of the following are equivalent:
4479\f[C]
4511\f[C]
4480% Author One
4512% Author One
4481 Author Two
4513 Author Two
4482−
4514+\f[R]
4515+.fi
4516+.IP
4517+.nf
4518+\f[C]
4483% Author One; Author Two
4519% Author One; Author Two
4484−
4520+\f[R]
4521+.fi
4522+.IP
4523+.nf
4524+\f[C]
4485% Author One;
4525% Author One;
4486 Author Two
4526 Author Two
4487\f[R]
4527\f[R]
@@ -5398,11 +5438,12 @@ For example:
5398\f[R]
5438\f[R]
5399.fi
5439.fi
5400.IP \[bu] 2
5440.IP \[bu] 2
5401−Dimensions are converted to inches for output in page-based formats like
5441+Dimensions may be converted to a form that is compatible with the output
5402−LaTeX.
5442+format (for example, dimensions given in pixels will be converted to
5403−Dimensions are converted to pixels for output in HTML-like formats.
5443+inches when converting HTML to LaTeX).
5404−Use the \f[C]--dpi\f[R] option to specify the number of pixels per inch.
5444+Conversion between pixels and physical measurements is affected by the
5405−The default is 96dpi.
5445+\f[C]--dpi\f[R] option (by default, 96 dpi is assumed, unless the image
5446+itself contains dpi information).
5406.IP \[bu] 2
5447.IP \[bu] 2
5407The \f[C]%\f[R] unit is generally relative to some available space.
5448The \f[C]%\f[R] unit is generally relative to some available space.
5408For example the above example will render to the following.
5449For example the above example will render to the following.
@@ -6371,6 +6412,51 @@ contents...
6371::::::::::::::
6412::::::::::::::
6372\f[R]
6413\f[R]
6373.fi
6414.fi
6415+.SS Additional columns attributes in beamer
6416+.PP
6417+The div containers with classes \f[C]columns\f[R] and \f[C]column\f[R]
6418+can optionally have an \f[C]align\f[R] attribute.
6419+The class \f[C]columns\f[R] can optionally have a \f[C]totalwidth\f[R]
6420+attribute or an \f[C]onlytextwidth\f[R] class.
6421+.IP
6422+.nf
6423+\f[C]
6424+:::::::::::::: {.columns align=center totalwidth=8em}
6425+::: {.column width=\[dq]40%\[dq]}
6426+contents...
6427+:::
6428+::: {.column width=\[dq]60%\[dq] align=bottom}
6429+contents...
6430+:::
6431+::::::::::::::
6432+\f[R]
6433+.fi
6434+.PP
6435+The \f[C]align\f[R] attributes on \f[C]columns\f[R] and \f[C]column\f[R]
6436+can be used with the values \f[C]top\f[R], \f[C]top-baseline\f[R],
6437+\f[C]center\f[R] and \f[C]bottom\f[R] to vertically align the columns.
6438+It defaults to \f[C]top\f[R] in \f[C]columns\f[R].
6439+.PP
6440+The \f[C]totalwidth\f[R] attribute limits the width of the columns to
6441+the given value.
6442+.IP
6443+.nf
6444+\f[C]
6445+:::::::::::::: {.columns align=top .onlytextwidth}
6446+::: {.column width=\[dq]40%\[dq] align=center}
6447+contents...
6448+:::
6449+::: {.column width=\[dq]60%\[dq]}
6450+contents...
6451+:::
6452+::::::::::::::
6453+\f[R]
6454+.fi
6455+.PP
6456+The class \f[C]onlytextwidth\f[R] sets the \f[C]totalwidth\f[R] to
6457+\f[C]\[rs]textwidth\f[R].
6458+.PP
6459+See Section 12.7 of the Beamer User\[aq]s Guide for more details.
6374.SS Frame attributes in beamer
6460.SS Frame attributes in beamer
6375.PP
6461.PP
6376Sometimes it is necessary to add the LaTeX \f[C][fragile]\f[R] option to
6462Sometimes it is necessary to add the LaTeX \f[C][fragile]\f[R] option to
pandoc.cabal+5−2
@@ -11,7 +11,7 @@ bug-reports: https://github.com/jgm/pandoc/issues
11stability: alpha
11stability: alpha
12homepage: https://pandoc.org
12homepage: https://pandoc.org
13category: Text
13category: Text
14−tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,
14+tested-with: GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,
15 GHC == 8.8.3, GHC == 8.10.1
15 GHC == 8.8.3, GHC == 8.10.1
16synopsis: Conversion between markup formats
16synopsis: Conversion between markup formats
17description: Pandoc is a Haskell library for converting from one markup
17description: Pandoc is a Haskell library for converting from one markup
@@ -421,8 +421,10 @@ library
421 deepseq >= 1.3 && < 1.5,
421 deepseq >= 1.3 && < 1.5,
422 JuicyPixels >= 3.1.6.1 && < 3.4,
422 JuicyPixels >= 3.1.6.1 && < 3.4,
423 Glob >= 0.7 && < 0.11,
423 Glob >= 0.7 && < 0.11,
424− cmark-gfm >= 0.2 && < 0.3,
425 doctemplates >= 0.8.2 && < 0.9,
424 doctemplates >= 0.8.2 && < 0.9,
425+ commonmark-pandoc >= 0.1,
426+ commonmark >= 0.1,
427+ commonmark-extensions >= 0.1,
426 network-uri >= 2.6 && < 2.7,
428 network-uri >= 2.6 && < 2.7,
427 network >= 2.6,
429 network >= 2.6,
428 connection >= 0.3.1,
430 connection >= 0.3.1,
@@ -816,6 +818,7 @@ test-suite test-pandoc
816 Tests.Writers.FB2
818 Tests.Writers.FB2
817 Tests.Writers.Powerpoint
819 Tests.Writers.Powerpoint
818 Tests.Writers.OOXML
820 Tests.Writers.OOXML
821+ Tests.Writers.Ms
819 if os(windows)
822 if os(windows)
820 cpp-options: -D_WINDOWS
823 cpp-options: -D_WINDOWS
821 default-language: Haskell2010
824 default-language: Haskell2010
src/Text/Pandoc/Extensions.hs+55−12
@@ -150,6 +150,7 @@ data Extension =
150 | Ext_tex_math_single_backslash -- ^ TeX math btw \(..\) \[..\]
150 | Ext_tex_math_single_backslash -- ^ TeX math btw \(..\) \[..\]
151 | Ext_yaml_metadata_block -- ^ YAML metadata block
151 | Ext_yaml_metadata_block -- ^ YAML metadata block
152 | Ext_gutenberg -- ^ Use Project Gutenberg conventions for plain
152 | Ext_gutenberg -- ^ Use Project Gutenberg conventions for plain
153+ | Ext_attributes -- ^ Generic attribute syntax
153 deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
154 deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
154
155
155-- | Extensions to be used with pandoc-flavored markdown.
156-- | Extensions to be used with pandoc-flavored markdown.
@@ -242,21 +243,15 @@ phpMarkdownExtraExtensions = extensionsFromList
242-- | Extensions to be used with github-flavored markdown.
243-- | Extensions to be used with github-flavored markdown.
243githubMarkdownExtensions :: Extensions
244githubMarkdownExtensions :: Extensions
244githubMarkdownExtensions = extensionsFromList
245githubMarkdownExtensions = extensionsFromList
245− [ Ext_all_symbols_escapable
246− , Ext_pipe_tables
246+ [ Ext_pipe_tables
247 , Ext_raw_html
247 , Ext_raw_html
248− , Ext_fenced_code_blocks
248+ , Ext_native_divs
249 , Ext_auto_identifiers
249 , Ext_auto_identifiers
250 , Ext_gfm_auto_identifiers
250 , Ext_gfm_auto_identifiers
251− , Ext_backtick_code_blocks
252 , Ext_autolink_bare_uris
251 , Ext_autolink_bare_uris
253− , Ext_space_in_atx_header
254− , Ext_intraword_underscores
255 , Ext_strikeout
252 , Ext_strikeout
256 , Ext_task_lists
253 , Ext_task_lists
257 , Ext_emoji
254 , Ext_emoji
258− , Ext_lists_without_preceding_blankline
259− , Ext_shortcut_reference_links
260 ]
255 ]
261
256
262-- | Extensions to be used with multimarkdown.
257-- | Extensions to be used with multimarkdown.
@@ -308,7 +303,16 @@ getDefaultExtensions :: T.Text -> Extensions
308getDefaultExtensions "markdown_strict" = strictExtensions
303getDefaultExtensions "markdown_strict" = strictExtensions
309getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
304getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
310getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
305getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
311−getDefaultExtensions "markdown_github" = githubMarkdownExtensions
306+getDefaultExtensions "markdown_github" = githubMarkdownExtensions <>
307+ extensionsFromList
308+ [ Ext_all_symbols_escapable
309+ , Ext_backtick_code_blocks
310+ , Ext_fenced_code_blocks
311+ , Ext_space_in_atx_header
312+ , Ext_intraword_underscores
313+ , Ext_lists_without_preceding_blankline
314+ , Ext_shortcut_reference_links
315+ ]
312getDefaultExtensions "markdown" = pandocExtensions
316getDefaultExtensions "markdown" = pandocExtensions
313getDefaultExtensions "ipynb" =
317getDefaultExtensions "ipynb" =
314 extensionsFromList
318 extensionsFromList
@@ -335,6 +339,29 @@ getDefaultExtensions "plain" = plainExtensions
335getDefaultExtensions "gfm" = githubMarkdownExtensions
339getDefaultExtensions "gfm" = githubMarkdownExtensions
336getDefaultExtensions "commonmark" = extensionsFromList
340getDefaultExtensions "commonmark" = extensionsFromList
337 [Ext_raw_html]
341 [Ext_raw_html]
342+getDefaultExtensions "commonmark_x" = extensionsFromList
343+ [ Ext_pipe_tables
344+ , Ext_raw_html
345+ , Ext_auto_identifiers
346+ , Ext_strikeout
347+ , Ext_task_lists
348+ , Ext_emoji
349+ , Ext_pipe_tables
350+ , Ext_raw_html
351+ , Ext_raw_tex -- only supported in writer (for math)
352+ , Ext_smart
353+ , Ext_tex_math_dollars
354+ , Ext_superscript
355+ , Ext_subscript
356+ , Ext_definition_lists
357+ , Ext_footnotes
358+ , Ext_fancy_lists
359+ , Ext_fenced_divs
360+ , Ext_bracketed_spans
361+ , Ext_raw_attribute
362+ , Ext_implicit_header_references
363+ , Ext_attributes
364+ ]
338getDefaultExtensions "org" = extensionsFromList
365getDefaultExtensions "org" = extensionsFromList
339 [Ext_citations,
366 [Ext_citations,
340 Ext_auto_identifiers]
367 Ext_auto_identifiers]
@@ -430,16 +457,32 @@ getAllExtensions f = universalExtensions <> getAll f
430 [ Ext_amuse ]
457 [ Ext_amuse ]
431 getAll "asciidoc" = autoIdExtensions
458 getAll "asciidoc" = autoIdExtensions
432 getAll "plain" = allMarkdownExtensions
459 getAll "plain" = allMarkdownExtensions
433− getAll "gfm" = githubMarkdownExtensions <>
460+ getAll "gfm" = getAll "commonmark"
461+ getAll "commonmark" =
434 autoIdExtensions <>
462 autoIdExtensions <>
435 extensionsFromList
463 extensionsFromList
464+ [ Ext_pipe_tables
465+ , Ext_autolink_bare_uris
466+ , Ext_strikeout
467+ , Ext_task_lists
468+ , Ext_emoji
436− [ Ext_raw_html
469+ , Ext_raw_html
437 , Ext_raw_tex -- only supported in writer (for math)
470 , Ext_raw_tex -- only supported in writer (for math)
438 , Ext_implicit_figures
471 , Ext_implicit_figures
439 , Ext_hard_line_breaks
472 , Ext_hard_line_breaks
440 , Ext_smart
473 , Ext_smart
474+ , Ext_tex_math_dollars
475+ , Ext_superscript
476+ , Ext_subscript
477+ , Ext_definition_lists
478+ , Ext_footnotes
479+ , Ext_fancy_lists
480+ , Ext_fenced_divs
481+ , Ext_bracketed_spans
482+ , Ext_raw_attribute
483+ , Ext_implicit_header_references
484+ , Ext_attributes
441 ]
485 ]
442− getAll "commonmark" = getAll "gfm"
443 getAll "org" = autoIdExtensions <>
486 getAll "org" = autoIdExtensions <>
444 extensionsFromList
487 extensionsFromList
445 [ Ext_citations
488 [ Ext_citations
src/Text/Pandoc/Readers.hs+1
@@ -111,6 +111,7 @@ readers = [ ("native" , TextReader readNative)
111 ,("markdown_github" , TextReader readMarkdown)
111 ,("markdown_github" , TextReader readMarkdown)
112 ,("markdown_mmd", TextReader readMarkdown)
112 ,("markdown_mmd", TextReader readMarkdown)
113 ,("commonmark" , TextReader readCommonMark)
113 ,("commonmark" , TextReader readCommonMark)
114+ ,("commonmark_x" , TextReader readCommonMark)
114 ,("creole" , TextReader readCreole)
115 ,("creole" , TextReader readCreole)
115 ,("dokuwiki" , TextReader readDokuWiki)
116 ,("dokuwiki" , TextReader readDokuWiki)
116 ,("gfm" , TextReader readCommonMark)
117 ,("gfm" , TextReader readCommonMark)
src/Text/Pandoc/Readers/CommonMark.hs+40−198
@@ -1,4 +1,5 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
2{-# LANGUAGE ViewPatterns #-}
3{-# LANGUAGE ViewPatterns #-}
3{- |
4{- |
4 Module : Text.Pandoc.Readers.CommonMark
5 Module : Text.Pandoc.Readers.CommonMark
@@ -16,209 +17,50 @@ CommonMark is a strongly specified variant of Markdown: http://commonmark.org.
16module Text.Pandoc.Readers.CommonMark (readCommonMark)
17module Text.Pandoc.Readers.CommonMark (readCommonMark)
17where
18where
18
19
19−import CMarkGFM
20+import Commonmark
20−import Control.Monad.State
21+import Commonmark.Extensions
21−import qualified Data.Set as Set
22+import Commonmark.Pandoc
22import Data.Text (Text)
23import Data.Text (Text)
23−import qualified Data.Text as T
24import Text.Pandoc.Class.PandocMonad (PandocMonad)
24import Text.Pandoc.Class.PandocMonad (PandocMonad)
25import Text.Pandoc.Definition
25import Text.Pandoc.Definition
26−import Text.Pandoc.Emoji (emojiToInline)
26+import Text.Pandoc.Builder as B
27import Text.Pandoc.Options
27import Text.Pandoc.Options
28−import Text.Pandoc.Shared (uniqueIdent, taskListItemFromAscii)
28+import Text.Pandoc.Error
29−import Text.Pandoc.Walk (walkM)
29+import Control.Monad.Except
30+import Data.Functor.Identity (runIdentity)
30
31
31-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
32-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
32readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
33readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
33−readCommonMark opts s = return $
34+readCommonMark opts s = do
34− (if isEnabled Ext_auto_identifiers opts
35+ let res = runIdentity $
35− then addHeaderIdentifiers opts
36+ commonmarkWith (foldr (<>) defaultSyntaxSpec exts) "input" s
36− else id) $
37+ case res of
37− nodeToPandoc opts $ commonmarkToNode opts' exts s
38+ Left err -> throwError $ PandocParsecError s err
39+ Right (Cm bls :: Cm () Blocks) -> return $ B.doc bls
40+ where
41+ exts = [ hardLineBreaksSpec | isEnabled Ext_hard_line_breaks opts ] ++
38− where opts' = [ optSmart | isEnabled Ext_smart opts ]
42+ [ smartPunctuationSpec | isEnabled Ext_smart opts ] ++
39− exts = [ extStrikethrough | isEnabled Ext_strikeout opts ] ++
43+ [ strikethroughSpec | isEnabled Ext_strikeout opts ] ++
44+ [ superscriptSpec | isEnabled Ext_superscript opts ] ++
45+ [ subscriptSpec | isEnabled Ext_subscript opts ] ++
46+ [ mathSpec | isEnabled Ext_tex_math_dollars opts ] ++
47+ [ fancyListSpec | isEnabled Ext_fancy_lists opts ] ++
48+ [ fencedDivSpec | isEnabled Ext_fenced_divs opts ] ++
49+ [ bracketedSpanSpec | isEnabled Ext_bracketed_spans opts ] ++
50+ [ rawAttributeSpec | isEnabled Ext_raw_attribute opts ] ++
51+ [ attributesSpec | isEnabled Ext_attributes opts ] ++
40− [ extTable | isEnabled Ext_pipe_tables opts ] ++
52+ [ pipeTableSpec | isEnabled Ext_pipe_tables opts ] ++
41− [ extAutolink | isEnabled Ext_autolink_bare_uris opts ]
53+ [ autolinkSpec | isEnabled Ext_autolink_bare_uris opts ] ++
54+ [ emojiSpec | isEnabled Ext_emoji opts ] ++
55+ [ autoIdentifiersSpec
56+ | isEnabled Ext_gfm_auto_identifiers opts
57+ , not (isEnabled Ext_ascii_identifiers opts) ] ++
58+ [ autoIdentifiersAsciiSpec
59+ | isEnabled Ext_gfm_auto_identifiers opts
60+ , isEnabled Ext_ascii_identifiers opts ] ++
61+ [ implicitHeadingReferencesSpec
62+ | isEnabled Ext_implicit_header_references opts ] ++
63+ [ footnoteSpec | isEnabled Ext_footnotes opts ] ++
64+ [ definitionListSpec | isEnabled Ext_definition_lists opts ] ++
65+ [ taskListSpec | isEnabled Ext_task_lists opts ]
42
66
43−convertEmojis :: Text -> [Inline]
44−convertEmojis s@(T.uncons -> Just (':',xs)) =
45− case T.break (==':') xs of
46− (ys, T.uncons -> Just (':',zs)) ->
47− case emojiToInline ys of
48− Just em -> em : convertEmojis zs
49− Nothing -> Str (":" <> ys) : convertEmojis (":" <> zs)
50− _ -> [Str s]
51−convertEmojis s =
52− case T.break (==':') s of
53− ("","") -> []
54− (_,"") -> [Str s]
55− (xs,ys) -> Str xs : convertEmojis ys
56−
57−addHeaderIdentifiers :: ReaderOptions -> Pandoc -> Pandoc
58−addHeaderIdentifiers opts doc = evalState (walkM (addHeaderId opts) doc) mempty
59−
60−addHeaderId :: ReaderOptions -> Block -> State (Set.Set Text) Block
61−addHeaderId opts (Header lev (_,classes,kvs) ils) = do
62− ids <- get
63− let ident = uniqueIdent (readerExtensions opts) ils ids
64− modify (Set.insert ident)
65− return $ Header lev (ident,classes,kvs) ils
66−addHeaderId _ x = return x
67−
68−nodeToPandoc :: ReaderOptions -> Node -> Pandoc
69−nodeToPandoc opts (Node _ DOCUMENT nodes) =
70− Pandoc nullMeta $ foldr (addBlock opts) [] nodes
71−nodeToPandoc opts n = -- shouldn't happen
72− Pandoc nullMeta $ foldr (addBlock opts) [] [n]
73−
74−addBlocks :: ReaderOptions -> [Node] -> [Block]
75−addBlocks opts = foldr (addBlock opts) []
76−
77−addBlock :: ReaderOptions -> Node -> [Block] -> [Block]
78−addBlock opts (Node _ PARAGRAPH nodes) =
79− case addInlines opts nodes of
80− [Image attr alt (src,tit)]
81− | isEnabled Ext_implicit_figures opts
82− -- the "fig:" prefix indicates an implicit figure
83− -> (Para [Image attr alt (src, "fig:" <> tit)] :)
84− ils -> (Para ils :)
85−addBlock _ (Node _ THEMATIC_BREAK _) =
86− (HorizontalRule :)
87−addBlock opts (Node _ BLOCK_QUOTE nodes) =
88− (BlockQuote (addBlocks opts nodes) :)
89−addBlock opts (Node _ (HTML_BLOCK t) _)
90− | isEnabled Ext_raw_html opts = (RawBlock (Format "html") t :)
91− | otherwise = id
92−-- Note: the cmark parser will never generate CUSTOM_BLOCK,
93−-- so we don't need to handle it:
94−addBlock _ (Node _ (CUSTOM_BLOCK _onEnter _onExit) _nodes) =
95− id
96−addBlock _ (Node _ (CODE_BLOCK info t) _) =
97− (CodeBlock ("", take 1 (T.words info), []) t :)
98−addBlock opts (Node _ (HEADING lev) nodes) =
99− (Header lev ("",[],[]) (addInlines opts nodes) :)
100−addBlock opts (Node _ (LIST listAttrs) nodes) =
101− (constructor (map listItem nodes) :)
102− where constructor = case listType listAttrs of
103− BULLET_LIST -> BulletList
104− ORDERED_LIST -> OrderedList
105− (start, DefaultStyle, delim)
106− start = listStart listAttrs
107− listItem = taskListItemFromAscii exts . setTightness
108− . addBlocks opts . children
109− setTightness = if listTight listAttrs
110− then map paraToPlain
111− else id
112− paraToPlain (Para xs) = Plain xs
113− paraToPlain x = x
114− delim = case listDelim listAttrs of
115− PERIOD_DELIM -> Period
116− PAREN_DELIM -> OneParen
117− exts = readerExtensions opts
118−addBlock opts (Node _ (TABLE alignments) nodes) =
119− (Table
120− nullAttr
121− (Caption Nothing [])
122− (zip aligns widths)
123− (TableHead nullAttr headers)
124− [TableBody nullAttr 0 [] rows]
125− (TableFoot nullAttr []) :)
126− where aligns = map fromTableCellAlignment alignments
127− fromTableCellAlignment NoAlignment = AlignDefault
128− fromTableCellAlignment LeftAligned = AlignLeft
129− fromTableCellAlignment RightAligned = AlignRight
130− fromTableCellAlignment CenterAligned = AlignCenter
131− widths = replicate numcols ColWidthDefault
132− numcols = if null rows'
133− then 0
134− else maximum $ map rowLength rows'
135− rows' = map toRow $ filter isRow nodes
136− (headers, rows) = case rows' of
137− (h:rs) -> ([h], rs)
138− [] -> ([], [])
139− isRow (Node _ TABLE_ROW _) = True
140− isRow _ = False
141− isCell (Node _ TABLE_CELL _) = True
142− isCell _ = False
143− toRow (Node _ TABLE_ROW ns) = Row nullAttr $ map toCell $ filter isCell ns
144− toRow (Node _ t _) = error $ "toRow encountered non-row " ++ show t
145− toCell (Node _ TABLE_CELL []) = fromSimpleCell []
146− toCell (Node _ TABLE_CELL (n:ns))
147− | isBlockNode n = fromSimpleCell $ addBlocks opts (n:ns)
148− | otherwise = fromSimpleCell [Plain (addInlines opts (n:ns))]
149− toCell (Node _ t _) = error $ "toCell encountered non-cell " ++ show t
150− fromSimpleCell = Cell nullAttr AlignDefault 1 1
151− rowLength (Row _ body) = length body -- all cells are 1×1
152−addBlock _ (Node _ TABLE_ROW _) = id -- handled in TABLE
153−addBlock _ (Node _ TABLE_CELL _) = id -- handled in TABLE
154−addBlock _ _ = id
155−
156−isBlockNode :: Node -> Bool
157−isBlockNode (Node _ nodetype _) =
158− case nodetype of
159− DOCUMENT -> True
160− THEMATIC_BREAK -> True
161− PARAGRAPH -> True
162− BLOCK_QUOTE -> True
163− HTML_BLOCK _ -> True
164− CUSTOM_BLOCK _ _ -> True
165− CODE_BLOCK _ _ -> True
166− HEADING _ -> True
167− LIST _ -> True
168− ITEM -> True
169− TEXT _ -> False
170− SOFTBREAK -> False
171− LINEBREAK -> False
172− HTML_INLINE _ -> False
173− CUSTOM_INLINE _ _ -> False
174− CODE _ -> False
175− EMPH -> False
176− STRONG -> False
177− LINK _ _ -> False
178− IMAGE _ _ -> False
179− STRIKETHROUGH -> False
180− TABLE _ -> False
181− TABLE_ROW -> False
182− TABLE_CELL -> False
183−
184−children :: Node -> [Node]
185−children (Node _ _ ns) = ns
186−
187−addInlines :: ReaderOptions -> [Node] -> [Inline]
188−addInlines opts = foldr (addInline opts) []
189−
190−addInline :: ReaderOptions -> Node -> [Inline] -> [Inline]
191−addInline opts (Node _ (TEXT t) _) = (concatMap toinl clumps ++)
192− where clumps = T.groupBy samekind t
193− samekind ' ' ' ' = True
194− samekind ' ' _ = False
195− samekind _ ' ' = False
196− samekind _ _ = True
197− toinl (T.uncons -> Just (' ', _)) = [Space]
198− toinl xs = if isEnabled Ext_emoji opts
199− then convertEmojis xs
200− else [Str xs]
201−addInline _ (Node _ LINEBREAK _) = (LineBreak :)
202−addInline opts (Node _ SOFTBREAK _)
203− | isEnabled Ext_hard_line_breaks opts = (LineBreak :)
204− | otherwise = (SoftBreak :)
205−addInline opts (Node _ (HTML_INLINE t) _)
206− | isEnabled Ext_raw_html opts = (RawInline (Format "html") t :)
207− | otherwise = id
208−-- Note: the cmark parser will never generate CUSTOM_BLOCK,
209−-- so we don't need to handle it:
210−addInline _ (Node _ (CUSTOM_INLINE _onEnter _onExit) _nodes) =
211− id
212−addInline _ (Node _ (CODE t) _) =
213− (Code ("",[],[]) t :)
214−addInline opts (Node _ EMPH nodes) =
215− (Emph (addInlines opts nodes) :)
216−addInline opts (Node _ STRONG nodes) =
217− (Strong (addInlines opts nodes) :)
218−addInline opts (Node _ STRIKETHROUGH nodes) =
219− (Strikeout (addInlines opts nodes) :)
220−addInline opts (Node _ (LINK url title) nodes) =
221− (Link nullAttr (addInlines opts nodes) (url, title) :)
222−addInline opts (Node _ (IMAGE url title) nodes) =
223− (Image nullAttr (addInlines opts nodes) (url, title) :)
224−addInline _ _ = id
src/Text/Pandoc/Readers/DocBook.hs+2−1
@@ -360,7 +360,7 @@ List of all DocBook tags, with [x] indicating implemented,
360[x] refsectioninfo - Meta-information for a refsection
360[x] refsectioninfo - Meta-information for a refsection
361[ ] refsynopsisdiv - A syntactic synopsis of the subject of the reference page
361[ ] refsynopsisdiv - A syntactic synopsis of the subject of the reference page
362[ ] refsynopsisdivinfo - Meta-information for a RefSynopsisDiv
362[ ] refsynopsisdivinfo - Meta-information for a RefSynopsisDiv
363−[x] releaseinfo - Information about a particular release of a document
363+[ ] releaseinfo - Information about a particular release of a document
364[ ] remark - A remark (or comment) intended for presentation in a draft
364[ ] remark - A remark (or comment) intended for presentation in a draft
365 manuscript
365 manuscript
366[x] replaceable - Content that may or must be replaced by the user
366[x] replaceable - Content that may or must be replaced by the user
@@ -608,6 +608,7 @@ addMetadataFromElement e = do
608 addMetaField "author" e
608 addMetaField "author" e
609 addMetaField "date" e
609 addMetaField "date" e
610 addMetaField "release" e
610 addMetaField "release" e
611+ addMetaField "releaseinfo" e
611 return mempty
612 return mempty
612 where addMetaField fieldname elt =
613 where addMetaField fieldname elt =
613 case filterChildren (named fieldname) elt of
614 case filterChildren (named fieldname) elt of
src/Text/Pandoc/Readers/Docx.hs+44−49
@@ -261,46 +261,43 @@ resolveDependentRunStyle rPr
261 | otherwise = return rPr
261 | otherwise = return rPr
262
262
263runStyleToTransform :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
263runStyleToTransform :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
264−runStyleToTransform rPr
264+runStyleToTransform rPr' = do
265+ opts <- asks docxOptions
266+ inBidi <- asks docxInBidi
267+ let styles = isEnabled Ext_styles opts
268+ ctl = (Just True == isRTL rPr') || (Just True == isForceCTL rPr')
269+ italic rPr | ctl = isItalicCTL rPr
270+ | otherwise = isItalic rPr
271+ bold rPr | ctl = isBoldCTL rPr
272+ | otherwise = isBold rPr
273+ go rPr
265− | Just sn <- getStyleName <$> rParentStyle rPr
274+ | Just sn <- getStyleName <$> rParentStyle rPr
266− , sn `elem` spansToKeep = do
275+ , sn `elem` spansToKeep =
267− transform <- runStyleToTransform rPr{rParentStyle = Nothing}
268− return $ spanWith ("", [normalizeToClassName sn], []) . transform
276+ spanWith ("", [normalizeToClassName sn], [])
277+ . go rPr{rParentStyle = Nothing}
269− | Just s <- rParentStyle rPr = do
278+ | styles, Just s <- rParentStyle rPr =
270− ei <- extraInfo spanWith s
271− transform <- runStyleToTransform rPr{rParentStyle = Nothing}
279+ spanWith (extraAttr s) . go rPr{rParentStyle = Nothing}
272− return $ ei . transform
273− | Just True <- isItalic rPr = do
280+ | Just True <- italic rPr =
274− transform <- runStyleToTransform rPr{isItalic = Nothing}
281+ emph . go rPr{isItalic = Nothing, isItalicCTL = Nothing}
275− return $ emph . transform
282+ | Just True <- bold rPr =
276− | Just True <- isBold rPr = do
283+ strong . go rPr{isBold = Nothing, isBoldCTL = Nothing}
277− transform <- runStyleToTransform rPr{isBold = Nothing}
284+ | Just True <- isSmallCaps rPr =
278− return $ strong . transform
285+ smallcaps . go rPr{isSmallCaps = Nothing}
279− | Just True <- isSmallCaps rPr = do
280− transform <- runStyleToTransform rPr{isSmallCaps = Nothing}
281− return $ smallcaps . transform
282− | Just True <- isStrike rPr = do
286+ | Just True <- isStrike rPr =
283− transform <- runStyleToTransform rPr{isStrike = Nothing}
287+ strikeout . go rPr{isStrike = Nothing}
284− return $ strikeout . transform
285− | Just True <- isRTL rPr = do
288+ | Just True <- isRTL rPr =
286− transform <- runStyleToTransform rPr{isRTL = Nothing}
287− return $ spanWith ("",[],[("dir","rtl")]) . transform
289+ spanWith ("",[],[("dir","rtl")]) . go rPr{isRTL = Nothing}
288− | Just False <- isRTL rPr = do
290+ | inBidi, Just False <- isRTL rPr =
289− transform <- runStyleToTransform rPr{isRTL = Nothing}
290− inBidi <- asks docxInBidi
291− return $ if inBidi
292− then spanWith ("",[],[("dir","ltr")]) . transform
291+ spanWith ("",[],[("dir","ltr")]) . go rPr{isRTL = Nothing}
293− else transform
294− | Just SupScrpt <- rVertAlign rPr = do
292+ | Just SupScrpt <- rVertAlign rPr =
295− transform <- runStyleToTransform rPr{rVertAlign = Nothing}
293+ superscript . go rPr{rVertAlign = Nothing}
296− return $ superscript . transform
297− | Just SubScrpt <- rVertAlign rPr = do
294+ | Just SubScrpt <- rVertAlign rPr = do
298− transform <- runStyleToTransform rPr{rVertAlign = Nothing}
295+ subscript . go rPr{rVertAlign = Nothing}
299− return $ subscript . transform
300− | Just "single" <- rUnderline rPr = do
296+ | Just "single" <- rUnderline rPr = do
301− transform <- runStyleToTransform rPr{rUnderline = Nothing}
302− return $ Pandoc.underline . transform
297+ Pandoc.underline . go rPr{rUnderline = Nothing}
303− | otherwise = return id
298+ | otherwise = id
299+ return $ go rPr'
300+
304
301
305runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
302runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
306runToInlines (Run rs runElems)
303runToInlines (Run rs runElems)
@@ -512,13 +509,8 @@ trimSps (Many ils) = Many $ Seq.dropWhileL isSp $Seq.dropWhileR isSp ils
512 isSp LineBreak = True
509 isSp LineBreak = True
513 isSp _ = False
510 isSp _ = False
514
511
515−extraInfo :: (Eq (StyleName a), PandocMonad m, HasStyleName a)
512+extraAttr :: (Eq (StyleName a), HasStyleName a) => a -> Attr
516− => (Attr -> i -> i) -> a -> DocxContext m (i -> i)
517−extraInfo f s = do
518− opts <- asks docxOptions
519− return $ if isEnabled Ext_styles opts
520− then f ("", [], [("custom-style", fromStyleName $ getStyleName s)])
513+extraAttr s = ("", [], [("custom-style", fromStyleName $ getStyleName s)])
521− else id
522
514
523parStyleToTransform :: PandocMonad m => ParagraphStyle -> DocxContext m (Blocks -> Blocks)
515parStyleToTransform :: PandocMonad m => ParagraphStyle -> DocxContext m (Blocks -> Blocks)
524parStyleToTransform pPr = case pStyle pPr of
516parStyleToTransform pPr = case pStyle pPr of
@@ -534,8 +526,11 @@ parStyleToTransform pPr = case pStyle pPr of
534 | otherwise -> do
526 | otherwise -> do
535 let pPr' = pPr { pStyle = cs }
527 let pPr' = pPr { pStyle = cs }
536 transform <- parStyleToTransform pPr'
528 transform <- parStyleToTransform pPr'
537− ei <- extraInfo divWith c
529+ styles <- asks (isEnabled Ext_styles . docxOptions)
530+ return $
531+ (if styles then divWith (extraAttr c) else id)
538− return $ ei . (if isBlockQuote c then blockQuote else id) . transform
532+ . (if isBlockQuote c then blockQuote else id)
533+ . transform
539 []
534 []
540 | Just left <- indentation pPr >>= leftParIndent -> do
535 | Just left <- indentation pPr >>= leftParIndent -> do
541 let pPr' = pPr { indentation = Nothing }
536 let pPr' = pPr { indentation = Nothing }
src/Text/Pandoc/Readers/Docx/Combine.hs+39−62
@@ -1,10 +1,9 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE PatternGuards #-}
3{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
4{- |
2{- |
5 Module : Text.Pandoc.Readers.Docx.Combine
3 Module : Text.Pandoc.Readers.Docx.Combine
6 Copyright : © 2014-2020 Jesse Rosenthal <jrosenthal@jhu.edu>,
4 Copyright : © 2014-2020 Jesse Rosenthal <jrosenthal@jhu.edu>,
7− 2014-2020 John MacFarlane <jgm@berkeley.edu>
5+ 2014-2020 John MacFarlane <jgm@berkeley.edu>,
6+ 2020 Nikolay Yakimov <root@livid.pp.ru>
8 License : GNU GPL, version 2 or above
7 License : GNU GPL, version 2 or above
9
8
10 Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
9 Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -59,79 +58,61 @@ module Text.Pandoc.Readers.Docx.Combine ( smushInlines
59 where
58 where
60
59
61import Data.List
60import Data.List
61+import Data.Bifunctor
62−import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr, (><), (|>))
62+import Data.Sequence ( ViewL (..), ViewR (..), viewl, viewr, spanr, spanl
63−import qualified Data.Sequence as Seq (null)
63+ , (><), (|>) )
64import Text.Pandoc.Builder
64import Text.Pandoc.Builder
65
65
66data Modifier a = Modifier (a -> a)
66data Modifier a = Modifier (a -> a)
67 | AttrModifier (Attr -> a -> a) Attr
67 | AttrModifier (Attr -> a -> a) Attr
68− | NullModifier
69
68
70spaceOutInlinesL :: Inlines -> (Inlines, Inlines)
69spaceOutInlinesL :: Inlines -> (Inlines, Inlines)
71spaceOutInlinesL ms = (l, stackInlines fs (m' <> r))
70spaceOutInlinesL ms = (l, stackInlines fs (m' <> r))
72− where (l, m, r) = spaceOutInlines ms
71+ where (l, (fs, m'), r) = spaceOutInlines ms
73− (fs, m') = unstackInlines m
74
72
75spaceOutInlinesR :: Inlines -> (Inlines, Inlines)
73spaceOutInlinesR :: Inlines -> (Inlines, Inlines)
76spaceOutInlinesR ms = (stackInlines fs (l <> m'), r)
74spaceOutInlinesR ms = (stackInlines fs (l <> m'), r)
77− where (l, m, r) = spaceOutInlines ms
75+ where (l, (fs, m'), r) = spaceOutInlines ms
78− (fs, m') = unstackInlines m
79
76
80−spaceOutInlines :: Inlines -> (Inlines, Inlines, Inlines)
77+spaceOutInlines :: Inlines -> (Inlines, ([Modifier Inlines], Inlines), Inlines)
81spaceOutInlines ils =
78spaceOutInlines ils =
82 let (fs, ils') = unstackInlines ils
79 let (fs, ils') = unstackInlines ils
83− contents = unMany ils'
80+ (left, (right, contents')) = second (spanr isSpace) $ spanl isSpace $ unMany ils'
84− left = case viewl contents of
81+ -- NOTE: spanr counterintuitively returns suffix as the FIRST tuple element
85− (Space :< _) -> space
86− _ -> mempty
87− right = case viewr contents of
88− (_ :> Space) -> space
89− _ -> mempty in
90− (left, stackInlines fs $ trimInlines . Many $ contents, right)
82+ in (Many left, (fs, Many contents'), Many right)
83+
84+isSpace :: Inline -> Bool
85+isSpace Space = True
86+isSpace SoftBreak = True
87+isSpace _ = False
91
88
92stackInlines :: [Modifier Inlines] -> Inlines -> Inlines
89stackInlines :: [Modifier Inlines] -> Inlines -> Inlines
93stackInlines [] ms = ms
90stackInlines [] ms = ms
94−stackInlines (NullModifier : fs) ms = stackInlines fs ms
95stackInlines (Modifier f : fs) ms =
91stackInlines (Modifier f : fs) ms =
96− if isEmpty ms
92+ if null ms
97 then stackInlines fs ms
93 then stackInlines fs ms
98 else f $ stackInlines fs ms
94 else f $ stackInlines fs ms
99stackInlines (AttrModifier f attr : fs) ms = f attr $ stackInlines fs ms
95stackInlines (AttrModifier f attr : fs) ms = f attr $ stackInlines fs ms
100
96
101unstackInlines :: Inlines -> ([Modifier Inlines], Inlines)
97unstackInlines :: Inlines -> ([Modifier Inlines], Inlines)
102−unstackInlines ms = case ilModifier ms of
98+unstackInlines ms = case ilModifierAndInnards ms of
103− NullModifier -> ([], ms)
99+ Nothing -> ([], ms)
104− _ -> (f : fs, ms') where
105− f = ilModifier ms
106− (fs, ms') = unstackInlines $ ilInnards ms
100+ Just (f, inner) -> first (f :) $ unstackInlines inner
107−
101+
108−ilModifier :: Inlines -> Modifier Inlines
102+ilModifierAndInnards :: Inlines -> Maybe (Modifier Inlines, Inlines)
109−ilModifier ils = case viewl (unMany ils) of
103+ilModifierAndInnards ils = case viewl $ unMany ils of
110− (x :< xs) | Seq.null xs -> case x of
104+ x :< xs | null xs -> second fromList <$> case x of
111− (Emph _) -> Modifier emph
105+ Emph lst -> Just (Modifier emph, lst)
112− (Strong _) -> Modifier strong
106+ Strong lst -> Just (Modifier strong, lst)
113− (SmallCaps _) -> Modifier smallcaps
107+ SmallCaps lst -> Just (Modifier smallcaps, lst)
114− (Strikeout _) -> Modifier strikeout
108+ Strikeout lst -> Just (Modifier strikeout, lst)
109+ Underline lst -> Just (Modifier underline, lst)
115− (Superscript _) -> Modifier superscript
110+ Superscript lst -> Just (Modifier superscript, lst)
116− (Subscript _) -> Modifier subscript
111+ Subscript lst -> Just (Modifier subscript, lst)
117− (Link attr _ tgt) -> Modifier $ linkWith attr (fst tgt) (snd tgt)
112+ Link attr lst tgt -> Just (Modifier $ linkWith attr (fst tgt) (snd tgt), lst)
118− (Span attr _) -> AttrModifier spanWith attr
113+ Span attr lst -> Just (AttrModifier spanWith attr, lst)
119− _ -> NullModifier
114+ _ -> Nothing
120− _ -> NullModifier
115+ _ -> Nothing
121−
122−ilInnards :: Inlines -> Inlines
123−ilInnards ils = case viewl (unMany ils) of
124− (x :< xs) | Seq.null xs -> case x of
125− (Emph lst) -> fromList lst
126− (Strong lst) -> fromList lst
127− (SmallCaps lst) -> fromList lst
128− (Strikeout lst) -> fromList lst
129− (Superscript lst) -> fromList lst
130− (Subscript lst) -> fromList lst
131− (Link _ lst _) -> fromList lst
132− (Span _ lst) -> fromList lst
133− _ -> ils
134− _ -> ils
135
116
136inlinesL :: Inlines -> (Inlines, Inlines)
117inlinesL :: Inlines -> (Inlines, Inlines)
137inlinesL ils = case viewl $ unMany ils of
118inlinesL ils = case viewl $ unMany ils of
@@ -161,12 +142,12 @@ combineSingletonInlines x y =
161 y_rem_attr = filter isAttrModifier y_remaining
142 y_rem_attr = filter isAttrModifier y_remaining
162 in
143 in
163 case null shared of
144 case null shared of
164− True | isEmpty xs && isEmpty ys ->
145+ True | null xs && null ys ->
165− stackInlines (x_rem_attr ++ y_rem_attr) mempty
146+ stackInlines (x_rem_attr <> y_rem_attr) mempty
166− | isEmpty xs ->
147+ | null xs ->
167 let (sp, y') = spaceOutInlinesL y in
148 let (sp, y') = spaceOutInlinesL y in
168 stackInlines x_rem_attr mempty <> sp <> y'
149 stackInlines x_rem_attr mempty <> sp <> y'
169− | isEmpty ys ->
150+ | null ys ->
170 let (x', sp) = spaceOutInlinesR x in
151 let (x', sp) = spaceOutInlinesR x in
171 x' <> sp <> stackInlines y_rem_attr mempty
152 x' <> sp <> stackInlines y_rem_attr mempty
172 | otherwise ->
153 | otherwise ->
@@ -193,12 +174,8 @@ combineBlocks bs cs = bs <> cs
193instance (Monoid a, Eq a) => Eq (Modifier a) where
174instance (Monoid a, Eq a) => Eq (Modifier a) where
194 (Modifier f) == (Modifier g) = f mempty == g mempty
175 (Modifier f) == (Modifier g) = f mempty == g mempty
195 (AttrModifier f attr) == (AttrModifier g attr') = f attr mempty == g attr' mempty
176 (AttrModifier f attr) == (AttrModifier g attr') = f attr mempty == g attr' mempty
196− NullModifier == NullModifier = True
197 _ == _ = False
177 _ == _ = False
198
178
199−isEmpty :: (Monoid a, Eq a) => a -> Bool
200−isEmpty x = x == mempty
201−
202isAttrModifier :: Modifier a -> Bool
179isAttrModifier :: Modifier a -> Bool
203isAttrModifier (AttrModifier _ _) = True
180isAttrModifier (AttrModifier _ _) = True
204isAttrModifier _ = False
181isAttrModifier _ = False
src/Text/Pandoc/Readers/Docx/Parse.hs+3
@@ -259,10 +259,13 @@ newtype Cell = Cell [BodyPart]
259leftBiasedMergeRunStyle :: RunStyle -> RunStyle -> RunStyle
259leftBiasedMergeRunStyle :: RunStyle -> RunStyle -> RunStyle
260leftBiasedMergeRunStyle a b = RunStyle
260leftBiasedMergeRunStyle a b = RunStyle
261 { isBold = isBold a <|> isBold b
261 { isBold = isBold a <|> isBold b
262+ , isBoldCTL = isBoldCTL a <|> isBoldCTL b
262 , isItalic = isItalic a <|> isItalic b
263 , isItalic = isItalic a <|> isItalic b
264+ , isItalicCTL = isItalicCTL a <|> isItalicCTL b
263 , isSmallCaps = isSmallCaps a <|> isSmallCaps b
265 , isSmallCaps = isSmallCaps a <|> isSmallCaps b
264 , isStrike = isStrike a <|> isStrike b
266 , isStrike = isStrike a <|> isStrike b
265 , isRTL = isRTL a <|> isRTL b
267 , isRTL = isRTL a <|> isRTL b
268+ , isForceCTL = isForceCTL a <|> isForceCTL b
266 , rVertAlign = rVertAlign a <|> rVertAlign b
269 , rVertAlign = rVertAlign a <|> rVertAlign b
267 , rUnderline = rUnderline a <|> rUnderline b
270 , rUnderline = rUnderline a <|> rUnderline b
268 , rParentStyle = rParentStyle a
271 , rParentStyle = rParentStyle a
src/Text/Pandoc/Readers/Docx/Parse/Styles.hs+12−6
@@ -44,7 +44,6 @@ module Text.Pandoc.Readers.Docx.Parse.Styles (
44 ) where
44 ) where
45import Codec.Archive.Zip
45import Codec.Archive.Zip
46import Control.Applicative ((<|>))
46import Control.Applicative ((<|>))
47−import Control.Monad.Except
48import Data.Function (on)
47import Data.Function (on)
49import Data.String (IsString(..))
48import Data.String (IsString(..))
50import qualified Data.Map as M
49import qualified Data.Map as M
@@ -101,10 +100,13 @@ data CharStyle = CharStyle { cStyleId :: CharStyleId
101 } deriving (Show)
100 } deriving (Show)
102
101
103data RunStyle = RunStyle { isBold :: Maybe Bool
102data RunStyle = RunStyle { isBold :: Maybe Bool
103+ , isBoldCTL :: Maybe Bool
104 , isItalic :: Maybe Bool
104 , isItalic :: Maybe Bool
105+ , isItalicCTL :: Maybe Bool
105 , isSmallCaps :: Maybe Bool
106 , isSmallCaps :: Maybe Bool
106 , isStrike :: Maybe Bool
107 , isStrike :: Maybe Bool
107 , isRTL :: Maybe Bool
108 , isRTL :: Maybe Bool
109+ , isForceCTL :: Maybe Bool
108 , rVertAlign :: Maybe VertAlign
110 , rVertAlign :: Maybe VertAlign
109 , rUnderline :: Maybe String
111 , rUnderline :: Maybe String
110 , rParentStyle :: Maybe CharStyle
112 , rParentStyle :: Maybe CharStyle
@@ -121,10 +123,13 @@ data ParStyle = ParStyle { headingLev :: Maybe (ParaStyleName, Int)
121
123
122defaultRunStyle :: RunStyle
124defaultRunStyle :: RunStyle
123defaultRunStyle = RunStyle { isBold = Nothing
125defaultRunStyle = RunStyle { isBold = Nothing
126+ , isBoldCTL = Nothing
124 , isItalic = Nothing
127 , isItalic = Nothing
128+ , isItalicCTL = Nothing
125 , isSmallCaps = Nothing
129 , isSmallCaps = Nothing
126 , isStrike = Nothing
130 , isStrike = Nothing
127 , isRTL = Nothing
131 , isRTL = Nothing
132+ , isForceCTL = Nothing
128 , rVertAlign = Nothing
133 , rVertAlign = Nothing
129 , rUnderline = Nothing
134 , rUnderline = Nothing
130 , rParentStyle = Nothing
135 , rParentStyle = Nothing
@@ -240,20 +245,21 @@ elemToCharStyle :: NameSpaces
240elemToCharStyle ns element parentStyle
245elemToCharStyle ns element parentStyle
241 = CharStyle <$> (CharStyleId <$> findAttrTextByName ns "w" "styleId" element)
246 = CharStyle <$> (CharStyleId <$> findAttrTextByName ns "w" "styleId" element)
242 <*> getElementStyleName ns element
247 <*> getElementStyleName ns element
243− <*> (Just $ elemToRunStyle ns element parentStyle)
248+ <*> Just (elemToRunStyle ns element parentStyle)
244
249
245elemToRunStyle :: NameSpaces -> Element -> Maybe CharStyle -> RunStyle
250elemToRunStyle :: NameSpaces -> Element -> Maybe CharStyle -> RunStyle
246elemToRunStyle ns element parentStyle
251elemToRunStyle ns element parentStyle
247 | Just rPr <- findChildByName ns "w" "rPr" element =
252 | Just rPr <- findChildByName ns "w" "rPr" element =
248 RunStyle
253 RunStyle
249 {
254 {
250− isBold = checkOnOff ns rPr (elemName ns "w" "b") `mplus`
255+ isBold = checkOnOff ns rPr (elemName ns "w" "b")
251− checkOnOff ns rPr (elemName ns "w" "bCs")
256+ , isBoldCTL = checkOnOff ns rPr (elemName ns "w" "bCs")
252− , isItalic = checkOnOff ns rPr (elemName ns "w" "i") `mplus`
257+ , isItalic = checkOnOff ns rPr (elemName ns "w" "i")
253− checkOnOff ns rPr (elemName ns "w" "iCs")
258+ , isItalicCTL = checkOnOff ns rPr (elemName ns "w" "iCs")
254 , isSmallCaps = checkOnOff ns rPr (elemName ns "w" "smallCaps")
259 , isSmallCaps = checkOnOff ns rPr (elemName ns "w" "smallCaps")
255 , isStrike = checkOnOff ns rPr (elemName ns "w" "strike")
260 , isStrike = checkOnOff ns rPr (elemName ns "w" "strike")
256 , isRTL = checkOnOff ns rPr (elemName ns "w" "rtl")
261 , isRTL = checkOnOff ns rPr (elemName ns "w" "rtl")
262+ , isForceCTL = checkOnOff ns rPr (elemName ns "w" "cs")
257 , rVertAlign =
263 , rVertAlign =
258 findChildByName ns "w" "vertAlign" rPr >>=
264 findChildByName ns "w" "vertAlign" rPr >>=
259 findAttrByName ns "w" "val" >>=
265 findAttrByName ns "w" "val" >>=
src/Text/Pandoc/Readers/Markdown.hs+2−5
@@ -67,16 +67,13 @@ yamlToMeta :: PandocMonad m
67 -> m Meta
67 -> m Meta
68yamlToMeta opts bstr = do
68yamlToMeta opts bstr = do
69 let parser = do
69 let parser = do
70− meta <- yamlBsToMeta (asBlocks <$> parseBlocks) bstr
70+ meta <- yamlBsToMeta (fmap B.toMetaValue <$> parseBlocks) bstr
71 return $ runF meta defaultParserState
71 return $ runF meta defaultParserState
72 parsed <- readWithM parser def{ stateOptions = opts } ""
72 parsed <- readWithM parser def{ stateOptions = opts } ""
73 case parsed of
73 case parsed of
74 Right result -> return result
74 Right result -> return result
75 Left e -> throwError e
75 Left e -> throwError e
76
76
77−asBlocks :: Functor f => f (B.Many Block) -> f MetaValue
78−asBlocks p = MetaBlocks . B.toList <$> p
79−
80--
77--
81-- Constants and data structure definitions
78-- Constants and data structure definitions
82--
79--
@@ -241,7 +238,7 @@ yamlMetaBlock = try $ do
241 -- by including --- and ..., we allow yaml blocks with just comments:
238 -- by including --- and ..., we allow yaml blocks with just comments:
242 let rawYaml = T.unlines ("---" : (rawYamlLines ++ ["..."]))
239 let rawYaml = T.unlines ("---" : (rawYamlLines ++ ["..."]))
243 optional blanklines
240 optional blanklines
244− newMetaF <- yamlBsToMeta (asBlocks <$> parseBlocks)
241+ newMetaF <- yamlBsToMeta (fmap B.toMetaValue <$> parseBlocks)
245 $ UTF8.fromTextLazy $ TL.fromStrict rawYaml
242 $ UTF8.fromTextLazy $ TL.fromStrict rawYaml
246 -- Since `<>` is left-biased, existing values are not touched:
243 -- Since `<>` is left-biased, existing values are not touched:
247 updateState $ \st -> st{ stateMeta' = stateMeta' st <> newMetaF }
244 updateState $ \st -> st{ stateMeta' = stateMeta' st <> newMetaF }
src/Text/Pandoc/Readers/Metadata.hs+23−36
@@ -1,4 +1,3 @@
1−{-# LANGUAGE ScopedTypeVariables #-}
2{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
3{- |
2{- |
4 Module : Text.Pandoc.Readers.Metadata
3 Module : Text.Pandoc.Readers.Metadata
@@ -21,7 +20,6 @@ import Data.Text (Text)
21import qualified Data.Text as T
20import qualified Data.Text as T
22import qualified Data.YAML as YAML
21import qualified Data.YAML as YAML
23import qualified Data.YAML.Event as YE
22import qualified Data.YAML.Event as YE
24−import qualified Text.Pandoc.Builder as B
25import Text.Pandoc.Class.PandocMonad (PandocMonad (..))
23import Text.Pandoc.Class.PandocMonad (PandocMonad (..))
26import Text.Pandoc.Definition
24import Text.Pandoc.Definition
27import Text.Pandoc.Error
25import Text.Pandoc.Error
@@ -33,11 +31,11 @@ yamlBsToMeta :: PandocMonad m
33 => ParserT Text ParserState m (F MetaValue)
31 => ParserT Text ParserState m (F MetaValue)
34 -> BL.ByteString
32 -> BL.ByteString
35 -> ParserT Text ParserState m (F Meta)
33 -> ParserT Text ParserState m (F Meta)
36−yamlBsToMeta pBlocks bstr = do
34+yamlBsToMeta pMetaValue bstr = do
37 pos <- getPosition
35 pos <- getPosition
38 case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of
36 case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of
39 Right (YAML.Doc (YAML.Mapping _ _ o):_)
37 Right (YAML.Doc (YAML.Mapping _ _ o):_)
40− -> fmap Meta <$> yamlMap pBlocks o
38+ -> fmap Meta <$> yamlMap pMetaValue o
41 Right [] -> return . return $ mempty
39 Right [] -> return . return $ mempty
42 Right [YAML.Doc (YAML.Scalar _ YAML.SNull)]
40 Right [YAML.Doc (YAML.Scalar _ YAML.SNull)]
43 -> return . return $ mempty
41 -> return . return $ mempty
@@ -57,30 +55,21 @@ nodeToKey (YAML.Scalar _ (YAML.SUnknown _ t)) = return t
57nodeToKey _ = throwError $ PandocParseError
55nodeToKey _ = throwError $ PandocParseError
58 "Non-string key in YAML mapping"
56 "Non-string key in YAML mapping"
59
57
60−toMetaValue :: PandocMonad m
58+normalizeMetaValue :: PandocMonad m
61− => ParserT Text ParserState m (F MetaValue)
59+ => ParserT Text ParserState m (F MetaValue)
62− -> Text
60+ -> Text
63− -> ParserT Text ParserState m (F MetaValue)
61+ -> ParserT Text ParserState m (F MetaValue)
64−toMetaValue pBlocks x =
62+normalizeMetaValue pMetaValue x =
65 -- Note: a standard quoted or unquoted YAML value will
63 -- Note: a standard quoted or unquoted YAML value will
66 -- not end in a newline, but a "block" set off with
64 -- not end in a newline, but a "block" set off with
67 -- `|` or `>` will.
65 -- `|` or `>` will.
68 if "\n" `T.isSuffixOf` x
66 if "\n" `T.isSuffixOf` x
69− then parseFromString' pBlocks (x <> "\n")
67+ then parseFromString' pMetaValue (x <> "\n")
70− else parseFromString' pInlines x
68+ else parseFromString' asInlines x
71− where pInlines = do
69+ where asInlines = fmap b2i <$> pMetaValue
72− bs <- pBlocks
73− return $ do
74− bs' <- bs
75− return $
76− case bs' of
77− MetaBlocks bs'' ->
78− case bs'' of
79− [Plain ils] -> MetaInlines ils
70+ b2i (MetaBlocks [Plain ils]) = MetaInlines ils
80− [Para ils] -> MetaInlines ils
71+ b2i (MetaBlocks [Para ils]) = MetaInlines ils
81− xs -> MetaBlocks xs
82− _ -> bs'
72+ b2i bs = bs
83−
84
73
85checkBoolean :: Text -> Maybe Bool
74checkBoolean :: Text -> Maybe Bool
86checkBoolean t
75checkBoolean t
@@ -92,32 +81,30 @@ yamlToMetaValue :: PandocMonad m
92 => ParserT Text ParserState m (F MetaValue)
81 => ParserT Text ParserState m (F MetaValue)
93 -> YAML.Node YE.Pos
82 -> YAML.Node YE.Pos
94 -> ParserT Text ParserState m (F MetaValue)
83 -> ParserT Text ParserState m (F MetaValue)
95−yamlToMetaValue pBlocks (YAML.Scalar _ x) =
84+yamlToMetaValue pMetaValue (YAML.Scalar _ x) =
96 case x of
85 case x of
97− YAML.SStr t -> toMetaValue pBlocks t
86+ YAML.SStr t -> normalizeMetaValue pMetaValue t
98 YAML.SBool b -> return $ return $ MetaBool b
87 YAML.SBool b -> return $ return $ MetaBool b
99 YAML.SFloat d -> return $ return $ MetaString $ tshow d
88 YAML.SFloat d -> return $ return $ MetaString $ tshow d
100 YAML.SInt i -> return $ return $ MetaString $ tshow i
89 YAML.SInt i -> return $ return $ MetaString $ tshow i
101 YAML.SUnknown _ t ->
90 YAML.SUnknown _ t ->
102 case checkBoolean t of
91 case checkBoolean t of
103 Just b -> return $ return $ MetaBool b
92 Just b -> return $ return $ MetaBool b
104− Nothing -> toMetaValue pBlocks t
93+ Nothing -> normalizeMetaValue pMetaValue t
105 YAML.SNull -> return $ return $ MetaString ""
94 YAML.SNull -> return $ return $ MetaString ""
106
95
107−yamlToMetaValue pBlocks (YAML.Sequence _ _ xs) = do
96+yamlToMetaValue pMetaValue (YAML.Sequence _ _ xs) =
97+ fmap MetaList . sequence
108− xs' <- mapM (yamlToMetaValue pBlocks) xs
98+ <$> mapM (yamlToMetaValue pMetaValue) xs
109− return $ do
110− xs'' <- sequence xs'
111− return $ B.toMetaValue xs''
112−yamlToMetaValue pBlocks (YAML.Mapping _ _ o) =
99+yamlToMetaValue pMetaValue (YAML.Mapping _ _ o) =
113− fmap B.toMetaValue <$> yamlMap pBlocks o
100+ fmap MetaMap <$> yamlMap pMetaValue o
114yamlToMetaValue _ _ = return $ return $ MetaString ""
101yamlToMetaValue _ _ = return $ return $ MetaString ""
115
102
116yamlMap :: PandocMonad m
103yamlMap :: PandocMonad m
117 => ParserT Text ParserState m (F MetaValue)
104 => ParserT Text ParserState m (F MetaValue)
118 -> M.Map (YAML.Node YE.Pos) (YAML.Node YE.Pos)
105 -> M.Map (YAML.Node YE.Pos) (YAML.Node YE.Pos)
119 -> ParserT Text ParserState m (F (M.Map Text MetaValue))
106 -> ParserT Text ParserState m (F (M.Map Text MetaValue))
120−yamlMap pBlocks o = do
107+yamlMap pMetaValue o = do
121 kvs <- forM (M.toList o) $ \(key, v) -> do
108 kvs <- forM (M.toList o) $ \(key, v) -> do
122 k <- nodeToKey key
109 k <- nodeToKey key
123 return (k, v)
110 return (k, v)
@@ -126,7 +113,7 @@ yamlMap pBlocks o = do
126 where
113 where
127 ignorable t = "_" `T.isSuffixOf` t
114 ignorable t = "_" `T.isSuffixOf` t
128 toMeta (k, v) = do
115 toMeta (k, v) = do
129− fv <- yamlToMetaValue pBlocks v
116+ fv <- yamlToMetaValue pMetaValue v
130 return $ do
117 return $ do
131 v' <- fv
118 v' <- fv
132 return (k, v')
119 return (k, v')
src/Text/Pandoc/Readers/Org/Blocks.hs+15−1
@@ -76,6 +76,7 @@ block = choice [ mempty <$ blanklines
76 , list
76 , list
77 , latexFragment
77 , latexFragment
78 , noteBlock
78 , noteBlock
79+ , rawOrgLine
79 , paraOrPlain
80 , paraOrPlain
80 ] <?> "block"
81 ] <?> "block"
81
82
@@ -559,6 +560,8 @@ include = try $ do
559 | otherwise -> Para content
560 | otherwise -> Para content
560 _ -> blk
561 _ -> blk
561
562
563+-- | Parses a meta line which defines a raw block. Currently recognized:
564+-- @#+LATEX:@, @#+HTML:@, @#+TEXINFO:@, and @#+BEAMER@.
562rawExportLine :: PandocMonad m => OrgParser m Blocks
565rawExportLine :: PandocMonad m => OrgParser m Blocks
563rawExportLine = try $ do
566rawExportLine = try $ do
564 metaLineStart
567 metaLineStart
@@ -567,6 +570,14 @@ rawExportLine = try $ do
567 then B.rawBlock key <$> anyLine
570 then B.rawBlock key <$> anyLine
568 else mzero
571 else mzero
569
572
573+-- | Parses any meta line, i.e., a line starting with @#+@, into a raw
574+-- org block. This should be the last resort when trying to parse
575+-- keywords. Leading spaces are discarded.
576+rawOrgLine :: PandocMonad m => OrgParser m (F Blocks)
577+rawOrgLine = do
578+ line <- metaLineStart *> anyLine
579+ returnF $ B.rawBlock "org" $ ("#+" <> line)
580+
570commentLine :: Monad m => OrgParser m Blocks
581commentLine :: Monad m => OrgParser m Blocks
571commentLine = commentLineStart *> anyLine *> pure mempty
582commentLine = commentLineStart *> anyLine *> pure mempty
572
583
@@ -597,7 +608,10 @@ data OrgTable = OrgTable
597 }
608 }
598
609
599table :: PandocMonad m => OrgParser m (F Blocks)
610table :: PandocMonad m => OrgParser m (F Blocks)
611+table = do
612+ withTables <- getExportSetting exportWithTables
600−table = gridTableWith blocks True <|> orgTable
613+ tbl <- gridTableWith blocks True <|> orgTable
614+ return $ if withTables then tbl else mempty
601
615
602-- | A normal org table
616-- | A normal org table
603orgTable :: PandocMonad m => OrgParser m (F Blocks)
617orgTable :: PandocMonad m => OrgParser m (F Blocks)
src/Text/Pandoc/Readers/Org/ExportSettings.hs+3−3
@@ -47,9 +47,9 @@ exportSetting = choice
47 , booleanSetting "creator" (\val es -> es { exportWithCreator = val })
47 , booleanSetting "creator" (\val es -> es { exportWithCreator = val })
48 , complementableListSetting "d" (\val es -> es { exportDrawers = val })
48 , complementableListSetting "d" (\val es -> es { exportDrawers = val })
49 , ignoredSetting "date"
49 , ignoredSetting "date"
50− , ignoredSetting "e"
50+ , booleanSetting "e" (\val es -> es { exportWithEntities = val })
51 , booleanSetting "email" (\val es -> es { exportWithEmail = val })
51 , booleanSetting "email" (\val es -> es { exportWithEmail = val })
52− , ignoredSetting "f"
52+ , booleanSetting "f" (\val es -> es { exportWithFootnotes = val })
53 , integerSetting "H" (\val es -> es { exportHeadlineLevels = val })
53 , integerSetting "H" (\val es -> es { exportHeadlineLevels = val })
54 , ignoredSetting "inline"
54 , ignoredSetting "inline"
55 , ignoredSetting "num"
55 , ignoredSetting "num"
@@ -64,7 +64,7 @@ exportSetting = choice
64 , ignoredSetting "title"
64 , ignoredSetting "title"
65 , ignoredSetting "toc"
65 , ignoredSetting "toc"
66 , booleanSetting "todo" (\val es -> es { exportWithTodoKeywords = val })
66 , booleanSetting "todo" (\val es -> es { exportWithTodoKeywords = val })
67− , ignoredSetting "|"
67+ , booleanSetting "|" (\val es -> es { exportWithTables = val })
68 , ignoreAndWarn
68 , ignoreAndWarn
69 ] <?> "export setting"
69 ] <?> "export setting"
70
70
src/Text/Pandoc/Readers/Org/Inlines.hs+17−6
@@ -378,7 +378,10 @@ citation = try $ do
378 else rest
378 else rest
379
379
380footnote :: PandocMonad m => OrgParser m (F Inlines)
380footnote :: PandocMonad m => OrgParser m (F Inlines)
381+footnote = try $ do
381−footnote = try $ inlineNote <|> referencedNote
382+ note <- inlineNote <|> referencedNote
383+ withNote <- getExportSetting exportWithFootnotes
384+ return $ if withNote then note else mempty
382
385
383inlineNote :: PandocMonad m => OrgParser m (F Inlines)
386inlineNote :: PandocMonad m => OrgParser m (F Inlines)
384inlineNote = try $ do
387inlineNote = try $ do
@@ -790,9 +793,12 @@ inlineLaTeX :: PandocMonad m => OrgParser m (F Inlines)
790inlineLaTeX = try $ do
793inlineLaTeX = try $ do
791 cmd <- inlineLaTeXCommand
794 cmd <- inlineLaTeXCommand
792 texOpt <- getExportSetting exportWithLatex
795 texOpt <- getExportSetting exportWithLatex
796+ allowEntities <- getExportSetting exportWithEntities
793 ils <- parseAsInlineLaTeX cmd texOpt
797 ils <- parseAsInlineLaTeX cmd texOpt
794 maybe mzero returnF $
798 maybe mzero returnF $
799+ parseAsMathMLSym allowEntities cmd `mplus`
795− parseAsMathMLSym cmd `mplus` parseAsMath cmd texOpt `mplus` ils
800+ parseAsMath cmd texOpt `mplus`
801+ ils
796 where
802 where
797 parseAsInlineLaTeX :: PandocMonad m
803 parseAsInlineLaTeX :: PandocMonad m
798 => Text -> TeXExport -> OrgParser m (Maybe Inlines)
804 => Text -> TeXExport -> OrgParser m (Maybe Inlines)
@@ -801,10 +807,15 @@ inlineLaTeX = try $ do
801 TeXIgnore -> return (Just mempty)
807 TeXIgnore -> return (Just mempty)
802 TeXVerbatim -> return (Just $ B.str cs)
808 TeXVerbatim -> return (Just $ B.str cs)
803
809
804− parseAsMathMLSym :: Text -> Maybe Inlines
810+ parseAsMathMLSym :: Bool -> Text -> Maybe Inlines
805− parseAsMathMLSym cs = B.str <$> MathMLEntityMap.getUnicode (clean cs)
811+ parseAsMathMLSym allowEntities cs = do
806− -- drop initial backslash and any trailing "{}"
812+ -- drop initial backslash and any trailing "{}"
807− where clean = T.dropWhileEnd (`elem` ("{}" :: String)) . T.drop 1
813+ let clean = T.dropWhileEnd (`elem` ("{}" :: String)) . T.drop 1
814+ -- If entities are disabled, then return the string as text, but
815+ -- only if this *is* a MathML entity.
816+ case B.str <$> MathMLEntityMap.getUnicode (clean cs) of
817+ Just _ | not allowEntities -> Just $ B.str cs
818+ x -> x
808
819
809 state :: ParserState
820 state :: ParserState
810 state = def{ stateOptions = def{ readerExtensions =
821 state = def{ stateOptions = def{ readerExtensions =
src/Text/Pandoc/Readers/Org/Meta.hs+67−70
@@ -22,7 +22,7 @@ import Text.Pandoc.Readers.Org.Inlines
22import Text.Pandoc.Readers.Org.ParserState
22import Text.Pandoc.Readers.Org.ParserState
23import Text.Pandoc.Readers.Org.Parsing
23import Text.Pandoc.Readers.Org.Parsing
24
24
25−import Text.Pandoc.Builder (Blocks, Inlines, ToMetaValue)
25+import Text.Pandoc.Builder (Blocks, Inlines)
26import qualified Text.Pandoc.Builder as B
26import qualified Text.Pandoc.Builder as B
27import Text.Pandoc.Class.PandocMonad (PandocMonad)
27import Text.Pandoc.Class.PandocMonad (PandocMonad)
28import Text.Pandoc.Definition
28import Text.Pandoc.Definition
@@ -57,13 +57,13 @@ removeMeta key meta' =
57-- The order, in which blocks are tried, makes sure that we're not looking at
57-- The order, in which blocks are tried, makes sure that we're not looking at
58-- the beginning of a block, so we don't need to check for it
58-- the beginning of a block, so we don't need to check for it
59metaLine :: PandocMonad m => OrgParser m Blocks
59metaLine :: PandocMonad m => OrgParser m Blocks
60−metaLine = mempty <$ metaLineStart <* (optionLine <|> declarationLine)
60+metaLine = try $ mempty <$ metaLineStart <* keywordLine
61
61
62−declarationLine :: PandocMonad m => OrgParser m ()
62+keywordLine :: PandocMonad m => OrgParser m ()
63−declarationLine = try $ do
63+keywordLine = try $ do
64 key <- T.toLower <$> metaKey
64 key <- T.toLower <$> metaKey
65− case Map.lookup key exportSettingHandlers of
65+ case Map.lookup key keywordHandlers of
66− Nothing -> () <$ anyLine
66+ Nothing -> fail $ "Unknown keyword: " ++ T.unpack key
67 Just hd -> hd
67 Just hd -> hd
68
68
69metaKey :: Monad m => OrgParser m Text
69metaKey :: Monad m => OrgParser m Text
@@ -71,28 +71,55 @@ metaKey = T.toLower <$> many1Char (noneOf ": \n\r")
71 <* char ':'
71 <* char ':'
72 <* skipSpaces
72 <* skipSpaces
73
73
74+infix 0 ~~>
75+(~~>) :: a -> b -> (a, b)
76+a ~~> b = (a, b)
77+
74−exportSettingHandlers :: PandocMonad m => Map Text (OrgParser m ())
78+keywordHandlers :: PandocMonad m => Map Text (OrgParser m ())
75−exportSettingHandlers = Map.fromList
79+keywordHandlers = Map.fromList
80+ [ "author" ~~> lineOfInlines `parseThen` collectLines "author"
76− [ ("result" , fmap pure anyLine `parseThen` discard)
81+ , "creator" ~~> fmap pure anyLine `parseThen` B.setMeta "creator"
77− -- Common settings
82+ , "date" ~~> lineOfInlines `parseThen` B.setMeta "date"
78− , ("author" , lineOfInlines `parseThen` collectLines "author")
83+ , "description" ~~> lineOfInlines `parseThen` collectLines "description"
79− , ("date" , lineOfInlines `parseThen` setField "date")
84+ , "email" ~~> fmap pure anyLine `parseThen` B.setMeta "email"
85+ , "exclude_tags" ~~> tagList >>= updateState . setExcludedTags
86+ , "header-includes" ~~>
80− , ("description", lineOfInlines `parseThen` collectLines "description")
87+ lineOfInlines `parseThen` collectLines "header-includes"
88+ -- HTML-specifix export settings
89+ , "html_head" ~~>
90+ metaExportSnippet "html" `parseThen` collectAsList "header-includes"
91+ , "html_head_extra" ~~>
92+ metaExportSnippet "html" `parseThen` collectAsList "header-includes"
81− , ("keywords" , lineOfInlines `parseThen` collectLines "keywords")
93+ , "institute" ~~> lineOfInlines `parseThen` collectLines "institute"
94+ -- topic keywords
82− , ("title" , lineOfInlines `parseThen` collectLines "title")
95+ , "keywords" ~~> lineOfInlines `parseThen` collectLines "keywords"
83− -- LaTeX
96+ -- LaTeX-specific export settings
84− , ("latex_class", fmap pure anyLine `parseThen` setField "documentclass")
97+ , "latex_class" ~~> fmap pure anyLine `parseThen` B.setMeta "documentclass"
98+ , "latex_class_options" ~~>
85− , ("latex_class_options", (pure . T.filter (`notElem` ("[]" :: String)) <$> anyLine)
99+ (pure . T.filter (`notElem` ("[]" :: String)) <$> anyLine)
86− `parseThen` setField "classoption")
100+ `parseThen` B.setMeta "classoption"
87− , ("latex_header", metaExportSnippet "latex" `parseThen`
101+ , "latex_header" ~~>
88− collectAsList "header-includes")
102+ metaExportSnippet "latex" `parseThen` collectAsList "header-includes"
89− -- HTML
103+ , "latex_header_extra" ~~>
90− , ("html_head" , metaExportSnippet "html" `parseThen`
91− collectAsList "header-includes")
104+ metaExportSnippet "latex" `parseThen` collectAsList "header-includes"
105+ -- link and macro
106+ , "link" ~~> addLinkFormatter
107+ , "macro" ~~> macroDefinition >>= updateState . registerMacro
92− -- pandoc-specific
108+ -- pandoc-specific way to include references in the bibliography
93− , ("nocite" , lineOfInlines `parseThen` collectLines "nocite")
109+ , "nocite" ~~> lineOfInlines `parseThen` collectLines "nocite"
110+ -- compact way to set export settings
111+ , "options" ~~> exportSettings
112+ -- pandoc-specific way to configure emphasis recognition
113+ , "pandoc-emphasis-post" ~~> emphChars >>= updateState . setEmphasisPostChar
114+ , "pandoc-emphasis-pre" ~~> emphChars >>= updateState . setEmphasisPreChar
115+ -- result markers (ignored)
116+ , "result" ~~> void anyLine
117+ , "select_tags" ~~> tagList >>= updateState . setSelectedTags
118+ , "seq_todo" ~~> todoSequence >>= updateState . registerTodoSequence
94− , ("header-includes", lineOfInlines `parseThen` collectLines "header-includes")
119+ , "subtitle" ~~> lineOfInlines `parseThen` collectLines "subtitle"
95− , ("institute" , lineOfInlines `parseThen` collectLines "institute")
120+ , "title" ~~> lineOfInlines `parseThen` collectLines "title"
121+ , "todo" ~~> todoSequence >>= updateState . registerTodoSequence
122+ , "typ_todo" ~~> todoSequence >>= updateState . registerTodoSequence
96 ]
123 ]
97
124
98parseThen :: PandocMonad m
125parseThen :: PandocMonad m
@@ -104,9 +131,6 @@ parseThen p modMeta = do
104 meta <- orgStateMeta <$> getState
131 meta <- orgStateMeta <$> getState
105 updateState (\st -> st { orgStateMeta = modMeta <$> value <*> meta })
132 updateState (\st -> st { orgStateMeta = modMeta <$> value <*> meta })
106
133
107−discard :: a -> Meta -> Meta
108−discard = const id
109−
110collectLines :: Text -> Inlines -> Meta -> Meta
134collectLines :: Text -> Inlines -> Meta -> Meta
111collectLines key value meta =
135collectLines key value meta =
112 let value' = appendValue meta (B.toList value)
136 let value' = appendValue meta (B.toList value)
@@ -141,51 +165,25 @@ collectAsList key value meta =
141 Just x -> [x]
165 Just x -> [x]
142 _ -> []
166 _ -> []
143
167
144−setField :: ToMetaValue a => Text -> a -> Meta -> Meta
145−setField field value meta = B.setMeta field (B.toMetaValue value) meta
146−
147-- | Read an format specific meta definition
168-- | Read an format specific meta definition
148metaExportSnippet :: Monad m => Text -> OrgParser m (F Inlines)
169metaExportSnippet :: Monad m => Text -> OrgParser m (F Inlines)
149metaExportSnippet format = pure . B.rawInline format <$> anyLine
170metaExportSnippet format = pure . B.rawInline format <$> anyLine
150
171
151−--
172+-- | Parse a link type definition (like @wp https://en.wikipedia.org/wiki/@).
152−-- export options
153−--
154−optionLine :: PandocMonad m => OrgParser m ()
155−optionLine = try $ do
156− key <- metaKey
157− case key of
158− "link" -> parseLinkFormat >>= uncurry addLinkFormat
159− "options" -> exportSettings
160− "todo" -> todoSequence >>= updateState . registerTodoSequence
161− "seq_todo" -> todoSequence >>= updateState . registerTodoSequence
162− "typ_todo" -> todoSequence >>= updateState . registerTodoSequence
163− "macro" -> macroDefinition >>= updateState . registerMacro
164− "exclude_tags" -> tagList >>= updateState . setExcludedTags
165− "select_tags" -> tagList >>= updateState . setSelectedTags
166− "pandoc-emphasis-pre" -> emphChars >>= updateState . setEmphasisPreChar
167− "pandoc-emphasis-post" -> emphChars >>= updateState . setEmphasisPostChar
168− _ -> mzero
169−
170−addLinkFormat :: Monad m => Text
171− -> (Text -> Text)
172− -> OrgParser m ()
173−addLinkFormat key formatter = updateState $ \s ->
174− let fs = orgStateLinkFormatters s
175− in s{ orgStateLinkFormatters = Map.insert key formatter fs }
176−
177−parseLinkFormat :: Monad m => OrgParser m (Text, Text -> Text)
173+addLinkFormatter :: Monad m => OrgParser m ()
178−parseLinkFormat = try $ do
174+addLinkFormatter = try $ do
179 linkType <- T.cons <$> letter <*> manyChar (alphaNum <|> oneOf "-_") <* skipSpaces
175 linkType <- T.cons <$> letter <*> manyChar (alphaNum <|> oneOf "-_") <* skipSpaces
180− linkSubst <- parseFormat
176+ formatter <- parseFormat
181− return (linkType, linkSubst)
177+ updateState $ \s ->
178+ let fs = orgStateLinkFormatters s
179+ in s{ orgStateLinkFormatters = Map.insert linkType formatter fs }
182
180
183-- | An ad-hoc, single-argument-only implementation of a printf-style format
181-- | An ad-hoc, single-argument-only implementation of a printf-style format
184-- parser.
182-- parser.
185parseFormat :: Monad m => OrgParser m (Text -> Text)
183parseFormat :: Monad m => OrgParser m (Text -> Text)
186parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend
184parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend
187 where
185 where
188− -- inefficient, but who cares
186+ -- inefficient
189 replacePlain = try $ (\x -> T.concat . flip intersperse x)
187 replacePlain = try $ (\x -> T.concat . flip intersperse x)
190 <$> sequence [tillSpecifier 's', rest]
188 <$> sequence [tillSpecifier 's', rest]
191 replaceUrl = try $ (\x -> T.concat . flip intersperse x . T.pack . urlEncode . T.unpack)
189 replaceUrl = try $ (\x -> T.concat . flip intersperse x . T.pack . urlEncode . T.unpack)
@@ -224,6 +222,7 @@ setEmphasisPostChar csMb st =
224 let postChars = fromMaybe (orgStateEmphasisPostChars defaultOrgParserState) csMb
222 let postChars = fromMaybe (orgStateEmphasisPostChars defaultOrgParserState) csMb
225 in st { orgStateEmphasisPostChars = postChars }
223 in st { orgStateEmphasisPostChars = postChars }
226
224
225+-- | Parses emphasis border character like @".,?!"@
227emphChars :: Monad m => OrgParser m (Maybe [Char])
226emphChars :: Monad m => OrgParser m (Maybe [Char])
228emphChars = do
227emphChars = do
229 skipSpaces
228 skipSpaces
@@ -234,16 +233,14 @@ lineOfInlines = do
234 updateLastPreCharPos
233 updateLastPreCharPos
235 trimInlinesF . mconcat <$> manyTill inline newline
234 trimInlinesF . mconcat <$> manyTill inline newline
236
235
237−--
236+-- | Parses ToDo sequences / keywords like @TODO DOING | DONE@.
238−-- ToDo Sequences and Keywords
239−--
240todoSequence :: Monad m => OrgParser m TodoSequence
237todoSequence :: Monad m => OrgParser m TodoSequence
241todoSequence = try $ do
238todoSequence = try $ do
242 todoKws <- todoKeywords
239 todoKws <- todoKeywords
243 doneKws <- optionMaybe $ todoDoneSep *> todoKeywords
240 doneKws <- optionMaybe $ todoDoneSep *> todoKeywords
244 newline
241 newline
245− -- There must be at least one DONE keyword. The last TODO keyword is taken if
242+ -- There must be at least one DONE keyword. The last TODO keyword is
246− -- necessary.
243+ -- taken if necessary.
247 case doneKws of
244 case doneKws of
248 Just done -> return $ keywordsToSequence todoKws done
245 Just done -> return $ keywordsToSequence todoKws done
249 Nothing -> case reverse todoKws of
246 Nothing -> case reverse todoKws of
src/Text/Pandoc/Readers/Org/ParserState.hs+6
@@ -257,9 +257,12 @@ data ExportSettings = ExportSettings
257 , exportWithAuthor :: Bool -- ^ Include author in final meta-data
257 , exportWithAuthor :: Bool -- ^ Include author in final meta-data
258 , exportWithCreator :: Bool -- ^ Include creator in final meta-data
258 , exportWithCreator :: Bool -- ^ Include creator in final meta-data
259 , exportWithEmail :: Bool -- ^ Include email in final meta-data
259 , exportWithEmail :: Bool -- ^ Include email in final meta-data
260+ , exportWithEntities :: Bool -- ^ Include MathML-like entities
261+ , exportWithFootnotes :: Bool -- ^ Include footnotes
260 , exportWithLatex :: TeXExport -- ^ Handling of raw TeX commands
262 , exportWithLatex :: TeXExport -- ^ Handling of raw TeX commands
261 , exportWithPlanning :: Bool -- ^ Keep planning info after headlines
263 , exportWithPlanning :: Bool -- ^ Keep planning info after headlines
262 , exportWithTags :: Bool -- ^ Keep tags as part of headlines
264 , exportWithTags :: Bool -- ^ Keep tags as part of headlines
265+ , exportWithTables :: Bool -- ^ Include tables
263 , exportWithTodoKeywords :: Bool -- ^ Keep TODO keywords in headers
266 , exportWithTodoKeywords :: Bool -- ^ Keep TODO keywords in headers
264 }
267 }
265
268
@@ -279,8 +282,11 @@ defaultExportSettings = ExportSettings
279 , exportWithAuthor = True
282 , exportWithAuthor = True
280 , exportWithCreator = True
283 , exportWithCreator = True
281 , exportWithEmail = True
284 , exportWithEmail = True
285+ , exportWithEntities = True
286+ , exportWithFootnotes = True
282 , exportWithLatex = TeXExport
287 , exportWithLatex = TeXExport
283 , exportWithPlanning = False
288 , exportWithPlanning = False
284 , exportWithTags = True
289 , exportWithTags = True
290+ , exportWithTables = True
285 , exportWithTodoKeywords = True
291 , exportWithTodoKeywords = True
286 }
292 }
src/Text/Pandoc/Readers/RST.hs+4−3
@@ -223,7 +223,8 @@ rawFieldListItem minIndent = try $ do
223 first <- anyLine
223 first <- anyLine
224 rest <- option "" $ try $ do lookAhead (count indent (char ' ') >> spaceChar)
224 rest <- option "" $ try $ do lookAhead (count indent (char ' ') >> spaceChar)
225 indentedBlock
225 indentedBlock
226− let raw = (if T.null first then "" else first <> "\n") <> rest <> "\n"
226+ let raw = (if T.null first then "" else first <> "\n") <> rest <>
227+ (if T.null first && T.null rest then "" else "\n")
227 return (name, raw)
228 return (name, raw)
228
229
229fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks])
230fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks])
@@ -484,7 +485,7 @@ includeDirective top fields body = do
484 Just patt -> drop 1 .
485 Just patt -> drop 1 .
485 dropWhile (not . (patt `T.isInfixOf`))
486 dropWhile (not . (patt `T.isInfixOf`))
486 Nothing -> id) $ contentLines'
487 Nothing -> id) $ contentLines'
487− let contents' = T.unlines contentLines'' <> "\n"
488+ let contents' = T.unlines contentLines''
488 case lookup "code" fields of
489 case lookup "code" fields of
489 Just lang -> do
490 Just lang -> do
490 let classes = maybe [] T.words (lookup "class" fields)
491 let classes = maybe [] T.words (lookup "class" fields)
@@ -494,7 +495,7 @@ includeDirective top fields body = do
494 Just _ -> return $ B.rawBlock "rst" contents'
495 Just _ -> return $ B.rawBlock "rst" contents'
495 Nothing -> do
496 Nothing -> do
496 setPosition $ newPos (T.unpack f) 1 1
497 setPosition $ newPos (T.unpack f) 1 1
497− setInput contents'
498+ setInput $ contents' <> "\n"
498 bs <- optional blanklines >>
499 bs <- optional blanklines >>
499 (mconcat <$> many block)
500 (mconcat <$> many block)
500 setInput oldInput
501 setInput oldInput
src/Text/Pandoc/Templates.hs+1
@@ -97,6 +97,7 @@ getDefaultTemplate writer = do
97 "markdown_mmd" -> getDefaultTemplate "markdown"
97 "markdown_mmd" -> getDefaultTemplate "markdown"
98 "markdown_phpextra" -> getDefaultTemplate "markdown"
98 "markdown_phpextra" -> getDefaultTemplate "markdown"
99 "gfm" -> getDefaultTemplate "commonmark"
99 "gfm" -> getDefaultTemplate "commonmark"
100+ "commonmark_x" -> getDefaultTemplate "commonmark"
100 _ -> do
101 _ -> do
101 let fname = "templates" </> "default" <.> T.unpack format
102 let fname = "templates" </> "default" <.> T.unpack format
102 UTF8.toText <$> readDataFile fname
103 UTF8.toText <$> readDataFile fname
src/Text/Pandoc/Writers.hs+1
@@ -178,6 +178,7 @@ writers = [
178 ,("asciidoctor" , TextWriter writeAsciiDoctor)
178 ,("asciidoctor" , TextWriter writeAsciiDoctor)
179 ,("haddock" , TextWriter writeHaddock)
179 ,("haddock" , TextWriter writeHaddock)
180 ,("commonmark" , TextWriter writeCommonMark)
180 ,("commonmark" , TextWriter writeCommonMark)
181+ ,("commonmark_x" , TextWriter writeCommonMark)
181 ,("gfm" , TextWriter writeCommonMark)
182 ,("gfm" , TextWriter writeCommonMark)
182 ,("tei" , TextWriter writeTEI)
183 ,("tei" , TextWriter writeTEI)
183 ,("muse" , TextWriter writeMuse)
184 ,("muse" , TextWriter writeMuse)
src/Text/Pandoc/Writers/CommonMark.hs+1−349
@@ -15,353 +15,5 @@ CommonMark: <http://commonmark.org>
15-}
15-}
16module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
16module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
17
17
18−import CMarkGFM
18+import Text.Pandoc.Writers.Markdown (writeCommonMark)
19−import Control.Monad.State.Strict (State, get, modify, runState)
20−import Data.Char (isAscii)
21−import Data.Foldable (foldrM)
22−import Data.List (transpose)
23−import Data.Text (Text)
24−import qualified Data.Text as T
25−import Network.HTTP (urlEncode)
26−import Text.Pandoc.Class.PandocMonad (PandocMonad)
27−import Text.Pandoc.Definition
28−import Text.Pandoc.Options
29−import Text.Pandoc.Shared (capitalize, isTightList,
30− linesToPara, onlySimpleTableCells, taskListItemToAscii, tshow)
31−import Text.Pandoc.Templates (renderTemplate)
32−import Text.Pandoc.Walk (walk, walkM)
33−import Text.Pandoc.Writers.HTML (writeHtml5String, tagWithAttributes)
34−import Text.Pandoc.Writers.Shared
35−import Text.Pandoc.XML (toHtml5Entities)
36−import Text.DocLayout (literal, render)
37
19
38−-- | Convert Pandoc to CommonMark.
39−writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
40−writeCommonMark opts (Pandoc meta blocks) = do
41− toc <- if writerTableOfContents opts
42− then blocksToCommonMark opts [ toTableOfContents opts blocks ]
43− else return mempty
44−
45− let (blocks', notes) = runState (walkM processNotes blocks) []
46− notes' = [OrderedList (1, Decimal, Period) $ reverse notes | not (null notes)]
47− main <- blocksToCommonMark opts (blocks' ++ notes')
48− metadata <- metaToContext opts
49− (fmap (literal . T.stripEnd) . blocksToCommonMark opts)
50− (fmap (literal . T.stripEnd) . inlinesToCommonMark opts)
51− meta
52− let context =
53− -- for backwards compatibility we populate toc
54− -- with the contents of the toc, rather than a boolean:
55− defField "toc" toc
56− $ defField "table-of-contents" toc
57− $ defField "body" main metadata
58− return $
59− case writerTemplate opts of
60− Nothing -> main
61− Just tpl -> render Nothing $ renderTemplate tpl context
62−
63−softBreakToSpace :: Inline -> Inline
64−softBreakToSpace SoftBreak = Space
65−softBreakToSpace x = x
66−
67−processNotes :: Inline -> State [[Block]] Inline
68−processNotes (Note bs) = do
69− modify (bs :)
70− notes <- get
71− return $ Str $ "[" <> tshow (length notes) <> "]"
72−processNotes x = return x
73−
74−node :: NodeType -> [Node] -> Node
75−node = Node Nothing
76−
77−blocksToCommonMark :: PandocMonad m => WriterOptions -> [Block] -> m Text
78−blocksToCommonMark opts bs = do
79− let cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
80− colwidth = if writerWrapText opts == WrapAuto
81− then Just $ writerColumns opts
82− else Nothing
83− nodes <- blocksToNodes opts bs
84− return $ T.stripEnd $
85− nodeToCommonmark cmarkOpts colwidth $
86− node DOCUMENT nodes
87−
88−inlinesToCommonMark :: PandocMonad m => WriterOptions -> [Inline] -> m Text
89−inlinesToCommonMark opts ils = return $
90− nodeToCommonmark cmarkOpts colwidth $
91− node PARAGRAPH (inlinesToNodes opts ils)
92− where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
93− colwidth = if writerWrapText opts == WrapAuto
94− then Just $ writerColumns opts
95− else Nothing
96−
97−blocksToNodes :: PandocMonad m => WriterOptions -> [Block] -> m [Node]
98−blocksToNodes opts = foldrM (blockToNodes opts) []
99−
100−blockToNodes :: PandocMonad m => WriterOptions -> Block -> [Node] -> m [Node]
101−blockToNodes opts (Plain xs) ns =
102− return (node PARAGRAPH (inlinesToNodes opts xs) : ns)
103−blockToNodes opts (Para xs) ns =
104− return (node PARAGRAPH (inlinesToNodes opts xs) : ns)
105−blockToNodes opts (LineBlock lns) ns = blockToNodes opts (linesToPara lns) ns
106−blockToNodes _ (CodeBlock (_,classes,_) xs) ns = return
107− (node (CODE_BLOCK (T.unwords classes) xs) [] : ns)
108−blockToNodes opts (RawBlock (Format f) xs) ns
109− | f == "html" && isEnabled Ext_raw_html opts
110− = return (node (HTML_BLOCK xs) [] : ns)
111− | (f == "latex" || f == "tex") && isEnabled Ext_raw_tex opts
112− = return (node (CUSTOM_BLOCK xs T.empty) [] : ns)
113− | f == "markdown"
114− = return (node (CUSTOM_BLOCK xs T.empty) [] : ns)
115− | otherwise = return ns
116−blockToNodes opts (BlockQuote bs) ns = do
117− nodes <- blocksToNodes opts bs
118− return (node BLOCK_QUOTE nodes : ns)
119−blockToNodes opts (BulletList items) ns = do
120− let exts = writerExtensions opts
121− nodes <- mapM (blocksToNodes opts . taskListItemToAscii exts) items
122− return (node (LIST ListAttributes{
123− listType = BULLET_LIST,
124− listDelim = PERIOD_DELIM,
125− listTight = isTightList items,
126− listStart = 1 }) (map (node ITEM) nodes) : ns)
127−blockToNodes opts (OrderedList (start, _sty, delim) items) ns = do
128− let exts = writerExtensions opts
129− nodes <- mapM (blocksToNodes opts . taskListItemToAscii exts) items
130− return (node (LIST ListAttributes{
131− listType = ORDERED_LIST,
132− listDelim = case delim of
133− OneParen -> PAREN_DELIM
134− TwoParens -> PAREN_DELIM
135− _ -> PERIOD_DELIM,
136− listTight = isTightList items,
137− listStart = start }) (map (node ITEM) nodes) : ns)
138−blockToNodes _ HorizontalRule ns = return (node THEMATIC_BREAK [] : ns)
139−blockToNodes opts (Header lev _ ils) ns =
140− return (node (HEADING lev) (inlinesToNodes opts ils) : ns)
141−blockToNodes opts (Div attr bs) ns = do
142− nodes <- blocksToNodes opts bs
143− let op = tagWithAttributes opts True False "div" attr
144− if isEnabled Ext_raw_html opts
145− then return (node (HTML_BLOCK op) [] : nodes ++
146− [node (HTML_BLOCK (T.pack "</div>")) []] ++ ns)
147− else return (nodes ++ ns)
148−blockToNodes opts (DefinitionList items) ns =
149− blockToNodes opts (BulletList items') ns
150− where items' = map dlToBullet items
151− dlToBullet (term, (Para xs : ys) : zs) =
152− Para (term ++ [LineBreak] ++ xs) : ys ++ concat zs
153− dlToBullet (term, (Plain xs : ys) : zs) =
154− Plain (term ++ [LineBreak] ++ xs) : ys ++ concat zs
155− dlToBullet (term, xs) =
156− Para term : concat xs
157−blockToNodes opts t@(Table _ blkCapt specs thead tbody tfoot) ns =
158− let (capt, aligns, _widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
159− in if isEnabled Ext_pipe_tables opts && onlySimpleTableCells (headers : rows)
160− then do
161− -- We construct a table manually as a CUSTOM_BLOCK, for
162− -- two reasons: (1) cmark-gfm currently doesn't support
163− -- rendering TABLE nodes; (2) we can align the column sides;
164− -- (3) we can render the caption as a regular paragraph.
165− let capt' = node PARAGRAPH (inlinesToNodes opts capt)
166− -- backslash | in code and raw:
167− let fixPipe (Code attr xs) =
168− Code attr (T.replace "|" "\\|" xs)
169− fixPipe (RawInline format xs) =
170− RawInline format (T.replace "|" "\\|" xs)
171− fixPipe x = x
172− let toCell [Plain ils] = T.strip
173− $ nodeToCommonmark [] Nothing
174− $ node (CUSTOM_INLINE mempty mempty)
175− $ inlinesToNodes opts
176− $ walk (fixPipe . softBreakToSpace) ils
177− toCell [Para ils] = T.strip
178− $ nodeToCommonmark [] Nothing
179− $ node (CUSTOM_INLINE mempty mempty)
180− $ inlinesToNodes opts
181− $ walk (fixPipe . softBreakToSpace) ils
182− toCell [] = ""
183− toCell xs = error $ "toCell encountered " ++ show xs
184− let separator = " | "
185− let starter = "| "
186− let ender = " |"
187− let rawheaders = map toCell headers
188− let rawrows = map (map toCell) rows
189− let maximum' [] = 0
190− maximum' xs = maximum xs
191− let colwidths = map (maximum' . map T.length) $
192− transpose (rawheaders:rawrows)
193− let toHeaderLine len AlignDefault = T.replicate len "-"
194− toHeaderLine len AlignLeft = ":" <>
195− T.replicate (max (len - 1) 1) "-"
196− toHeaderLine len AlignRight =
197− T.replicate (max (len - 1) 1) "-" <> ":"
198− toHeaderLine len AlignCenter = ":" <>
199− T.replicate (max (len - 2) 1) (T.pack "-") <> ":"
200− let rawheaderlines = zipWith toHeaderLine colwidths aligns
201− let headerlines = starter <> T.intercalate separator rawheaderlines <>
202− ender
203− let padContent (align, w) t' =
204− let padding = w - T.length t'
205− halfpadding = padding `div` 2
206− in case align of
207− AlignRight -> T.replicate padding " " <> t'
208− AlignCenter -> T.replicate halfpadding " " <> t' <>
209− T.replicate (padding - halfpadding) " "
210− _ -> t' <> T.replicate padding " "
211− let toRow xs = starter <> T.intercalate separator
212− (zipWith padContent (zip aligns colwidths) xs) <>
213− ender
214− let table' = toRow rawheaders <> "\n" <> headerlines <> "\n" <>
215− T.intercalate "\n" (map toRow rawrows)
216− return (node (CUSTOM_BLOCK table' mempty) [] :
217− if null capt
218− then ns
219− else capt' : ns)
220− else do -- fall back to raw HTML
221− s <- writeHtml5String def $! Pandoc nullMeta [t]
222− return (node (HTML_BLOCK s) [] : ns)
223−blockToNodes _ Null ns = return ns
224−
225−inlinesToNodes :: WriterOptions -> [Inline] -> [Node]
226−inlinesToNodes opts = foldr (inlineToNodes opts) []
227−
228−inlineToNodes :: WriterOptions -> Inline -> [Node] -> [Node]
229−inlineToNodes opts (Str s) = stringToNodes opts s'
230− where s' = if isEnabled Ext_smart opts
231− then unsmartify opts s
232− else s
233−inlineToNodes _ Space = (node (TEXT (T.pack " ")) [] :)
234−inlineToNodes _ LineBreak = (node LINEBREAK [] :)
235−inlineToNodes opts SoftBreak
236− | isEnabled Ext_hard_line_breaks opts = (node (TEXT " ") [] :)
237− | writerWrapText opts == WrapNone = (node (TEXT " ") [] :)
238− | otherwise = (node SOFTBREAK [] :)
239−inlineToNodes opts (Emph xs) = (node EMPH (inlinesToNodes opts xs) :)
240−inlineToNodes opts (Underline xs)
241− | isEnabled Ext_raw_html opts =
242− ((node (HTML_INLINE (T.pack "<u>")) [] : inlinesToNodes opts xs ++
243− [node (HTML_INLINE (T.pack "</u>")) []]) ++ )
244− | otherwise = (node EMPH (inlinesToNodes opts xs) :)
245−inlineToNodes opts (Strong xs) = (node STRONG (inlinesToNodes opts xs) :)
246−inlineToNodes opts (Strikeout xs)
247− | isEnabled Ext_strikeout opts = (node (CUSTOM_INLINE "~~" "~~") (inlinesToNodes opts xs) :)
248− | isEnabled Ext_raw_html opts = ((node (HTML_INLINE (T.pack "<s>")) [] : inlinesToNodes opts xs ++
249− [node (HTML_INLINE (T.pack "</s>")) []]) ++ )
250− | otherwise = (inlinesToNodes opts xs ++)
251−inlineToNodes opts (Superscript xs) =
252− if isEnabled Ext_raw_html opts
253− then ((node (HTML_INLINE (T.pack "<sup>")) [] : inlinesToNodes opts xs ++
254− [node (HTML_INLINE (T.pack "</sup>")) []]) ++ )
255− else case traverse toSuperscriptInline xs of
256− Just xs' | not (writerPreferAscii opts)
257− -> (inlinesToNodes opts xs' ++)
258− _ ->
259− ((node (TEXT (T.pack "^(")) [] : inlinesToNodes opts xs ++
260− [node (TEXT (T.pack ")")) []]) ++ )
261−inlineToNodes opts (Subscript xs) =
262− if isEnabled Ext_raw_html opts
263− then ((node (HTML_INLINE (T.pack "<sub>")) [] : inlinesToNodes opts xs ++
264− [node (HTML_INLINE (T.pack "</sub>")) []]) ++ )
265− else case traverse toSubscriptInline xs of
266− Just xs' | not (writerPreferAscii opts)
267− -> (inlinesToNodes opts xs' ++)
268− _ ->
269− ((node (TEXT (T.pack "_(")) [] : inlinesToNodes opts xs ++
270− [node (TEXT (T.pack ")")) []]) ++ )
271−inlineToNodes opts (SmallCaps xs) =
272− if isEnabled Ext_raw_html opts
273− then ((node (HTML_INLINE (T.pack "<span class=\"smallcaps\">")) []
274− : inlinesToNodes opts xs ++
275− [node (HTML_INLINE (T.pack "</span>")) []]) ++ )
276− else (inlinesToNodes opts (capitalize xs) ++)
277−inlineToNodes opts (Link _ ils (url,tit)) =
278− (node (LINK url tit) (inlinesToNodes opts ils) :)
279−-- title beginning with fig: indicates implicit figure
280−inlineToNodes opts (Image alt ils (url,T.stripPrefix "fig:" -> Just tit)) =
281− inlineToNodes opts (Image alt ils (url,tit))
282−inlineToNodes opts (Image _ ils (url,tit)) =
283− (node (IMAGE url tit) (inlinesToNodes opts ils) :)
284−inlineToNodes opts (RawInline (Format f) xs)
285− | f == "html" && isEnabled Ext_raw_html opts
286− = (node (HTML_INLINE xs) [] :)
287− | (f == "latex" || f == "tex") && isEnabled Ext_raw_tex opts
288− = (node (CUSTOM_INLINE xs T.empty) [] :)
289− | f == "markdown"
290− = (node (CUSTOM_INLINE xs T.empty) [] :)
291− | otherwise = id
292−inlineToNodes opts (Quoted qt ils) =
293− ((node (HTML_INLINE start) [] :
294− inlinesToNodes opts ils ++ [node (HTML_INLINE end) []]) ++)
295− where (start, end) = case qt of
296− SingleQuote
297− | isEnabled Ext_smart opts -> ("'","'")
298− | writerPreferAscii opts ->
299− ("&lsquo;", "&rsquo;")
300− | otherwise -> ("‘", "’")
301− DoubleQuote
302− | isEnabled Ext_smart opts -> ("\"", "\"")
303− | writerPreferAscii opts ->
304− ("&ldquo;", "&rdquo;")
305− | otherwise -> ("“", "”")
306−inlineToNodes _ (Code _ str) = (node (CODE str) [] :)
307−inlineToNodes opts (Math mt str) =
308− case writerHTMLMathMethod opts of
309− WebTeX url ->
310− let core = inlineToNodes opts
311− (Image nullAttr [Str str] (url <> T.pack (urlEncode $ T.unpack str), str))
312− sep = if mt == DisplayMath
313− then (node LINEBREAK [] :)
314− else id
315− in (sep . core . sep)
316− _ ->
317− case mt of
318− InlineMath ->
319− (node (HTML_INLINE ("\\(" <> str <> "\\)")) [] :)
320− DisplayMath ->
321− (node (HTML_INLINE ("\\[" <> str <> "\\]")) [] :)
322−inlineToNodes opts (Span ("",["emoji"],kvs) [Str s]) =
323− case lookup "data-emoji" kvs of
324− Just emojiname | isEnabled Ext_emoji opts ->
325− (node (TEXT (":" <> emojiname <> ":")) [] :)
326− _ -> (node (TEXT s) [] :)
327−inlineToNodes opts (Span attr ils) =
328− let nodes = inlinesToNodes opts ils
329− op = tagWithAttributes opts True False "span" attr
330− in if isEnabled Ext_raw_html opts
331− then ((node (HTML_INLINE op) [] : nodes ++
332− [node (HTML_INLINE (T.pack "</span>")) []]) ++)
333− else (nodes ++)
334−inlineToNodes opts (Cite _ ils) = (inlinesToNodes opts ils ++)
335−inlineToNodes _ (Note _) = id -- should not occur
336−-- we remove Note elements in preprocessing
337−
338−stringToNodes :: WriterOptions -> Text -> [Node] -> [Node]
339−stringToNodes opts s
340− | not (writerPreferAscii opts) = (node (TEXT s) [] :)
341− | otherwise = step s
342− where
343− step input =
344− let (ascii, rest) = T.span isAscii input
345− this = node (TEXT ascii) []
346− nodes = case T.uncons rest of
347− Nothing -> id
348− Just (nonAscii, rest') ->
349− let escaped = toHtml5Entities (T.singleton nonAscii)
350− in (node (HTML_INLINE escaped) [] :) . step rest'
351− in (this :) . nodes
352−
353−toSubscriptInline :: Inline -> Maybe Inline
354−toSubscriptInline Space = Just Space
355−toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils
356−toSubscriptInline (Str s) = Str . T.pack <$> traverse toSubscript (T.unpack s)
357−toSubscriptInline LineBreak = Just LineBreak
358−toSubscriptInline SoftBreak = Just SoftBreak
359−toSubscriptInline _ = Nothing
360−
361−toSuperscriptInline :: Inline -> Maybe Inline
362−toSuperscriptInline Space = Just Space
363−toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils
364−toSuperscriptInline (Str s) = Str . T.pack <$> traverse toSuperscript (T.unpack s)
365−toSuperscriptInline LineBreak = Just LineBreak
366−toSuperscriptInline SoftBreak = Just SoftBreak
367−toSuperscriptInline _ = Nothing
src/Text/Pandoc/Writers/Jira.hs+12−10
@@ -194,7 +194,7 @@ toJiraInlines inlines = do
194 Jira.Monospaced (escapeSpecialChars cs)
194 Jira.Monospaced (escapeSpecialChars cs)
195 Emph xs -> styled Jira.Emphasis xs
195 Emph xs -> styled Jira.Emphasis xs
196 Underline xs -> styled Jira.Insert xs
196 Underline xs -> styled Jira.Insert xs
197− Image attr _ tgt -> imageToJira attr (fst tgt) (snd tgt)
197+ Image attr cap tgt -> imageToJira attr cap (fst tgt) (snd tgt)
198 LineBreak -> pure . singleton $ Jira.Linebreak
198 LineBreak -> pure . singleton $ Jira.Linebreak
199 Link attr xs tgt -> toJiraLink attr tgt xs
199 Link attr xs tgt -> toJiraLink attr tgt xs
200 Math mtype cs -> mathToJira mtype cs
200 Math mtype cs -> mathToJira mtype cs
@@ -233,16 +233,18 @@ escapeSpecialChars t = case plainText t of
233 Left _ -> singleton $ Jira.Str t
233 Left _ -> singleton $ Jira.Str t
234
234
235imageToJira :: PandocMonad m
235imageToJira :: PandocMonad m
236− => Attr -> Text -> Text
236+ => Attr -> [Inline] -> Text -> Text
237 -> JiraConverter m [Jira.Inline]
237 -> JiraConverter m [Jira.Inline]
238−imageToJira (_, classes, kvs) src title =
238+imageToJira (_, classes, kvs) caption src title =
239+ let imageWithParams ps = Jira.Image ps (Jira.URL src)
240+ alt = stringify caption
241+ in pure . singleton . imageWithParams $
239− let imgParams = if "thumbnail" `elem` classes
242+ if "thumbnail" `elem` classes
240− then [Jira.Parameter "thumbnail" ""]
243+ then [Jira.Parameter "thumbnail" ""]
241− else map (uncurry Jira.Parameter) kvs
244+ else map (uncurry Jira.Parameter)
242− imgParams' = if T.null title
245+ . (if T.null title then id else (("title", title):))
243− then imgParams
246+ . (if T.null alt then id else (("alt", alt):))
244− else Jira.Parameter "title" title : imgParams
247+ $ kvs
245− in pure . singleton $ Jira.Image imgParams' (Jira.URL src)
246
248
247-- | Creates a Jira Link element.
249-- | Creates a Jira Link element.
248toJiraLink :: PandocMonad m
250toJiraLink :: PandocMonad m
src/Text/Pandoc/Writers/Markdown.hs+144−100
@@ -16,7 +16,10 @@ Conversion of 'Pandoc' documents to markdown-formatted plain text.
16
16
17Markdown: <http://daringfireball.net/projects/markdown/>
17Markdown: <http://daringfireball.net/projects/markdown/>
18-}
18-}
19−module Text.Pandoc.Writers.Markdown (writeMarkdown, writePlain) where
19+module Text.Pandoc.Writers.Markdown (
20+ writeMarkdown,
21+ writeCommonMark,
22+ writePlain) where
20import Control.Monad.Reader
23import Control.Monad.Reader
21import Control.Monad.State.Strict
24import Control.Monad.State.Strict
22import Data.Char (isAlphaNum)
25import Data.Char (isAlphaNum)
@@ -55,15 +58,21 @@ evalMD :: PandocMonad m => MD m a -> WriterEnv -> WriterState -> m a
55evalMD md env st = evalStateT (runReaderT md env) st
58evalMD md env st = evalStateT (runReaderT md env) st
56
59
57data WriterEnv = WriterEnv { envInList :: Bool
60data WriterEnv = WriterEnv { envInList :: Bool
58− , envPlain :: Bool
61+ , envVariant :: MarkdownVariant
59 , envRefShortcutable :: Bool
62 , envRefShortcutable :: Bool
60 , envBlockLevel :: Int
63 , envBlockLevel :: Int
61 , envEscapeSpaces :: Bool
64 , envEscapeSpaces :: Bool
62 }
65 }
63
66
67+data MarkdownVariant =
68+ PlainText
69+ | Commonmark
70+ | Markdown
71+ deriving (Show, Eq)
72+
64instance Default WriterEnv
73instance Default WriterEnv
65− where def = WriterEnv { envInList = False
74+ where def = WriterEnv { envInList = False
66− , envPlain = False
75+ , envVariant = Markdown
67 , envRefShortcutable = True
76 , envRefShortcutable = True
68 , envBlockLevel = 0
77 , envBlockLevel = 0
69 , envEscapeSpaces = False
78 , envEscapeSpaces = False
@@ -102,7 +111,12 @@ writeMarkdown opts document =
102-- pictures, or inline formatting).
111-- pictures, or inline formatting).
103writePlain :: PandocMonad m => WriterOptions -> Pandoc -> m Text
112writePlain :: PandocMonad m => WriterOptions -> Pandoc -> m Text
104writePlain opts document =
113writePlain opts document =
105− evalMD (pandocToMarkdown opts document) def{ envPlain = True } def
114+ evalMD (pandocToMarkdown opts document) def{ envVariant = PlainText } def
115+
116+-- | Convert Pandoc to Commonmark.
117+writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
118+writeCommonMark opts document =
119+ evalMD (pandocToMarkdown opts document) def{ envVariant = Commonmark } def
106
120
107pandocTitleBlock :: Doc Text -> [Doc Text] -> Doc Text -> Doc Text
121pandocTitleBlock :: Doc Text -> [Doc Text] -> Doc Text -> Doc Text
108pandocTitleBlock tit auths dat =
122pandocTitleBlock tit auths dat =
@@ -187,7 +201,7 @@ pandocToMarkdown opts (Pandoc meta blocks) = do
187 let colwidth = if writerWrapText opts == WrapAuto
201 let colwidth = if writerWrapText opts == WrapAuto
188 then Just $ writerColumns opts
202 then Just $ writerColumns opts
189 else Nothing
203 else Nothing
190− isPlain <- asks envPlain
204+ variant <- asks envVariant
191 metadata <- metaToContext'
205 metadata <- metaToContext'
192 (blockListToMarkdown opts)
206 (blockListToMarkdown opts)
193 (inlineListToMarkdown opts)
207 (inlineListToMarkdown opts)
@@ -196,7 +210,7 @@ pandocToMarkdown opts (Pandoc meta blocks) = do
196 let authors' = fromMaybe [] $ getField "author" metadata
210 let authors' = fromMaybe [] $ getField "author" metadata
197 let date' = fromMaybe empty $ getField "date" metadata
211 let date' = fromMaybe empty $ getField "date" metadata
198 let titleblock = case writerTemplate opts of
212 let titleblock = case writerTemplate opts of
199− Just _ | isPlain ->
213+ Just _ | variant == PlainText ->
200 plainTitleBlock title' authors' date'
214 plainTitleBlock title' authors' date'
201 | isEnabled Ext_yaml_metadata_block opts ->
215 | isEnabled Ext_yaml_metadata_block opts ->
202 yamlMetadataBlock metadata
216 yamlMetadataBlock metadata
@@ -422,7 +436,7 @@ blockToMarkdown' opts (Div attrs ils) = do
422 attrs' = (id',classes',("markdown","1"):kvs')
436 attrs' = (id',classes',("markdown","1"):kvs')
423blockToMarkdown' opts (Plain inlines) = do
437blockToMarkdown' opts (Plain inlines) = do
424 -- escape if para starts with ordered list marker
438 -- escape if para starts with ordered list marker
425− isPlain <- asks envPlain
439+ variant <- asks envVariant
426 let escapeMarker = T.concatMap $ \x -> if x `elemText` ".()"
440 let escapeMarker = T.concatMap $ \x -> if x `elemText` ".()"
427 then T.pack ['\\', x]
441 then T.pack ['\\', x]
428 else T.singleton x
442 else T.singleton x
@@ -430,17 +444,15 @@ blockToMarkdown' opts (Plain inlines) = do
430 startsWithSpace (SoftBreak:_) = True
444 startsWithSpace (SoftBreak:_) = True
431 startsWithSpace _ = False
445 startsWithSpace _ = False
432 let inlines' =
446 let inlines' =
433− if isPlain
447+ if variant == PlainText
434 then inlines
448 then inlines
435 else case inlines of
449 else case inlines of
436 (Str t:ys)
450 (Str t:ys)
437− | not isPlain
438− , (null ys || startsWithSpace ys)
451+ | (null ys || startsWithSpace ys)
439 , beginsWithOrderedListMarker t
452 , beginsWithOrderedListMarker t
440 -> RawInline (Format "markdown") (escapeMarker t):ys
453 -> RawInline (Format "markdown") (escapeMarker t):ys
441 (Str t:_)
454 (Str t:_)
442− | not isPlain
443− , t == "+" || t == "-" ||
455+ | t == "+" || t == "-" ||
444 (t == "%" && isEnabled Ext_pandoc_title_block opts &&
456 (t == "%" && isEnabled Ext_pandoc_title_block opts &&
445 isEnabled Ext_all_symbols_escapable opts)
457 isEnabled Ext_all_symbols_escapable opts)
446 -> RawInline (Format "markdown") "\\" : inlines
458 -> RawInline (Format "markdown") "\\" : inlines
@@ -465,16 +477,16 @@ blockToMarkdown' opts (LineBlock lns) =
465 return $ (vcat $ map (hang 2 (literal "| ")) mdLines) <> blankline
477 return $ (vcat $ map (hang 2 (literal "| ")) mdLines) <> blankline
466 else blockToMarkdown opts $ linesToPara lns
478 else blockToMarkdown opts $ linesToPara lns
467blockToMarkdown' opts b@(RawBlock f str) = do
479blockToMarkdown' opts b@(RawBlock f str) = do
468− plain <- asks envPlain
480+ variant <- asks envVariant
469 let Format fmt = f
481 let Format fmt = f
470 let rawAttribBlock = return $
482 let rawAttribBlock = return $
471 (literal "```{=" <> literal fmt <> "}") $$
483 (literal "```{=" <> literal fmt <> "}") $$
472 literal str $$
484 literal str $$
473 (literal "```" <> literal "\n")
485 (literal "```" <> literal "\n")
474 let renderEmpty = mempty <$ report (BlockNotRendered b)
486 let renderEmpty = mempty <$ report (BlockNotRendered b)
475− case () of
487+ case variant of
476− _ | plain -> renderEmpty
488+ PlainText -> renderEmpty
477− | isEnabled Ext_raw_attribute opts -> rawAttribBlock
489+ _ | isEnabled Ext_raw_attribute opts -> rawAttribBlock
478 | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
490 | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
479 "markdown_mmd", "markdown_strict"] ->
491 "markdown_mmd", "markdown_strict"] ->
480 return $ literal str <> literal "\n"
492 return $ literal str <> literal "\n"
@@ -503,7 +515,7 @@ blockToMarkdown' opts (Header level attr inlines) = do
503 then notesAndRefs opts
515 then notesAndRefs opts
504 else return empty
516 else return empty
505
517
506− plain <- asks envPlain
518+ variant <- asks envVariant
507 -- we calculate the id that would be used by auto_identifiers
519 -- we calculate the id that would be used by auto_identifiers
508 -- so we know whether to print an explicit identifier
520 -- so we know whether to print an explicit identifier
509 ids <- gets stIds
521 ids <- gets stIds
@@ -521,19 +533,20 @@ blockToMarkdown' opts (Header level attr inlines) = do
521 contents <- inlineListToMarkdown opts $
533 contents <- inlineListToMarkdown opts $
522 -- ensure no newlines; see #3736
534 -- ensure no newlines; see #3736
523 walk lineBreakToSpace $
535 walk lineBreakToSpace $
536+ if level == 1 && variant == PlainText &&
524− if level == 1 && plain && isEnabled Ext_gutenberg opts
537+ isEnabled Ext_gutenberg opts
525− then capitalize inlines
538+ then capitalize inlines
526− else inlines
539+ else inlines
527 let setext = writerSetextHeaders opts
540 let setext = writerSetextHeaders opts
528 hdr = nowrap $ case level of
541 hdr = nowrap $ case level of
529− 1 | plain ->
542+ 1 | variant == PlainText ->
530 if isEnabled Ext_gutenberg opts
543 if isEnabled Ext_gutenberg opts
531 then blanklines 3 <> contents <> blanklines 2
544 then blanklines 3 <> contents <> blanklines 2
532 else contents <> blankline
545 else contents <> blankline
533 | setext ->
546 | setext ->
534 contents <> attr' <> cr <> literal (T.replicate (offset contents) "=") <>
547 contents <> attr' <> cr <> literal (T.replicate (offset contents) "=") <>
535 blankline
548 blankline
536− 2 | plain ->
549+ 2 | variant == PlainText ->
537 if isEnabled Ext_gutenberg opts
550 if isEnabled Ext_gutenberg opts
538 then blanklines 2 <> contents <> blankline
551 then blanklines 2 <> contents <> blankline
539 else contents <> blankline
552 else contents <> blankline
@@ -541,7 +554,7 @@ blockToMarkdown' opts (Header level attr inlines) = do
541 contents <> attr' <> cr <> literal (T.replicate (offset contents) "-") <>
554 contents <> attr' <> cr <> literal (T.replicate (offset contents) "-") <>
542 blankline
555 blankline
543 -- ghc interprets '#' characters in column 1 as linenum specifiers.
556 -- ghc interprets '#' characters in column 1 as linenum specifiers.
544− _ | plain || isEnabled Ext_literate_haskell opts ->
557+ _ | variant == PlainText || isEnabled Ext_literate_haskell opts ->
545 contents <> blankline
558 contents <> blankline
546 _ -> literal (T.replicate level "#") <> space <> contents <> attr' <> blankline
559 _ -> literal (T.replicate level "#") <> space <> contents <> attr' <> blankline
547
560
@@ -571,12 +584,12 @@ blockToMarkdown' opts (CodeBlock attribs str) = return $
571 (_,(cls:_),_) -> " " <> literal cls
584 (_,(cls:_),_) -> " " <> literal cls
572 _ -> empty
585 _ -> empty
573blockToMarkdown' opts (BlockQuote blocks) = do
586blockToMarkdown' opts (BlockQuote blocks) = do
574− plain <- asks envPlain
587+ variant <- asks envVariant
575 -- if we're writing literate haskell, put a space before the bird tracks
588 -- if we're writing literate haskell, put a space before the bird tracks
576 -- so they won't be interpreted as lhs...
589 -- so they won't be interpreted as lhs...
577 let leader = if isEnabled Ext_literate_haskell opts
590 let leader = if isEnabled Ext_literate_haskell opts
578 then " > "
591 then " > "
579− else if plain then " " else "> "
592+ else if variant == PlainText then " " else "> "
580 contents <- blockListToMarkdown opts blocks
593 contents <- blockListToMarkdown opts blocks
581 return $ (prefixed leader contents) <> blankline
594 return $ (prefixed leader contents) <> blankline
582blockToMarkdown' opts t@(Table _ blkCapt specs thead tbody tfoot) = do
595blockToMarkdown' opts t@(Table _ blkCapt specs thead tbody tfoot) = do
@@ -584,9 +597,12 @@ blockToMarkdown' opts t@(Table _ blkCapt specs thead tbody tfoot) = do
584 let numcols = maximum (length aligns : length widths :
597 let numcols = maximum (length aligns : length widths :
585 map length (headers:rows))
598 map length (headers:rows))
586 caption' <- inlineListToMarkdown opts caption
599 caption' <- inlineListToMarkdown opts caption
587− let caption'' = if null caption || not (isEnabled Ext_table_captions opts)
600+ let caption'' = if null caption
588 then blankline
601 then blankline
602+ else
603+ if isEnabled Ext_table_captions opts
589− else blankline $$ (": " <> caption') $$ blankline
604+ then blankline $$ (": " <> caption') $$ blankline
605+ else blankline $$ caption' $$ blankline
590 let hasSimpleCells = onlySimpleTableCells $ headers : rows
606 let hasSimpleCells = onlySimpleTableCells $ headers : rows
591 let isSimple = hasSimpleCells && all (==0) widths
607 let isSimple = hasSimpleCells && all (==0) widths
592 let isPlainBlock (Plain _) = True
608 let isPlainBlock (Plain _) = True
@@ -806,8 +822,8 @@ definitionListItemToMarkdown opts (label, defs) = do
806 if isEnabled Ext_definition_lists opts
822 if isEnabled Ext_definition_lists opts
807 then do
823 then do
808 let tabStop = writerTabStop opts
824 let tabStop = writerTabStop opts
809− isPlain <- asks envPlain
825+ variant <- asks envVariant
810− let leader = if isPlain then " " else ": "
826+ let leader = if variant == PlainText then " " else ": "
811 let sps = case writerTabStop opts - 3 of
827 let sps = case writerTabStop opts - 3 of
812 n | n > 0 -> literal $ T.replicate n " "
828 n | n > 0 -> literal $ T.replicate n " "
813 _ -> literal " "
829 _ -> literal " "
@@ -836,7 +852,7 @@ blockListToMarkdown :: PandocMonad m
836 -> MD m (Doc Text)
852 -> MD m (Doc Text)
837blockListToMarkdown opts blocks = do
853blockListToMarkdown opts blocks = do
838 inlist <- asks envInList
854 inlist <- asks envInList
839− isPlain <- asks envPlain
855+ variant <- asks envVariant
840 -- a) insert comment between list and indented code block, or the
856 -- a) insert comment between list and indented code block, or the
841 -- code block will be treated as a list continuation paragraph
857 -- code block will be treated as a list continuation paragraph
842 -- b) change Plain to Para unless it's followed by a RawBlock
858 -- b) change Plain to Para unless it's followed by a RawBlock
@@ -870,7 +886,7 @@ blockListToMarkdown opts blocks = do
870 isListBlock (OrderedList _ _) = True
886 isListBlock (OrderedList _ _) = True
871 isListBlock (DefinitionList _) = True
887 isListBlock (DefinitionList _) = True
872 isListBlock _ = False
888 isListBlock _ = False
873− commentSep = if isPlain
889+ commentSep = if variant == PlainText
874 then Null
890 then Null
875 else if isEnabled Ext_raw_html opts
891 else if isEnabled Ext_raw_html opts
876 then RawBlock "html" "<!-- -->\n"
892 then RawBlock "html" "<!-- -->\n"
@@ -1022,11 +1038,11 @@ inlineToMarkdown opts (Span ("",["emoji"],kvs) [Str s]) =
1022 return $ ":" <> literal emojiname <> ":"
1038 return $ ":" <> literal emojiname <> ":"
1023 _ -> inlineToMarkdown opts (Str s)
1039 _ -> inlineToMarkdown opts (Str s)
1024inlineToMarkdown opts (Span attrs ils) = do
1040inlineToMarkdown opts (Span attrs ils) = do
1025− plain <- asks envPlain
1041+ variant <- asks envVariant
1026 contents <- inlineListToMarkdown opts ils
1042 contents <- inlineListToMarkdown opts ils
1027− return $ case plain of
1043+ return $ case variant of
1028− True -> contents
1044+ PlainText -> contents
1029− False | attrs == nullAttr -> contents
1045+ _ | attrs == nullAttr -> contents
1030 | isEnabled Ext_bracketed_spans opts ->
1046 | isEnabled Ext_bracketed_spans opts ->
1031 let attrs' = if attrs /= nullAttr
1047 let attrs' = if attrs /= nullAttr
1032 then attrsToMarkdown attrs
1048 then attrsToMarkdown attrs
@@ -1038,20 +1054,20 @@ inlineToMarkdown opts (Span attrs ils) = do
1038 | otherwise -> contents
1054 | otherwise -> contents
1039inlineToMarkdown _ (Emph []) = return empty
1055inlineToMarkdown _ (Emph []) = return empty
1040inlineToMarkdown opts (Emph lst) = do
1056inlineToMarkdown opts (Emph lst) = do
1041− plain <- asks envPlain
1057+ variant <- asks envVariant
1042 contents <- inlineListToMarkdown opts lst
1058 contents <- inlineListToMarkdown opts lst
1043− return $ if plain
1059+ return $ case variant of
1060+ PlainText
1044− then if isEnabled Ext_gutenberg opts
1061+ | isEnabled Ext_gutenberg opts -> "_" <> contents <> "_"
1045− then "_" <> contents <> "_"
1046− else contents
1062+ | otherwise -> contents
1047− else "*" <> contents <> "*"
1063+ _ -> "*" <> contents <> "*"
1048inlineToMarkdown _ (Underline []) = return empty
1064inlineToMarkdown _ (Underline []) = return empty
1049inlineToMarkdown opts (Underline lst) = do
1065inlineToMarkdown opts (Underline lst) = do
1050− plain <- asks envPlain
1066+ variant <- asks envVariant
1051 contents <- inlineListToMarkdown opts lst
1067 contents <- inlineListToMarkdown opts lst
1052− case plain of
1068+ case variant of
1053− True -> return contents
1069+ PlainText -> return contents
1054− False | isEnabled Ext_bracketed_spans opts ->
1070+ _ | isEnabled Ext_bracketed_spans opts ->
1055 return $ "[" <> contents <> "]" <> "{.ul}"
1071 return $ "[" <> contents <> "]" <> "{.ul}"
1056 | isEnabled Ext_native_spans opts ->
1072 | isEnabled Ext_native_spans opts ->
1057 return $ tagWithAttrs "span" ("", ["underline"], [])
1073 return $ tagWithAttrs "span" ("", ["underline"], [])
@@ -1062,13 +1078,14 @@ inlineToMarkdown opts (Underline lst) = do
1062 | otherwise -> inlineToMarkdown opts (Emph lst)
1078 | otherwise -> inlineToMarkdown opts (Emph lst)
1063inlineToMarkdown _ (Strong []) = return empty
1079inlineToMarkdown _ (Strong []) = return empty
1064inlineToMarkdown opts (Strong lst) = do
1080inlineToMarkdown opts (Strong lst) = do
1065− plain <- asks envPlain
1081+ variant <- asks envVariant
1066− if plain
1082+ case variant of
1083+ PlainText ->
1067− then inlineListToMarkdown opts $
1084+ inlineListToMarkdown opts $
1068− if isEnabled Ext_gutenberg opts
1085+ if isEnabled Ext_gutenberg opts
1069− then capitalize lst
1086+ then capitalize lst
1070− else lst
1087+ else lst
1071− else do
1088+ _ -> do
1072 contents <- inlineListToMarkdown opts lst
1089 contents <- inlineListToMarkdown opts lst
1073 return $ "**" <> contents <> "**"
1090 return $ "**" <> contents <> "**"
1074inlineToMarkdown _ (Strikeout []) = return empty
1091inlineToMarkdown _ (Strikeout []) = return empty
@@ -1081,33 +1098,43 @@ inlineToMarkdown opts (Strikeout lst) = do
1081 else contents
1098 else contents
1082inlineToMarkdown _ (Superscript []) = return empty
1099inlineToMarkdown _ (Superscript []) = return empty
1083inlineToMarkdown opts (Superscript lst) =
1100inlineToMarkdown opts (Superscript lst) =
1084− local (\env -> env {envEscapeSpaces = True}) $ do
1101+ local (\env -> env {envEscapeSpaces = (envVariant env == Markdown)}) $ do
1085 contents <- inlineListToMarkdown opts lst
1102 contents <- inlineListToMarkdown opts lst
1086− return $ if isEnabled Ext_superscript opts
1103+ if isEnabled Ext_superscript opts
1087− then "^" <> contents <> "^"
1104+ then return $ "^" <> contents <> "^"
1088− else if isEnabled Ext_raw_html opts
1105+ else if isEnabled Ext_raw_html opts
1089− then "<sup>" <> contents <> "</sup>"
1106+ then return $ "<sup>" <> contents <> "</sup>"
1090− else
1107+ else
1108+ case traverse toSuperscriptInline lst of
1109+ Just xs' | not (writerPreferAscii opts)
1110+ -> inlineListToMarkdown opts xs'
1111+ _ -> do
1091− let rendered = render Nothing contents
1112+ let rendered = render Nothing contents
1113+ return $
1092− in case mapM toSuperscript (T.unpack rendered) of
1114+ case mapM toSuperscript (T.unpack rendered) of
1093− Just r -> literal $ T.pack r
1115+ Just r -> literal $ T.pack r
1094− Nothing -> literal $ "^(" <> rendered <> ")"
1116+ Nothing -> literal $ "^(" <> rendered <> ")"
1095inlineToMarkdown _ (Subscript []) = return empty
1117inlineToMarkdown _ (Subscript []) = return empty
1096inlineToMarkdown opts (Subscript lst) =
1118inlineToMarkdown opts (Subscript lst) =
1097− local (\env -> env {envEscapeSpaces = True}) $ do
1119+ local (\env -> env {envEscapeSpaces = (envVariant env == Markdown)}) $ do
1098 contents <- inlineListToMarkdown opts lst
1120 contents <- inlineListToMarkdown opts lst
1099− return $ if isEnabled Ext_subscript opts
1121+ if isEnabled Ext_subscript opts
1100− then "~" <> contents <> "~"
1122+ then return $ "~" <> contents <> "~"
1101− else if isEnabled Ext_raw_html opts
1123+ else if isEnabled Ext_raw_html opts
1102− then "<sub>" <> contents <> "</sub>"
1124+ then return $ "<sub>" <> contents <> "</sub>"
1103− else
1125+ else
1126+ case traverse toSubscriptInline lst of
1127+ Just xs' | not (writerPreferAscii opts)
1128+ -> inlineListToMarkdown opts xs'
1129+ _ -> do
1104− let rendered = render Nothing contents
1130+ let rendered = render Nothing contents
1131+ return $
1105− in case mapM toSubscript (T.unpack rendered) of
1132+ case mapM toSuperscript (T.unpack rendered) of
1106− Just r -> literal $ T.pack r
1133+ Just r -> literal $ T.pack r
1107− Nothing -> literal $ "_(" <> rendered <> ")"
1134+ Nothing -> literal $ "_(" <> rendered <> ")"
1108inlineToMarkdown opts (SmallCaps lst) = do
1135inlineToMarkdown opts (SmallCaps lst) = do
1109− plain <- asks envPlain
1136+ variant <- asks envVariant
1110− if not plain &&
1137+ if variant /= PlainText &&
1111 (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
1138 (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
1112 then inlineToMarkdown opts (Span ("",["smallcaps"],[]) lst)
1139 then inlineToMarkdown opts (Span ("",["smallcaps"],[]) lst)
1113 else inlineListToMarkdown opts $ capitalize lst
1140 else inlineListToMarkdown opts $ capitalize lst
@@ -1137,16 +1164,17 @@ inlineToMarkdown opts (Code attr str) = do
1137 let attrs = if isEnabled Ext_inline_code_attributes opts && attr /= nullAttr
1164 let attrs = if isEnabled Ext_inline_code_attributes opts && attr /= nullAttr
1138 then attrsToMarkdown attr
1165 then attrsToMarkdown attr
1139 else empty
1166 else empty
1140− plain <- asks envPlain
1167+ variant <- asks envVariant
1141− if plain
1168+ case variant of
1142− then return $ literal str
1169+ PlainText -> return $ literal str
1170+ _ -> return $ literal
1143− else return $ literal (marker <> spacer <> str <> spacer <> marker) <> attrs
1171+ (marker <> spacer <> str <> spacer <> marker) <> attrs
1144inlineToMarkdown opts (Str str) = do
1172inlineToMarkdown opts (Str str) = do
1145− isPlain <- asks envPlain
1173+ variant <- asks envVariant
1146 let str' = (if isEnabled Ext_smart opts
1174 let str' = (if isEnabled Ext_smart opts
1147 then unsmartify opts
1175 then unsmartify opts
1148 else id) $
1176 else id) $
1149− if isPlain
1177+ if variant == PlainText
1150 then str
1178 then str
1151 else escapeText opts str
1179 else escapeText opts str
1152 return $ literal str'
1180 return $ literal str'
@@ -1161,10 +1189,10 @@ inlineToMarkdown opts (Math InlineMath str) =
1161 | isEnabled Ext_tex_math_double_backslash opts ->
1189 | isEnabled Ext_tex_math_double_backslash opts ->
1162 return $ "\\\\(" <> literal str <> "\\\\)"
1190 return $ "\\\\(" <> literal str <> "\\\\)"
1163 | otherwise -> do
1191 | otherwise -> do
1164− plain <- asks envPlain
1192+ variant <- asks envVariant
1165 texMathToInlines InlineMath str >>=
1193 texMathToInlines InlineMath str >>=
1166 inlineListToMarkdown opts .
1194 inlineListToMarkdown opts .
1167− (if plain then makeMathPlainer else id)
1195+ (if variant == PlainText then makeMathPlainer else id)
1168inlineToMarkdown opts (Math DisplayMath str) =
1196inlineToMarkdown opts (Math DisplayMath str) =
1169 case writerHTMLMathMethod opts of
1197 case writerHTMLMathMethod opts of
1170 WebTeX url -> (\x -> blankline <> x <> blankline) `fmap`
1198 WebTeX url -> (\x -> blankline <> x <> blankline) `fmap`
@@ -1183,15 +1211,15 @@ inlineToMarkdown opts il@(RawInline f str) = do
1183 let numticks = if null tickGroups
1211 let numticks = if null tickGroups
1184 then 1
1212 then 1
1185 else 1 + maximum (map T.length tickGroups)
1213 else 1 + maximum (map T.length tickGroups)
1186− plain <- asks envPlain
1214+ variant <- asks envVariant
1187 let Format fmt = f
1215 let Format fmt = f
1188 let rawAttribInline = return $
1216 let rawAttribInline = return $
1189 literal (T.replicate numticks "`") <> literal str <>
1217 literal (T.replicate numticks "`") <> literal str <>
1190 literal (T.replicate numticks "`") <> literal "{=" <> literal fmt <> literal "}"
1218 literal (T.replicate numticks "`") <> literal "{=" <> literal fmt <> literal "}"
1191 let renderEmpty = mempty <$ report (InlineNotRendered il)
1219 let renderEmpty = mempty <$ report (InlineNotRendered il)
1192− case () of
1220+ case variant of
1193− _ | plain -> renderEmpty
1221+ PlainText -> renderEmpty
1194− | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
1222+ _ | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
1195 "markdown_mmd", "markdown_strict"] ->
1223 "markdown_mmd", "markdown_strict"] ->
1196 return $ literal str
1224 return $ literal str
1197 | isEnabled Ext_raw_attribute opts -> rawAttribInline
1225 | isEnabled Ext_raw_attribute opts -> rawAttribInline
@@ -1207,8 +1235,8 @@ inlineToMarkdown opts il@(RawInline f str) = do
1207 | otherwise -> renderEmpty
1235 | otherwise -> renderEmpty
1208 | otherwise -> renderEmpty
1236 | otherwise -> renderEmpty
1209inlineToMarkdown opts LineBreak = do
1237inlineToMarkdown opts LineBreak = do
1210− plain <- asks envPlain
1238+ variant <- asks envVariant
1211− if plain || isEnabled Ext_hard_line_breaks opts
1239+ if variant == PlainText || isEnabled Ext_hard_line_breaks opts
1212 then return cr
1240 then return cr
1213 else return $
1241 else return $
1214 if isEnabled Ext_escaped_line_breaks opts
1242 if isEnabled Ext_escaped_line_breaks opts
@@ -1261,7 +1289,7 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
1261 (literal . T.strip) <$>
1289 (literal . T.strip) <$>
1262 writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [lnk]])
1290 writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [lnk]])
1263 | otherwise = do
1291 | otherwise = do
1264− plain <- asks envPlain
1292+ variant <- asks envVariant
1265 linktext <- inlineListToMarkdown opts txt
1293 linktext <- inlineListToMarkdown opts txt
1266 let linktitle = if T.null tit
1294 let linktitle = if T.null tit
1267 then empty
1295 then empty
@@ -1279,9 +1307,9 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
1279 then literal <$> getReference attr linktext (src, tit)
1307 then literal <$> getReference attr linktext (src, tit)
1280 else return mempty
1308 else return mempty
1281 return $ if useAuto
1309 return $ if useAuto
1282− then if plain
1310+ then case variant of
1283− then literal srcSuffix
1311+ PlainText -> literal srcSuffix
1284− else "<" <> literal srcSuffix <> ">"
1312+ _ -> "<" <> literal srcSuffix <> ">"
1285 else if useRefLinks
1313 else if useRefLinks
1286 then let first = "[" <> linktext <> "]"
1314 then let first = "[" <> linktext <> "]"
1287 second = if getKey linktext == getKey reftext
1315 second = if getKey linktext == getKey reftext
@@ -1290,9 +1318,9 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
1290 else "[]"
1318 else "[]"
1291 else "[" <> reftext <> "]"
1319 else "[" <> reftext <> "]"
1292 in first <> second
1320 in first <> second
1293− else if plain
1321+ else case variant of
1294− then linktext
1322+ PlainText -> linktext
1295− else "[" <> linktext <> "](" <>
1323+ _ -> "[" <> linktext <> "](" <>
1296 literal src <> linktitle <> ")" <>
1324 literal src <> linktitle <> ")" <>
1297 linkAttributes opts attr
1325 linkAttributes opts attr
1298inlineToMarkdown opts img@(Image attr alternate (source, tit))
1326inlineToMarkdown opts img@(Image attr alternate (source, tit))
@@ -1302,15 +1330,15 @@ inlineToMarkdown opts img@(Image attr alternate (source, tit))
1302 (literal . T.strip) <$>
1330 (literal . T.strip) <$>
1303 writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
1331 writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
1304 | otherwise = do
1332 | otherwise = do
1305− plain <- asks envPlain
1333+ variant <- asks envVariant
1306 let txt = if null alternate || alternate == [Str source]
1334 let txt = if null alternate || alternate == [Str source]
1307 -- to prevent autolinks
1335 -- to prevent autolinks
1308 then [Str ""]
1336 then [Str ""]
1309 else alternate
1337 else alternate
1310 linkPart <- inlineToMarkdown opts (Link attr txt (source, tit))
1338 linkPart <- inlineToMarkdown opts (Link attr txt (source, tit))
1311− return $ if plain
1339+ return $ case variant of
1312− then "[" <> linkPart <> "]"
1340+ PlainText -> "[" <> linkPart <> "]"
1313− else "!" <> linkPart
1341+ _ -> "!" <> linkPart
1314inlineToMarkdown opts (Note contents) = do
1342inlineToMarkdown opts (Note contents) = do
1315 modify (\st -> st{ stNotes = contents : stNotes st })
1343 modify (\st -> st{ stNotes = contents : stNotes st })
1316 st <- get
1344 st <- get
@@ -1329,3 +1357,19 @@ lineBreakToSpace :: Inline -> Inline
1329lineBreakToSpace LineBreak = Space
1357lineBreakToSpace LineBreak = Space
1330lineBreakToSpace SoftBreak = Space
1358lineBreakToSpace SoftBreak = Space
1331lineBreakToSpace x = x
1359lineBreakToSpace x = x
1360+
1361+toSubscriptInline :: Inline -> Maybe Inline
1362+toSubscriptInline Space = Just Space
1363+toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils
1364+toSubscriptInline (Str s) = Str . T.pack <$> traverse toSubscript (T.unpack s)
1365+toSubscriptInline LineBreak = Just LineBreak
1366+toSubscriptInline SoftBreak = Just SoftBreak
1367+toSubscriptInline _ = Nothing
1368+
1369+toSuperscriptInline :: Inline -> Maybe Inline
1370+toSuperscriptInline Space = Just Space
1371+toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils
1372+toSuperscriptInline (Str s) = Str . T.pack <$> traverse toSuperscript (T.unpack s)
1373+toSuperscriptInline LineBreak = Just LineBreak
1374+toSuperscriptInline SoftBreak = Just SoftBreak
1375+toSuperscriptInline _ = Nothing
src/Text/Pandoc/Writers/Ms.hs+8−6
@@ -204,7 +204,9 @@ blockToMs opts (CodeBlock attr str) = do
204 literal ".IP" $$
204 literal ".IP" $$
205 literal ".nf" $$
205 literal ".nf" $$
206 literal "\\f[C]" $$
206 literal "\\f[C]" $$
207+ ((case T.uncons str of
208+ Just ('.',_) -> literal "\\&"
207− hlCode $$
209+ _ -> mempty) <> hlCode) $$
208 literal "\\f[]" $$
210 literal "\\f[]" $$
209 literal ".fi"
211 literal ".fi"
210blockToMs opts (LineBlock ls) = do
212blockToMs opts (LineBlock ls) = do
@@ -517,11 +519,11 @@ toMacro sty toktype =
517
519
518msFormatter :: WriterOptions -> FormatOptions -> [SourceLine] -> Doc Text
520msFormatter :: WriterOptions -> FormatOptions -> [SourceLine] -> Doc Text
519msFormatter opts _fmtopts =
521msFormatter opts _fmtopts =
520− vcat . map fmtLine
522+ literal . T.intercalate "\n" . map fmtLine
523+ where
521− where fmtLine = hcat . map fmtToken
524+ fmtLine = mconcat . map fmtToken
522− fmtToken (toktype, tok) = literal "\\*" <>
525+ fmtToken (toktype, tok) =
523− brackets (literal (tshow toktype) <> literal " \""
524− <> literal (escapeStr opts tok) <> literal "\"")
526+ "\\*[" <> (tshow toktype) <> " \"" <> (escapeStr opts tok) <> "\"]"
525
527
526highlightCode :: PandocMonad m => WriterOptions -> Attr -> Text -> MS m (Doc Text)
528highlightCode :: PandocMonad m => WriterOptions -> Attr -> Text -> MS m (Doc Text)
527highlightCode opts attr str =
529highlightCode opts attr str =
stack.yaml+9
@@ -27,6 +27,15 @@ extra-deps:
27- HsYAML-0.2.1.0
27- HsYAML-0.2.1.0
28- HsYAML-aeson-0.2.0.0
28- HsYAML-aeson-0.2.0.0
29- doctemplates-0.8.2
29- doctemplates-0.8.2
30+- commonmark-0.1.0.0
31+#- commonmark-extensions-0.1.0.0
32+#- commonmark-pandoc-0.1.0.0
33+- git: https://github.com/jgm/commonmark-hs
34+ commit: 8d4442abc443ce0100cc87af797e7df9a72b9b9a
35+ subdirs:
36+ - commonmark-extensions
37+ - commonmark-pandoc
38+
30ghc-options:
39ghc-options:
31 "$locals": -fhide-source-paths -Wno-missing-home-modules
40 "$locals": -fhide-source-paths -Wno-missing-home-modules
32resolver: lts-14.6
41resolver: lts-14.6
test/Tests/Readers/Org/Directive.hs+30
@@ -150,6 +150,28 @@ tests =
150 ] =?>
150 ] =?>
151 Pandoc nullMeta mempty
151 Pandoc nullMeta mempty
152
152
153+ , "disable MathML-like entities" =:
154+ T.unlines [ "#+OPTIONS: e:nil"
155+ , "Icelandic letter: \\thorn"
156+ ] =?>
157+ para "Icelandic letter: \\thorn"
158+
159+ , testGroup "Option f"
160+ [ "disable inline footnotes" =:
161+ T.unlines [ "#+OPTIONS: f:nil"
162+ , "Funny![fn:funny:or not]"
163+ ] =?>
164+ para "Funny!"
165+
166+ , "disable reference footnotes" =:
167+ T.unlines [ "#+OPTIONS: f:nil"
168+ , "Burn everything[fn:1] down!"
169+ , ""
170+ , "[fn:2] Not quite everything."
171+ ] =?>
172+ para "Burn everything down!"
173+ ]
174+
153 , "disable inclusion of todo keywords" =:
175 , "disable inclusion of todo keywords" =:
154 T.unlines [ "#+OPTIONS: todo:nil"
176 T.unlines [ "#+OPTIONS: todo:nil"
155 , "** DONE todo export"
177 , "** DONE todo export"
@@ -258,6 +280,14 @@ tests =
258 headerWith ("wichtig", mempty, mempty) 1 "Wichtig"
280 headerWith ("wichtig", mempty, mempty) 1 "Wichtig"
259 ]
281 ]
260
282
283+ , testGroup "Option |"
284+ [ "disable export of tables" =:
285+ T.unlines [ "#+OPTIONS: |:nil"
286+ , "| chair |"
287+ ] =?>
288+ (mempty :: Blocks)
289+ ]
290+
261 , testGroup "unknown options"
291 , testGroup "unknown options"
262 [ "unknown options are ignored" =:
292 [ "unknown options are ignored" =:
263 T.unlines [ "#+OPTIONS: does-not-exist:t "] =?>
293 T.unlines [ "#+OPTIONS: does-not-exist:t "] =?>
test/Tests/Readers/Org/Meta.hs+110−72
@@ -93,6 +93,13 @@ tests =
93 in Pandoc meta mempty
93 in Pandoc meta mempty
94 ]
94 ]
95
95
96+ , "Subtitle" =:
97+ T.unlines [ "#+SUBTITLE: Your Life in"
98+ , "#+SUBTITLE: /Plain/ Text"
99+ ] =?>
100+ let subtitle = "Your Life in" <> softbreak <> emph "Plain" <> " Text"
101+ in Pandoc (setMeta "subtitle" (toMetaValue subtitle) nullMeta) mempty
102+
96 , "Keywords" =:
103 , "Keywords" =:
97 T.unlines [ "#+KEYWORDS: pandoc, testing,"
104 T.unlines [ "#+KEYWORDS: pandoc, testing,"
98 , "#+KEYWORDS: Org"
105 , "#+KEYWORDS: Org"
@@ -101,42 +108,117 @@ tests =
101 meta = setMeta "keywords" (MetaInlines keywords) nullMeta
108 meta = setMeta "keywords" (MetaInlines keywords) nullMeta
102 in Pandoc meta mempty
109 in Pandoc meta mempty
103
110
104− , "LaTeX_headers options are translated to header-includes" =:
111+ , "Institute" =:
105− "#+LaTeX_header: \\usepackage{tikz}" =?>
112+ "#+INSTITUTE: ACME Inc." =?>
106− let latexInlines = rawInline "latex" "\\usepackage{tikz}"
113+ Pandoc (setMeta "institute" ("ACME Inc." :: Inlines) nullMeta) mempty
107− inclList = MetaList [MetaInlines (toList latexInlines)]
108− meta = setMeta "header-includes" inclList nullMeta
109− in Pandoc meta mempty
110
114
111− , testGroup "LaTeX_CLASS"
115+ , testGroup "LaTeX"
112− [ "LaTeX_class option is translated to documentclass" =:
116+ [ "LATEX_HEADER" =:
113− "#+LATEX_CLASS: article" =?>
117+ "#+LaTeX_header: \\usepackage{tikz}" =?>
114− let meta = setMeta "documentclass" (MetaString "article") nullMeta
118+ let latexInlines = rawInline "latex" "\\usepackage{tikz}"
119+ inclList = MetaList [MetaInlines (toList latexInlines)]
120+ meta = setMeta "header-includes" inclList nullMeta
115 in Pandoc meta mempty
121 in Pandoc meta mempty
116
122
123+ , "LATEX_HEADER_EXTRA" =:
124+ "#+LATEX_HEADER_EXTRA: \\usepackage{calc}" =?>
125+ let latexInlines = rawInline "latex" "\\usepackage{calc}"
126+ inclList = toMetaValue [latexInlines]
127+ in Pandoc (setMeta "header-includes" inclList nullMeta) mempty
128+
129+ , testGroup "LaTeX_CLASS"
130+ [ "stored as documentclass" =:
131+ "#+LATEX_CLASS: article" =?>
132+ let meta = setMeta "documentclass" (MetaString "article") nullMeta
133+ in Pandoc meta mempty
134+
117− , "last definition takes precedence" =:
135+ , "last definition takes precedence" =:
118− T.unlines [ "#+LATEX_CLASS: this will not be used"
136+ T.unlines [ "#+LATEX_CLASS: this will not be used"
119− , "#+LATEX_CLASS: report"
137+ , "#+LATEX_CLASS: report"
120− ] =?>
138+ ] =?>
121− let meta = setMeta "documentclass" (MetaString "report") nullMeta
139+ let meta = setMeta "documentclass" (MetaString "report") nullMeta
140+ in Pandoc meta mempty
141+ ]
142+
143+ , "LATEX_CLASS_OPTIONS as classoption" =:
144+ "#+LATEX_CLASS_OPTIONS: [a4paper]" =?>
145+ let meta = setMeta "classoption" (MetaString "a4paper") nullMeta
122 in Pandoc meta mempty
146 in Pandoc meta mempty
123 ]
147 ]
124
148
125− , "LaTeX_class_options is translated to classoption" =:
149+ , testGroup "HTML"
126− "#+LATEX_CLASS_OPTIONS: [a4paper]" =?>
150+ [ "HTML_HEAD values are added to header-includes" =:
127− let meta = setMeta "classoption" (MetaString "a4paper") nullMeta
151+ "#+html_head: <meta/>" =?>
152+ let html = rawInline "html" "<meta/>"
153+ inclList = MetaList [MetaInlines (toList html)]
154+ meta = setMeta "header-includes" inclList nullMeta
128− in Pandoc meta mempty
155+ in Pandoc meta mempty
129
156
130− , "LaTeX_class_options is translated to classoption" =:
157+ , "HTML_HEAD_EXTRA behaves like HTML_HEAD" =:
131− "#+html_head: <meta/>" =?>
158+ T.unlines [ "#+HTML_HEAD: <meta name=\"generator\" content=\"pandoc\">"
159+ , "#+HTML_HEAD_EXTRA: <meta charset=\"utf-8\">"
160+ ] =?>
161+ let generator = rawInline "html"
162+ "<meta name=\"generator\" content=\"pandoc\">"
132− let html = rawInline "html" "<meta/>"
163+ charset = rawInline "html" "<meta charset=\"utf-8\">"
133− inclList = MetaList [MetaInlines (toList html)]
164+ inclList = toMetaValue [generator, charset]
134− meta = setMeta "header-includes" inclList nullMeta
165+ in Pandoc (setMeta "header-includes" inclList nullMeta) mempty
135− in Pandoc meta mempty
166+ ]
167+ ]
136
168
137− , "Institute" =:
169+ , testGroup "Non-export keywords"
138− "#+INSTITUTE: ACME Inc." =?>
170+ [ testGroup "#+LINK"
139− Pandoc (setMeta "institute" ("ACME Inc." :: Inlines) nullMeta) mempty
171+ [ "Link abbreviation" =:
172+ T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
173+ , "[[wp:Org_mode][Wikipedia on Org-mode]]"
174+ ] =?>
175+ para (link "https://en.wikipedia.org/wiki/Org_mode" ""
176+ ("Wikipedia" <> space <> "on" <> space <> "Org-mode"))
177+
178+ , "Link abbreviation, defined after first use" =:
179+ T.unlines [ "[[zl:non-sense][Non-sense articles]]"
180+ , "#+LINK: zl http://zeitlens.com/tags/%s.html"
181+ ] =?>
182+ para (link "http://zeitlens.com/tags/non-sense.html" ""
183+ ("Non-sense" <> space <> "articles"))
184+
185+ , "Link abbreviation, URL encoded arguments" =:
186+ T.unlines [ "#+link: expl http://example.com/%h/foo"
187+ , "[[expl:Hello, World!][Moin!]]"
188+ ] =?>
189+ para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!")
190+
191+ , "Link abbreviation, append arguments" =:
192+ T.unlines [ "#+link: expl http://example.com/"
193+ , "[[expl:foo][bar]]"
194+ ] =?>
195+ para (link "http://example.com/foo" "" "bar")
196+ ]
197+
198+ , testGroup "emphasis config"
199+ [ "Changing pre and post chars for emphasis" =:
200+ T.unlines [ "#+pandoc-emphasis-pre: \"[)\""
201+ , "#+pandoc-emphasis-post: \"]\\n\""
202+ , "([/emph/])*foo*"
203+ ] =?>
204+ para ("([" <> emph "emph" <> "])" <> strong "foo")
205+
206+ , "setting an invalid value restores the default" =:
207+ T.unlines [ "#+pandoc-emphasis-pre: \"[\""
208+ , "#+pandoc-emphasis-post: \"]\""
209+ , "#+pandoc-emphasis-pre:"
210+ , "#+pandoc-emphasis-post:"
211+ , "[/noemph/]"
212+ ] =?>
213+ para "[/noemph/]"
214+ ]
215+
216+ , "Unknown keyword" =:
217+ T.unlines [ "#+UNKNOWN_KEYWORD: Chumbawamba"
218+ , "#+ANOTHER_UNKNOWN: Blur"
219+ ] =?>
220+ rawBlock "org" "#+UNKNOWN_KEYWORD: Chumbawamba" <>
221+ rawBlock "org" "#+ANOTHER_UNKNOWN: Blur"
140 ]
222 ]
141
223
142 , "Properties drawer" =:
224 , "Properties drawer" =:
@@ -193,48 +275,4 @@ tests =
193 ] =?>
275 ] =?>
194 (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
276 (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
195 para (emph ("See" <> space <> "here!")))
277 para (emph ("See" <> space <> "here!")))
196−
197− , "Link abbreviation" =:
198− T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
199− , "[[wp:Org_mode][Wikipedia on Org-mode]]"
200− ] =?>
201− para (link "https://en.wikipedia.org/wiki/Org_mode" ""
202− ("Wikipedia" <> space <> "on" <> space <> "Org-mode"))
203−
204− , "Link abbreviation, defined after first use" =:
205− T.unlines [ "[[zl:non-sense][Non-sense articles]]"
206− , "#+LINK: zl http://zeitlens.com/tags/%s.html"
207− ] =?>
208− para (link "http://zeitlens.com/tags/non-sense.html" ""
209− ("Non-sense" <> space <> "articles"))
210−
211− , "Link abbreviation, URL encoded arguments" =:
212− T.unlines [ "#+link: expl http://example.com/%h/foo"
213− , "[[expl:Hello, World!][Moin!]]"
214− ] =?>
215− para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!")
216−
217− , "Link abbreviation, append arguments" =:
218− T.unlines [ "#+link: expl http://example.com/"
219− , "[[expl:foo][bar]]"
220− ] =?>
221− para (link "http://example.com/foo" "" "bar")
222−
223− , testGroup "emphasis config"
224− [ "Changing pre and post chars for emphasis" =:
225− T.unlines [ "#+pandoc-emphasis-pre: \"[)\""
226− , "#+pandoc-emphasis-post: \"]\\n\""
227− , "([/emph/])*foo*"
228− ] =?>
229− para ("([" <> emph "emph" <> "])" <> strong "foo")
230−
231− , "setting an invalid value restores the default" =:
232− T.unlines [ "#+pandoc-emphasis-pre: \"[\""
233− , "#+pandoc-emphasis-post: \"]\""
234− , "#+pandoc-emphasis-pre:"
235− , "#+pandoc-emphasis-post:"
236− , "[/noemph/]"
237− ] =?>
238− para "[/noemph/]"
239− ]
240 ]
278 ]
test/Tests/Writers/Ms.hsnew file+37
@@ -0,0 +1,37 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Tests.Writers.Ms (tests) where
4+
5+import Prelude
6+import Test.Tasty
7+import Tests.Helpers
8+import Text.Pandoc
9+import Text.Pandoc.Builder
10+
11+infix 4 =:
12+(=:) :: (ToString a, ToPandoc a)
13+ => String -> (a, String) -> TestTree
14+(=:) = test (purely (writeMs def . toPandoc))
15+
16+tests :: [TestTree]
17+tests = [ testGroup "code blocks"
18+ [ "basic"
19+ =: codeBlock "hello"
20+ =?> unlines
21+ [ ".IP"
22+ , ".nf"
23+ , "\\f[C]"
24+ , "hello"
25+ , "\\f[]"
26+ , ".fi"]
27+ , "escape starting ."
28+ =: codeBlock ". hello"
29+ =?> unlines
30+ [ ".IP"
31+ , ".nf"
32+ , "\\f[C]"
33+ , "\\&. hello"
34+ , "\\f[]"
35+ , ".fi"]
36+ ]
37+ ]
test/command/3734.md+1−1
@@ -27,6 +27,6 @@
27| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
27| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
28^D
28^D
29| aaaaaaaaaaaa | bbbbb | ccccccccccc |
29| aaaaaaaaaaaa | bbbbb | ccccccccccc |
30−| ------------ | ----- | ------------------------------------------------------------------------ |
30+|--------------|-------|--------------------------------------------------------------------------|
31| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
31| aaaaaaaaaaaa | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
32```
32```
test/command/4038.md+1−1
@@ -1,5 +1,5 @@
1```
1```
2−% pandoc -f gfm -t gfm
2+% pandoc -f gfm -t gfm --atx-headers
3# ~~Header~~
3# ~~Header~~
4^D
4^D
5# ~~Header~~
5# ~~Header~~
test/command/4528.md+1−1
@@ -124,7 +124,7 @@ This has ^superscript^ in it and ^2^ again.
124% pandoc --wrap=none -f html -t commonmark-raw_html
124% pandoc --wrap=none -f html -t commonmark-raw_html
125This has <sub>subscript</sub> in it and <sub>2 3</sub> again. With emphasis: <sub><em>2</em> 3</sub>. With letters: <sub>foo</sub>. With a span: <sub><span class=foo>2</span></sub>.
125This has <sub>subscript</sub> in it and <sub>2 3</sub> again. With emphasis: <sub><em>2</em> 3</sub>. With letters: <sub>foo</sub>. With a span: <sub><span class=foo>2</span></sub>.
126^D
126^D
127−This has \_(subscript) in it and ₂ ₃ again. With emphasis: \_(*2* 3). With letters: \_(foo). With a span: ₂.
127+This has _(subscript) in it and ₂ ₃ again. With emphasis: _(*2* 3). With letters: _(foo). With a span: ₂.
128```
128```
129
129
130```
130```
test/command/gfm.md+4−4
@@ -69,7 +69,7 @@ My:thumbsup:emoji:heart:
69% pandoc -f gfm+smart -t native
69% pandoc -f gfm+smart -t native
70"hi"
70"hi"
71^D
71^D
72−[Para [Str "\8220hi\8221"]]
72+[Para [Quoted DoubleQuote [Str "hi"]]]
73```
73```
74
74
75```
75```
@@ -100,7 +100,7 @@ My:thumbsup:emoji:heart:
100 [])]
100 [])]
101^D
101^D
102| Fruit | Price |
102| Fruit | Price |
103−| ------ | ----: |
103+|--------|------:|
104| apple | 0.13 |
104| apple | 0.13 |
105| orange | 1.12 |
105| orange | 1.12 |
106
106
@@ -161,6 +161,6 @@ hi
161- [ ] foo
161- [ ] foo
162- [x] bar
162- [x] bar
163^D
163^D
164− - [ ] foo
164+- [ ] foo
165− - [x] bar
165+- [x] bar
166```
166```
test/docx/golden/inline_formatting.docx

Binary file not shown.

test/docx/inline_formatting.native+1−1
@@ -1,6 +1,6 @@
1Pandoc (Meta {unMeta = fromList []})
1Pandoc (Meta {unMeta = fromList []})
2[Para [Str "Regular",Space,Str "text",Space,Emph [Str "italics"],Space,Strong [Str "bold",Space,Emph [Str "bold",Space,Str "italics"]],Str "."]
2[Para [Str "Regular",Space,Str "text",Space,Emph [Str "italics"],Space,Strong [Str "bold",Space,Emph [Str "bold",Space,Str "italics"]],Str "."]
3,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "Small",Space,Str "Caps"],Str ",",Space,Str "and",Space,Str "this",Space,Str "is",Space,Strikeout [Str "strikethrough"],Str "."]
3,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "Small",Space,Str "Caps"],Str ",",Space,Str "and",Space,Str "this",Space,Str "is",Space,Strikeout [Str "strikethrough"],Str "."]
4−,Para [Str "Some",Space,Str "people",Space,Str "use",Space,Underline [Str "single",Space,Str "underlines",Space,Str "for",Space],Emph [Underline [Str "emphasis"]],Str "."]
4+,Para [Str "Some",Space,Str "people",Space,Str "use",Space,Underline [Str "single",Space,Str "underlines",Space,Str "for",Space,Emph [Str "emphasis"]],Str "."]
5,Para [Str "Above",Space,Str "the",Space,Str "line",Space,Str "is",Space,Superscript [Str "superscript"],Space,Str "and",Space,Str "below",Space,Str "the",Space,Str "line",Space,Str "is",Space,Subscript [Str "subscript"],Str "."]
5,Para [Str "Above",Space,Str "the",Space,Str "line",Space,Str "is",Space,Superscript [Str "superscript"],Space,Str "and",Space,Str "below",Space,Str "the",Space,Str "line",Space,Str "is",Space,Subscript [Str "subscript"],Str "."]
6,Para [Str "A",Space,Str "line",LineBreak,Str "break."]]
6,Para [Str "A",Space,Str "line",LineBreak,Str "break."]]
test/lhs-test.latex+3
@@ -81,6 +81,9 @@
81\providecommand{\tightlist}{%
81\providecommand{\tightlist}{%
82 \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
82 \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
83\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
83\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
84+\ifluatex
85+ \usepackage{selnolig} % disable illegal ligatures
86+\fi
84
87
85\author{}
88\author{}
86\date{}
89\date{}
test/lhs-test.latex+lhs+3
@@ -48,6 +48,9 @@
48\providecommand{\tightlist}{%
48\providecommand{\tightlist}{%
49 \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
49 \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
50\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
50\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
51+\ifluatex
52+ \usepackage{selnolig} % disable illegal ligatures
53+\fi
51
54
52\author{}
55\author{}
53\date{}
56\date{}
test/test-pandoc.hs+2
@@ -37,6 +37,7 @@ import qualified Tests.Writers.JATS
37import qualified Tests.Writers.Jira
37import qualified Tests.Writers.Jira
38import qualified Tests.Writers.LaTeX
38import qualified Tests.Writers.LaTeX
39import qualified Tests.Writers.Markdown
39import qualified Tests.Writers.Markdown
40+import qualified Tests.Writers.Ms
40import qualified Tests.Writers.Muse
41import qualified Tests.Writers.Muse
41import qualified Tests.Writers.Native
42import qualified Tests.Writers.Native
42import qualified Tests.Writers.Org
43import qualified Tests.Writers.Org
@@ -70,6 +71,7 @@ tests pandocPath = testGroup "pandoc tests"
70 , testGroup "Muse" Tests.Writers.Muse.tests
71 , testGroup "Muse" Tests.Writers.Muse.tests
71 , testGroup "FB2" Tests.Writers.FB2.tests
72 , testGroup "FB2" Tests.Writers.FB2.tests
72 , testGroup "PowerPoint" Tests.Writers.Powerpoint.tests
73 , testGroup "PowerPoint" Tests.Writers.Powerpoint.tests
74+ , testGroup "Ms" Tests.Writers.Ms.tests
73 ]
75 ]
74 , testGroup "Readers"
76 , testGroup "Readers"
75 [ testGroup "LaTeX" Tests.Readers.LaTeX.tests
77 [ testGroup "LaTeX" Tests.Readers.LaTeX.tests
test/writer.jira+2−2
@@ -513,9 +513,9 @@ or here: <http://example.com/>
513h1. {anchor:images}Images
513h1. {anchor:images}Images
514From "Voyage dans la Lune" by Georges Melies \(1902):
514From "Voyage dans la Lune" by Georges Melies \(1902):
515
515
516−!lalune.jpg|title=fig:Voyage dans la Lune!
516+!lalune.jpg|title=fig:Voyage dans la Lune, alt=lalune!
517
517
518−Here is a movie !movie.jpg! icon.
518+Here is a movie !movie.jpg|alt=movie! icon.
519
519
520----
520----
521h1. {anchor:footnotes}Footnotes
521h1. {anchor:footnotes}Footnotes
test/writer.latex+3
@@ -63,6 +63,9 @@
63\providecommand{\tightlist}{%
63\providecommand{\tightlist}{%
64 \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
64 \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
65\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
65\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
66+\ifluatex
67+ \usepackage{selnolig} % disable illegal ligatures
68+\fi
66
69
67\title{Pandoc Test Suite}
70\title{Pandoc Test Suite}
68\author{John MacFarlane \and Anonymous}
71\author{John MacFarlane \and Anonymous}
test/writers-lang-and-dir.latex+3
@@ -66,6 +66,9 @@
66 \newcommand{\textfrench}[2][]{\foreignlanguage{french}{#2}}
66 \newcommand{\textfrench}[2][]{\foreignlanguage{french}{#2}}
67 \newenvironment{french}[2][]{\begin{otherlanguage}{french}}{\end{otherlanguage}}
67 \newenvironment{french}[2][]{\begin{otherlanguage}{french}}{\end{otherlanguage}}
68\fi
68\fi
69+\ifluatex
70+ \usepackage{selnolig} % disable illegal ligatures
71+\fi
69\ifxetex
72\ifxetex
70 % Load bidi as late as possible as it modifies e.g. graphicx
73 % Load bidi as late as possible as it modifies e.g. graphicx
71 \usepackage{bidi}
74 \usepackage{bidi}