git.iko.soy/typeable/pandoc
on e89e5ce help sign in
.circleci/config.yml+2−2
since splitsnapshots
unifiedsplit
@@ -20,10 +20,10 @@ jobs:
20 command: stack --no-terminal setup
20 command: stack --no-terminal setup
21 - run:
21 - run:
22 name: Run tests
22 name: Run tests
23− command: stack --no-terminal test --ghc-options=-split-sections
23+ command: stack --no-terminal test
24 - run:
24 - run:
25 name: Install executable
25 name: Install executable
26− command: stack --no-terminal install --ghc-options=-split-sections
26+ command: stack --no-terminal install
27 - run:
27 - run:
28 name: Create artifacts
28 name: Create artifacts
29 command: |
29 command: |
AUTHORS.md+4
@@ -163,6 +163,8 @@
163- Leif Metcalf
163- Leif Metcalf
164- Leonard Rosenthol
164- Leonard Rosenthol
165- Lila
165- Lila
166+- Loïc Grobol
167+- Lorenzo
166- Lucas Escot
168- Lucas Escot
167- Luke Plant
169- Luke Plant
168- Marc Schreiber
170- Marc Schreiber
@@ -196,10 +198,12 @@
196- Nathan Gass
198- Nathan Gass
197- Neil Mayhew
199- Neil Mayhew
198- Nick Bart
200- Nick Bart
201+- Nick Berendsen
199- Nick Fleisher
202- Nick Fleisher
200- Nicolas Kaiser
203- Nicolas Kaiser
201- Nikolay Yakimov
204- Nikolay Yakimov
202- Nils Carlson
205- Nils Carlson
206+- Nixon Enraght-Moony
203- Nokome Bentley
207- Nokome Bentley
204- Ole Martin Ruud
208- Ole Martin Ruud
205- Oliver Matthews
209- Oliver Matthews
MANUAL.txt+1−1
@@ -1,7 +1,7 @@
1---
1---
2title: Pandoc User's Guide
2title: Pandoc User's Guide
3author: John MacFarlane
3author: John MacFarlane
4−date: January 21, 2021
4+date: March 4, 2021
5---
5---
6
6
7# Synopsis
7# Synopsis
README.md+6−6
@@ -8,10 +8,10 @@ pandoc --lua-filter tools/update-readme.lua README.template -o README.md
8[![github
8[![github
9release](https://img.shields.io/github/release/jgm/pandoc.svg?label=current+release)](https://github.com/jgm/pandoc/releases)
9release](https://img.shields.io/github/release/jgm/pandoc.svg?label=current+release)](https://github.com/jgm/pandoc/releases)
10[![hackage
10[![hackage
11−release](https://img.shields.io/hackage/v/pandoc.svg?label=hackage)](http://hackage.haskell.org/package/pandoc)
11+release](https://img.shields.io/hackage/v/pandoc.svg?label=hackage)](https://hackage.haskell.org/package/pandoc)
12−[![homebrew](https://img.shields.io/homebrew/v/pandoc.svg)](http://brewformulas.org/Pandoc)
12+[![homebrew](https://img.shields.io/homebrew/v/pandoc.svg)](https://formulae.brew.sh/formula/pandoc)
13[![stackage LTS
13[![stackage LTS
14−package](http://stackage.org/package/pandoc/badge/lts)](http://stackage.org/lts/package/pandoc)
14+package](https://stackage.org/package/pandoc/badge/lts)](https://www.stackage.org/lts/package/pandoc-types)
15[![CI
15[![CI
16tests](https://github.com/jgm/pandoc/workflows/CI%20tests/badge.svg)](https://github.com/jgm/pandoc/actions)
16tests](https://github.com/jgm/pandoc/workflows/CI%20tests/badge.svg)](https://github.com/jgm/pandoc/actions)
17[![license](https://img.shields.io/badge/license-GPLv2+-lightgray.svg)](https://www.gnu.org/licenses/gpl.html)
17[![license](https://img.shields.io/badge/license-GPLv2+-lightgray.svg)](https://www.gnu.org/licenses/gpl.html)
@@ -20,7 +20,7 @@ groups](https://img.shields.io/badge/pandoc-discuss-red.svg?style=social)](https
20
20
21## The universal markup converter
21## The universal markup converter
22
22
23−Pandoc is a [Haskell](http://haskell.org) library for converting from
23+Pandoc is a [Haskell](https://haskell.org) library for converting from
24one markup format to another, and a command-line tool that uses this
24one markup format to another, and a command-line tool that uses this
25library. It can convert *from*
25library. It can convert *from*
26
26
@@ -175,7 +175,7 @@ It can convert *to*
175 and JavaScript slide show)
175 and JavaScript slide show)
176- `slidy` ([Slidy](https://www.w3.org/Talks/Tools/Slidy2/) HTML and
176- `slidy` ([Slidy](https://www.w3.org/Talks/Tools/Slidy2/) HTML and
177 JavaScript slide show)
177 JavaScript slide show)
178−- `dzslides` ([DZSlides](http://paulrouget.com/dzslides/) HTML5 +
178+- `dzslides` ([DZSlides](https://paulrouget.com/dzslides/) HTML5 +
179 JavaScript slide show),
179 JavaScript slide show),
180- `revealjs` ([reveal.js](https://revealjs.com/) HTML5 + JavaScript
180- `revealjs` ([reveal.js](https://revealjs.com/) HTML5 + JavaScript
181 slide show)
181 slide show)
@@ -239,6 +239,6 @@ opening a new issue.
239## License
239## License
240
240
241© 2006-2021 John MacFarlane (jgm@berkeley.edu). Released under the
241© 2006-2021 John MacFarlane (jgm@berkeley.edu). Released under the
242−[GPL](http://www.gnu.org/copyleft/gpl.html "GNU General Public License"),
242+[GPL](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html "GNU General Public License"),
243version 2 or greater. This software carries no warranty of any kind.
243version 2 or greater. This software carries no warranty of any kind.
244(See COPYRIGHT for full copyright and warranty notices.)
244(See COPYRIGHT for full copyright and warranty notices.)
cabal.project+1−1
@@ -3,7 +3,7 @@ packages: pandoc.cabal
3tests: True
3tests: True
4
4
5package pandoc
5package pandoc
6− flags: +embed_data_files -trypandoc
6+ flags: +embed_data_files
7 ghc-options: -j +RTS -A256m -RTS
7 ghc-options: -j +RTS -A256m -RTS
8
8
9-- source-repository-package
9-- source-repository-package
changelog.md+189−99
@@ -2,6 +2,11 @@
2
2
3## pandoc 2.12 (UNRELEASED -- PROVISIONAL)
3## pandoc 2.12 (UNRELEASED -- PROVISIONAL)
4
4
5+ * When downloading content from URL arguments, be sensitive to
6+ the character encoding (#5600). We can properly handle UTF-8 and latin1
7+ (ISO-8859-1); for others we raise an error. Fall back to latin1 if
8+ no charset is given in the mime type and UTF-8 decoding fails.
9+
5 * Add new unexported module Text.Pandoc.XML.Light, as well
10 * Add new unexported module Text.Pandoc.XML.Light, as well
6 as Text.Pandoc.XML.Light.Types, Text.Pantoc.XML.Light.Proc,
11 as Text.Pandoc.XML.Light.Types, Text.Pantoc.XML.Light.Proc,
7 Text.Pandoc.XML.Light.Output. (Closes #6001, #6565, #7091).
12 Text.Pandoc.XML.Light.Output. (Closes #6001, #6565, #7091).
@@ -34,75 +39,6 @@
34 these have been added. And the docx golden tests have been updated,
39 these have been added. And the docx golden tests have been updated,
35 because the new parser does not preserve the order of attributes.
40 because the new parser does not preserve the order of attributes.
36
41
37− * Text.Pandoc.App
38−
39− + Add `parseOptionsFromArgs` [API change, new exported function].
40−
41− * Text.Pandoc.Citeproc.BibTeX
42−
43− + `Text.Pandoc.Citeproc.writeBibTeXString` now returns
44− `Doc Text` instead of `Text` (#7068).
45− + Correctly handle `pages` (= `page` in CSL) (#7067).
46− + Correctly handle BibLaTeX `langid` (= `language` in CSL, #7067).
47− + In BibTeX output, protect foreign titles since there's no language
48− field (#7067).
49− + Clean up BibTeX parsing (#7049). Previously there was a messy code
50− path that gave strange results in some cases, not passing through raw
51− tex but trying to extract a string content. This was an artefact of
52− trying to handle some special bibtex-specific commands in the BibTeX
53− reader. Now we just handle these in the LaTeX reader and simplify
54− parsing in the BibTeX reader. This does mean that more raw tex will
55− be passed through (and currently this is not sensitive to the
56− `raw_tex` extension; this should be fixed).
57−
58− * Text.Pandoc.Citeproc.MetaValue
59−
60− + Correctly parse "raw" date value in markdown references metadata.
61− (See jgm/citeproc#53.)
62−
63− * Text.Pandoc.Class
64−
65− + Add `getTimestamp` [API change]. This attempts to read the
66− `SOURCE_DATE_EPOCH` environment variable and parse a UTC time
67− from it (treating it as a unix date stamp, see
68− https://reproducible-builds.org/specs/source-date-epoch/). If the
69− variable is not set or can't be parsed as a unix date stamp, then the
70− function returns the current date.
71−
72− * Text.Pandoc.Error
73−
74− + Remove unused variables (Albert Krewinkel)
75− + Export `renderError` [API change].
76− + Refactor `handleError` to use `renderError`. This allows us render
77− error messages without exiting.
78−
79− * Text.Pandoc.Extensions
80−
81− + `Ext_task_lists` is now supported by org (and turned
82− on by default) (Albert Krewinkel, #6336).
83− + Remove `Ext_fenced_code_attributes` from allowed commonmark attributes
84− (#7097). This attribute was listed as allowed, but it didn't actually
85− do anything. Use `attributes` for code attributes and more.
86−
87− * Lua subsystem:
88−
89− + Always load built-in Lua scripts from default data-dir (Albert
90− Krewinkel). The Lua modules `pandoc` and `pandoc.List` are now always
91− loaded from the system's default data directory. Loading from a
92− different directory by overriding the default path, e.g. via
93− `--data-dir`, is no longer supported to avoid unexpected behavior
94− and to address security concerns.
95− + Add module "pandoc.path" (Albert Krewinkel, #6001, #6565).
96− The module allows to work with file paths in a convenient and
97− platform-independent manner.
98−
99− * Text.Pandoc.PDF
100−
101− + Disable `smart` extension when building PDF via LaTeX.
102− This is to prevent accidental creation of ligatures like
103− `` ?` `` and `` !` `` (especially in languages with quotations like
104− German), and similar ligature issues. (See jgm/citeproc#54.)
105−
106 * DocBook reader:
42 * DocBook reader:
107
43
108 + Avoid expensive tree normalization step, as it is not necessary
44 + Avoid expensive tree normalization step, as it is not necessary
@@ -137,6 +73,11 @@
137
73
138 * LaTeX reader:
74 * LaTeX reader:
139
75
76+ + Don't export `tokenize`, `untokenize` [API change]. These are internal
77+ implementation details, which were only exported for testing.
78+ They don't belong in the public API.
79+ + Improved efficiency of the parser. With these changes the reader
80+ is almost twice as fast as in the last release in our benchmarks.
140 + Code cleanup, removing some unnecessary things.
81 + Code cleanup, removing some unnecessary things.
141 + Rewrite `withRaw` so it doesn't rely on fragile assumptions
82 + Rewrite `withRaw` so it doesn't rely on fragile assumptions
142 about token positions (which break when macros are expanded)
83 about token positions (which break when macros are expanded)
@@ -156,11 +97,19 @@
156 it doesn't change anything.
97 it doesn't change anything.
157 + Improve `braced'`. Remove the parameter, have it parse the
98 + Improve `braced'`. Remove the parameter, have it parse the
158 opening brace, and make it more efficient.
99 opening brace, and make it more efficient.
100+ + Factor out pieces of the LaTeX reader to make the module smaller.
101+ This reduces memory demands when compiling. Created
102+ Text.Pandoc.Readers.{LaTeX,Math,Citation,Table,Macro,Inline}.
103+ Changed Text.Pandoc.Readers.LaTeX.SIunitx to export a command map
104+ instead of individual commands.
105+
106+ * Make Text.Pandoc.Readers.LaTeX.Types an unexported module [API change].
159
107
160 * Markdown reader:
108 * Markdown reader:
161
109
162 + Improved handling of mmd link attributes in references (#7080).
110 + Improved handling of mmd link attributes in references (#7080).
163 Previously they only worked for links that had titles.
111 Previously they only worked for links that had titles.
112+ + Improved efficiency of the parser (benchmarks show a 15% speedup).
164
113
165 * OPML reader:
114 * OPML reader:
166
115
@@ -218,7 +167,7 @@
218 + Use `getTimestamp` instead of `getCurrentTime` for timestamp.
167 + Use `getTimestamp` instead of `getCurrentTime` for timestamp.
219 Setting `SOURCE_DATE_EPOCH` will allow reproducible builds.
168 Setting `SOURCE_DATE_EPOCH` will allow reproducible builds.
220
169
221− * Text.Pandoc.Writers.EPUB
170+ * EPUB writer:
222
171
223 + Use `getTimestamp` instead of `getCurrentTime` for timestamp.
172 + Use `getTimestamp` instead of `getCurrentTime` for timestamp.
224 Setting `SOURCE_DATE_EPOCH` will allow reproducible builds (#7093).
173 Setting `SOURCE_DATE_EPOCH` will allow reproducible builds (#7093).
@@ -233,6 +182,10 @@
233 contains an ampersand or another character with a special meaning
182 contains an ampersand or another character with a special meaning
234 in XML.
183 in XML.
235
184
185+ * Jira writer:
186+
187+ + Use Span identifiers as anchors (Albert Krewinkel,
188+
236 * LaTeX writer:
189 * LaTeX writer:
237
190
238 + Adjust hypertargets to beginnings of paragraphs (#7078).
191 + Adjust hypertargets to beginnings of paragraphs (#7078).
@@ -241,12 +194,18 @@
241 This makes a particular difference for links to citations using
194 This makes a particular difference for links to citations using
242 `--citeproc` and `link-citations: true`.
195 `--citeproc` and `link-citations: true`.
243 + Change BCP47 lang tag from `jp` to `ja` (Mauro Bieg, #7047).
196 + Change BCP47 lang tag from `jp` to `ja` (Mauro Bieg, #7047).
197+ + Use function instead of map for accent lookup (should be
198+ more efficient).
199+ + Split the module to make it easier to compile on low-memory
200+ systems: added Text.Pandoc.Writers.LaTeX.{Util,Citation,Lang}.
244
201
245 * Markdown writer:
202 * Markdown writer:
246
203
247 + Handle math right before digit. We insert an HTML comment to
204 + Handle math right before digit. We insert an HTML comment to
248 avoid a `$` right before a digit, which pandoc will not recognize
205 avoid a `$` right before a digit, which pandoc will not recognize
249 as a math delimiter.
206 as a math delimiter.
207+ + Split the module to make it easier to compile on low-memory
208+ systems: added Text.Pandoc.Writers.Markdown.{Types,Inline}.
250
209
251 * ODT writer:
210 * ODT writer:
252
211
@@ -279,40 +238,153 @@
279 `--include-in-header`, `--include-before-body`, `--include-after-body`)
238 `--include-in-header`, `--include-before-body`, `--include-after-body`)
280 may be used.
239 may be used.
281
240
241+ * LaTeX template:
242+
282− * LaTeX template: Update to iftex package (#7073) (Andrew Dunning)
243+ + Update to iftex package (#7073) (Andrew Dunning)
244+ + Wrap url colours in braces (#7121) (Loïc Grobol).
283
245
284 * revealjs template: Add 'center' option for vertical slide centering.
246 * revealjs template: Add 'center' option for vertical slide centering.
285 (maurerle, #7104).
247 (maurerle, #7104).
286
248
287 * Text.Pandoc.XML: Improve efficiency of `fromEntities`.
249 * Text.Pandoc.XML: Improve efficiency of `fromEntities`.
288
250
251+ * Text.Pandoc.MIME
252+
253+ + Add exported function `getCharset` [API change].
254+
255+ * Text.Pandoc.UTF8: change IO functions to return Text, not String
256+ [API change]. This affects `readFile`, `getContents`, `writeFileWith`,
257+ `writeFile`, `putStrWith`, `putStr`, `putStrLnWith`, `putStrLn`.
258+ `hPutStrWith`, `hPutStr`, `hPutStrLnWith`, `hPutStrLn`, `hGetContents`.
259+ This avoids the need to uselessly create a linked list of characters
260+ when emiting output.
261+
262+ * Text.Pandoc.App
263+
264+ + Add `parseOptionsFromArgs` [API change, new exported function].
265+
266+ * Text.Pandoc.Citeproc.BibTeX
267+
268+ + `Text.Pandoc.Citeproc.writeBibTeXString` now returns
269+ `Doc Text` instead of `Text` (#7068).
270+ + Correctly handle `pages` (= `page` in CSL) (#7067).
271+ + Correctly handle BibLaTeX `langid` (= `language` in CSL, #7067).
272+ + In BibTeX output, protect foreign titles since there's no language
273+ field (#7067).
274+ + Clean up BibTeX parsing (#7049). Previously there was a messy code
275+ path that gave strange results in some cases, not passing through raw
276+ tex but trying to extract a string content. This was an artefact of
277+ trying to handle some special bibtex-specific commands in the BibTeX
278+ reader. Now we just handle these in the LaTeX reader and simplify
279+ parsing in the BibTeX reader. This does mean that more raw tex will
280+ be passed through (and currently this is not sensitive to the
281+ `raw_tex` extension; this should be fixed).
282+
283+ * Text.Pandoc.Citeproc.MetaValue
284+
285+ + Correctly parse "raw" date value in markdown references metadata.
286+ (See jgm/citeproc#53.)
287+
288+ * Text.Pandoc.Citeproc
289+
290+ + Use https URLs for links (Salim B, #7122).
291+
292+ * Text.Pandoc.Class
293+
294+ + Add `getTimestamp` [API change]. This attempts to read the
295+ `SOURCE_DATE_EPOCH` environment variable and parse a UTC time
296+ from it (treating it as a unix date stamp, see
297+ https://reproducible-builds.org/specs/source-date-epoch/). If the
298+ variable is not set or can't be parsed as a unix date stamp, then the
299+ function returns the current date.
300+
301+ * Text.Pandoc.Error
302+
303+ + Add `PandocUnsupportedCharsetError` constructor for
304+ `PandocError` [API change].
305+ + Export `renderError` [API change].
306+ + Refactor `handleError` to use `renderError`. This allows us render
307+ error messages without exiting.
308+ + Remove unused variables (Albert Krewinkel)
309+
310+ * Text.Pandoc.Extensions
311+
312+ + `Ext_task_lists` is now supported by org (and turned
313+ on by default) (Albert Krewinkel, #6336).
314+ + Remove `Ext_fenced_code_attributes` from allowed commonmark attributes
315+ (#7097). This attribute was listed as allowed, but it didn't actually
316+ do anything. Use `attributes` for code attributes and more.
317+
318+ * Lua subsystem:
319+
320+ + Always load built-in Lua scripts from default data-dir (Albert
321+ Krewinkel). The Lua modules `pandoc` and `pandoc.List` are now always
322+ loaded from the system's default data directory. Loading from a
323+ different directory by overriding the default path, e.g. via
324+ `--data-dir`, is no longer supported to avoid unexpected behavior
325+ and to address security concerns.
326+ + Add module "pandoc.path" (Albert Krewinkel, #6001, #6565).
327+ The module allows to work with file paths in a convenient and
328+ platform-independent manner.
329+ + Use strict evaluation when retrieving AST value from the stack
330+ (Albert Krewinkel, #6674).
331+
332+ * Text.Pandoc.PDF
333+
334+ + Disable `smart` extension when building PDF via LaTeX.
335+ This is to prevent accidental creation of ligatures like
336+ `` ?` `` and `` !` `` (especially in languages with quotations like
337+ German), and similar ligature issues. (See jgm/citeproc#54.)
338+
339+ * Text.Pandoc.CSV:
340+
341+ + Fix parsing of unquoted values (#7112). Previously we didn't allow
342+ unescaped quotes in unquoted values, but they are allowed
343+ in CSV.
344+
345+ * Test suite:
346+
289− * Test suite: a more robust way of testing the executable.
347+ + Use a more robust method for testing the executable. Many
290− Many of our tests require running the pandoc executable. This is
348+ of our tests require running the pandoc executable. This
291− problematic for a few different reasons. First, cabal-install will
349+ is problematic for a few different reasons. First,
292− sometimes run the test suite after building the library but before
350+ cabal-install will sometimes run the test suite after
351+ building the library but before building the executable,
293− building the executable, which means the executable isn't in place for
352+ which means the executable isn't in place for the tests.
294− the tests. One can work around that by first building, then building and
353+ One can work around that by first building, then building
295− running the tests, but that's fragile. Second, we have to find the
354+ and running the tests, but that's fragile. Second, we
296− executable. So far, we've done that using a function `findPandoc` that
355+ have to find the executable. So far, we've done that using
356+ a function `findPandoc` that attempts to locate it
297− attempts to locate it relative to the test executable (which can be
357+ relative to the test executable (which can be located
298− located using findExecutablePath). But the logic here is delicate and
358+ using findExecutablePath). But the logic here is delicate
299− work with every combination of options. To solve both problems, we add
359+ and work with every combination of options. To solve both
360+ problems, we add an `--emulate` option to the
300− an `--emulate` option to the `test-pandoc` executable. When `--emulate`
361+ `test-pandoc` executable. When `--emulate` occurs as the
301− occurs as the first argument passed to `test-pandoc`, the program simply
362+ first argument passed to `test-pandoc`, the program simply
302− emulates the regular pandoc executable, using the rest of the arguments
363+ emulates the regular pandoc executable, using the rest of
303− (after `--emulate`). Thus, `test-pandoc --emulate -f markdown -t latex`
364+ the arguments (after `--emulate`). Thus, `test-pandoc
304− is just like `pandoc -f markdown -t latex`.
365+ --emulate -f markdown -t latex` is just like `pandoc -f
305− Since all the work is done by library functions, implementing this
366+ markdown -t latex`. Since all the work is done by library
367+ functions, implementing this emulation just takes a couple
306− emulation just takes a couple lines of code and should be entirely
368+ lines of code and should be entirely reliable. With this
307− reliable. With this change, we can test the pandoc executable by running
369+ change, we can test the pandoc executable by running the
308− the test program itself (locatable using `findExecutablePath`) with the
370+ test program itself (locatable using `findExecutablePath`)
309− `--emulate` option. This removes the need for the fragile `findPandoc`
371+ with the `--emulate` option. This removes the need for the
372+ fragile `findPandoc` step, and it means we can run our
310− step, and it means we can run our integration tests even when we're just
373+ integration tests even when we're just building the
311− building the library, not the executable. [Note: part of this change
374+ library, not the executable. [Note: part of this change
312− involved simplifying some complex handling to set environment variables
375+ involved simplifying some complex handling to set
313− for dynamic library paths. I have tested a build with
376+ environment variables for dynamic library paths. I have
377+ tested a build with `--enable-dynamic-executable`, and it
314− `--enable-dynamic-executable`, and it works, but further testing may be
378+ works, but further testing may be needed.]
315− needed.]
379+ + Print accurate location if a test fails (Albert
380+ Krewinkel). Ensures that tasty-hunit reports the location
381+ of the failing test instead of the location of the helper
382+ `test` function.
383+
384+ * Documentation: Update URLs and use `https` where possible (#7122,
385+ Salim B).
386+
387+ * Add `doc/libraries.md`, a description of libraries that support pandoc.
316
388
317 * MANUAL.txt
389 * MANUAL.txt
318
390
@@ -328,6 +400,9 @@
328 * Makefile: in `make bench`, create CSV files for comparison and compare
400 * Makefile: in `make bench`, create CSV files for comparison and compare
329 against previous benchmark run. Add timestamp to CSV filenames.
401 against previous benchmark run. Add timestamp to CSV filenames.
330
402
403+ * cabal.project: don't explicitly set -trypandoc.
404+ If we do, this can't be overridden on the cabal command line.
405+
331 * doc/lua-filters.md: improve documentation for
406 * doc/lua-filters.md: improve documentation for
332 `pandoc.mediabag.insert`, `pandoc.mediabag.fetch`,
407 `pandoc.mediabag.insert`, `pandoc.mediabag.fetch`,
333 `directory`, `normalize` (Albert Krewinkel).
408 `directory`, `normalize` (Albert Krewinkel).
@@ -336,9 +411,17 @@
336
411
337 * Require jira-wiki-markup 1.3.3 (Albert Krewinkel)
412 * Require jira-wiki-markup 1.3.3 (Albert Krewinkel)
338
413
339− * Require citeproc 0.3.0.7, which correctly titlecases when titles
414+ * Require citeproc 0.3.0.8, which correctly titlecases when titles
340 contain non-ASCII characters.
415 contain non-ASCII characters.
341
416
417+ * Use skylighting 0.10.4. This version of skylighting uses xml-conduit
418+ rather than hxt. This speeds up parsing of XML syntax definitions
419+ fourfold, and removes four packages from pandoc's dependency graph:
420+ hxt-charproperties, hxt-unicode, hxt-regex-xmlschema, hxt.
421+
422+ * Add script `tools/parseTimings.pl` to help pin down which
423+ modules take the most time and memory to compile.
424+
342 * Avoid unnecessary use of NoImplicitPrelude pragma (#7089) (Albert
425 * Avoid unnecessary use of NoImplicitPrelude pragma (#7089) (Albert
343 Krewinkel)
426 Krewinkel)
344
427
@@ -353,6 +436,13 @@
353 + Clean up benchmark code.
436 + Clean up benchmark code.
354 + Allow specifying patterns using `-p blah'.
437 + Allow specifying patterns using `-p blah'.
355
438
439+ * trypandoc: add 2 second timeout.
440+
441+ * Use `-split-sections` in creating linux release binary.
442+ This reduces executable size significantly (by about 30%).
443+
444+ * Remove `weigh-pandoc`. It's not really useful any more, now that our
445+ regular benchmarks include data on allocation.
356
446
357
447
358## pandoc 2.11.4 (2021-01-22)
448## pandoc 2.11.4 (2021-01-22)
doc/libraries.mdnew file+59
@@ -0,0 +1,59 @@
1+---
2+title: The pandoc family of libraries
3+author: John MacFarlane
4+---
5+
6+The following Haskell libraries have been developed to support
7+pandoc:
8+
9+[skylighting-core] and [skylighting]
10+: Syntax highlighting engine supporting over 140 languages.
11+
12+[citeproc]
13+: Citation processing using CSL stylesheets.
14+
15+[texmath]
16+: Conversion of math between tex, Word equation, MathML, and GNU eqn.
17+
18+[doclayout]
19+: Combinators for laying out a textual document, with support
20+ for line wrapping, tabular layout, and more.
21+
22+[doctemplates]
23+: Supports pandoc's templates.
24+
25+[commonmark], [commonmark-extensions], and [commonmark-pandoc]
26+: Efficient, standards-compliant parser for commonmark and extensions.
27+
28+[ipynb]
29+: Representation of Jupyter notebooks and conversion to and
30+ from JSON.
31+
32+[zip-archive]
33+: A pure zip file creator and extractor, used by pandoc for
34+ docx, ODT, and EPUB.
35+
36+[rfc5051]
37+: Simple unicode collation (used for citation sorting).
38+
39+[emojis]
40+: Conversion between emoji characters and aliases.
41+
42+[jira-wiki-markup]
43+: Support for parsing Jira wiki syntax.
44+
45+[skylighting]: https://hackage.haskell.org/package/skylighting
46+[skylighting-core]: https://hackage.haskell.org/package/skylighting-core
47+[citeproc]: https://hackage.haskell.org/package/citeproc
48+[texmath]: https://hackage.haskell.org/package/texmath
49+[doclayout]: https://hackage.haskell.org/package/doclayout
50+[doctemplates]: https://hackage.haskell.org/package/doctemplates
51+[commonmark]: https://hackage.haskell.org/package/commonmark
52+[commonmark-extensions]: https://hackage.haskell.org/package/commonmark-extensions
53+[commonmark-pandoc]: https://hackage.haskell.org/package/commonmark-pandoc
54+[ipynb]: https://hackage.haskell.org/package/ipynb
55+[zip-archive]: https://hackage.haskell.org/package/zip-archive
56+[rfc5051]: https://hackage.haskell.org/package/rfc5051
57+[emojis]: https://hackage.haskell.org/package/emojis
58+[jira-wiki-markup]: https://hackage.haskell.org/package/jira-wiki-markup
59+
man/pandoc.1+54−13
@@ -1,7 +1,7 @@
1'\" t
1'\" t
2.\" Automatically generated by Pandoc 2.11.4
2.\" Automatically generated by Pandoc 2.11.4
3.\"
3.\"
4−.TH "Pandoc User\[cq]s Guide" "" "January 21, 2021" "pandoc 2.11.4" ""
4+.TH "Pandoc User\[cq]s Guide" "" "March 4, 2021" "pandoc 2.12" ""
5.hy
5.hy
6.SH NAME
6.SH NAME
7pandoc - general markup converter
7pandoc - general markup converter
@@ -172,13 +172,12 @@ You can then test it with \f[C]pdflatex test.tex\f[R].
172When using LaTeX, the following packages need to be available (they are
172When using LaTeX, the following packages need to be available (they are
173included with all recent versions of TeX Live): \f[C]amsfonts\f[R],
173included with all recent versions of TeX Live): \f[C]amsfonts\f[R],
174\f[C]amsmath\f[R], \f[C]lm\f[R], \f[C]unicode-math\f[R],
174\f[C]amsmath\f[R], \f[C]lm\f[R], \f[C]unicode-math\f[R],
175−\f[C]ifxetex\f[R], \f[C]ifluatex\f[R], \f[C]listings\f[R] (if the
175+\f[C]iftex\f[R], \f[C]listings\f[R] (if the \f[C]--listings\f[R] option
176−\f[C]--listings\f[R] option is used), \f[C]fancyvrb\f[R],
177−\f[C]longtable\f[R], \f[C]booktabs\f[R], \f[C]graphicx\f[R] (if the
176+is used), \f[C]fancyvrb\f[R], \f[C]longtable\f[R], \f[C]booktabs\f[R],
178−document contains images), \f[C]hyperref\f[R], \f[C]xcolor\f[R],
177+\f[C]graphicx\f[R] (if the document contains images),
178+\f[C]hyperref\f[R], \f[C]xcolor\f[R], \f[C]ulem\f[R], \f[C]geometry\f[R]
179−\f[C]ulem\f[R], \f[C]geometry\f[R] (with the \f[C]geometry\f[R] variable
179+(with the \f[C]geometry\f[R] variable set), \f[C]setspace\f[R] (with
180−set), \f[C]setspace\f[R] (with \f[C]linestretch\f[R]), and
181−\f[C]babel\f[R] (with \f[C]lang\f[R]).
180+\f[C]linestretch\f[R]), and \f[C]babel\f[R] (with \f[C]lang\f[R]).
182The use of \f[C]xelatex\f[R] or \f[C]lualatex\f[R] as the PDF engine
181The use of \f[C]xelatex\f[R] or \f[C]lualatex\f[R] as the PDF engine
183requires \f[C]fontspec\f[R].
182requires \f[C]fontspec\f[R].
184\f[C]lualatex\f[R] uses \f[C]selnolig\f[R].
183\f[C]lualatex\f[R] uses \f[C]selnolig\f[R].
@@ -1614,6 +1613,11 @@ T}@T{
1614PandocPDFError
1613PandocPDFError
1615T}
1614T}
1616T{
1615T{
1616+44
1617+T}@T{
1618+PandocXMLError
1619+T}
1620+T{
161747
162147
1618T}@T{
1622T}@T{
1619PandocPDFProgramNotFoundError
1623PandocPDFProgramNotFoundError
@@ -1674,6 +1678,11 @@ T}@T{
1674PandocIpynbDecodingError
1678PandocIpynbDecodingError
1675T}
1679T}
1676T{
1680T{
1681+94
1682+T}@T{
1683+PandocUnsupportedCharsetError
1684+T}
1685+T{
167797
168697
1678T}@T{
1687T}@T{
1679PandocCouldNotFindDataFileError
1688PandocCouldNotFindDataFileError
@@ -1773,8 +1782,11 @@ data-dir:
1773verbosity: INFO
1782verbosity: INFO
1774log-file: log.json
1783log-file: log.json
1775
1784
1776−# citeproc, natbib, or biblatex
1785+# citeproc, natbib, or biblatex. This only affects LaTeX
1786+# output. If you want to use citeproc to format citations,
1787+# you should also set \[aq]citeproc: true\[aq] (see above).
1777cite-method: citeproc
1788cite-method: citeproc
1789+
1778# part, chapter, section, or default:
1790# part, chapter, section, or default:
1779top-level-division: chapter
1791top-level-division: chapter
1780abbreviations:
1792abbreviations:
@@ -2134,9 +2146,9 @@ ${ styles.html() }
2134\f[R]
2146\f[R]
2135.fi
2147.fi
2136.PP
2148.PP
2137−(If a partial is not found in the directory of the template, it will
2149+(If a partial is not found in the directory of the template and the
2150+template path is given as a relative path, it will also be sought in the
2138−also be sought in the \f[C]templates\f[R] subdirectory of the user data
2151+\f[C]templates\f[R] subdirectory of the user data directory.)
2139−directory.)
2140.PP
2152.PP
2141Partials may optionally be applied to variables using a colon:
2153Partials may optionally be applied to variables using a colon:
2142.IP
2154.IP
@@ -3928,6 +3940,9 @@ begin with a space.
3928\f[R]
3940\f[R]
3929.fi
3941.fi
3930.PP
3942.PP
3943+Inline formatting (such as emphasis) is allowed in the content, but not
3944+block-level formatting (such as block quotes or lists).
3945+.PP
3931This syntax is borrowed from reStructuredText.
3946This syntax is borrowed from reStructuredText.
3932.SS Lists
3947.SS Lists
3933.SS Bullet lists
3948.SS Bullet lists
@@ -5048,7 +5063,9 @@ delimiters.
5048.PP
5063.PP
5049For display math, use \f[C]$$\f[R] delimiters.
5064For display math, use \f[C]$$\f[R] delimiters.
5050(In this case, the delimiters may be separated from the formula by
5065(In this case, the delimiters may be separated from the formula by
5051−whitespace.)
5066+whitespace.
5067+However, there can be no blank lines betwen the opening and closing
5068+\f[C]$$\f[R] delimiters.)
5052.PP
5069.PP
5053TeX math will be printed in all output formats.
5070TeX math will be printed in all output formats.
5054How it is rendered depends on the output format:
5071How it is rendered depends on the output format:
@@ -6938,6 +6955,16 @@ A string value.
6938\f[B]\f[CB]rights\f[B]\f[R]
6955\f[B]\f[CB]rights\f[B]\f[R]
6939A string value.
6956A string value.
6940.TP
6957.TP
6958+\f[B]\f[CB]belongs-to-collection\f[B]\f[R]
6959+A string value.
6960+identifies the name of a collection to which the EPUB Publication
6961+belongs.
6962+.TP
6963+\f[B]\f[CB]group-position\f[B]\f[R]
6964+The \f[C]group-position\f[R] field indicates the numeric position in
6965+which the EPUB Publication belongs relative to other works belonging to
6966+the same \f[C]belongs-to-collection\f[R] field.
6967+.TP
6941\f[B]\f[CB]cover-image\f[B]\f[R]
6968\f[B]\f[CB]cover-image\f[B]\f[R]
6942A string value (path to cover image).
6969A string value (path to cover image).
6943.TP
6970.TP
@@ -7453,6 +7480,20 @@ need to specify a template manually using \f[C]--template\f[R] or add a
7453new default template with the name
7480new default template with the name
7454\f[C]default.NAME_OF_CUSTOM_WRITER.lua\f[R] to the \f[C]templates\f[R]
7481\f[C]default.NAME_OF_CUSTOM_WRITER.lua\f[R] to the \f[C]templates\f[R]
7455subdirectory of your user data directory (see Templates).
7482subdirectory of your user data directory (see Templates).
7483+.SH REPRODUCIBLE BUILDS
7484+.PP
7485+Some of the document formats pandoc targets (such as EPUB, docx, and
7486+ODT) include build timestamps in the generated document.
7487+That means that the files generated on successive builds will differ,
7488+even if the source does not.
7489+To avoid this, set the \f[C]SOURCE_DATE_EPOCH\f[R] environment variable,
7490+and the timestamp will be taken from it instead of the current time.
7491+\f[C]SOURCE_DATE_EPOCH\f[R] should contain an integer unix timestamp
7492+(specifying the number of second since midnight UTC January 1, 1970).
7493+.PP
7494+Some document formats also include a unique identifier.
7495+For EPUB, this can be set explicitly by setting the \f[C]identifier\f[R]
7496+metadata field (see EPUB Metadata, above).
7456.SH A NOTE ON SECURITY
7497.SH A NOTE ON SECURITY
7457.PP
7498.PP
7458If you use pandoc to convert user-contributed content in a web
7499If you use pandoc to convert user-contributed content in a web
pandoc.cabal+12−7
@@ -1,6 +1,6 @@
1cabal-version: 2.2
1cabal-version: 2.2
2name: pandoc
2name: pandoc
3−version: 2.11.4
3+version: 2.12
4build-type: Simple
4build-type: Simple
5license: GPL-2.0-or-later
5license: GPL-2.0-or-later
6license-file: COPYING.md
6license-file: COPYING.md
@@ -626,15 +626,15 @@ library
626 Text.Pandoc.Readers.HTML.Table,
626 Text.Pandoc.Readers.HTML.Table,
627 Text.Pandoc.Readers.HTML.TagCategories,
627 Text.Pandoc.Readers.HTML.TagCategories,
628 Text.Pandoc.Readers.HTML.Types,
628 Text.Pandoc.Readers.HTML.Types,
629− Text.Pandoc.Readers.LaTeX.Types,
629+ Text.Pandoc.Readers.LaTeX.Inline,
630− Text.Pandoc.Readers.LaTeX.Parsing,
631− Text.Pandoc.Readers.LaTeX.Lang,
632− Text.Pandoc.Readers.LaTeX.SIunitx,
633− Text.Pandoc.Readers.LaTeX.Accent,
634 Text.Pandoc.Readers.LaTeX.Citation,
630 Text.Pandoc.Readers.LaTeX.Citation,
631+ Text.Pandoc.Readers.LaTeX.Lang,
632+ Text.Pandoc.Readers.LaTeX.Macro,
635 Text.Pandoc.Readers.LaTeX.Math,
633 Text.Pandoc.Readers.LaTeX.Math,
634+ Text.Pandoc.Readers.LaTeX.Parsing,
635+ Text.Pandoc.Readers.LaTeX.SIunitx,
636 Text.Pandoc.Readers.LaTeX.Table,
636 Text.Pandoc.Readers.LaTeX.Table,
637− Text.Pandoc.Readers.LaTeX.Macro,
637+ Text.Pandoc.Readers.LaTeX.Types,
638 Text.Pandoc.Readers.Odt.Base,
638 Text.Pandoc.Readers.Odt.Base,
639 Text.Pandoc.Readers.Odt.Namespaces,
639 Text.Pandoc.Readers.Odt.Namespaces,
640 Text.Pandoc.Readers.Odt.StyleReader,
640 Text.Pandoc.Readers.Odt.StyleReader,
@@ -664,7 +664,12 @@ library
664 Text.Pandoc.Writers.LaTeX.Caption,
664 Text.Pandoc.Writers.LaTeX.Caption,
665 Text.Pandoc.Writers.LaTeX.Notes,
665 Text.Pandoc.Writers.LaTeX.Notes,
666 Text.Pandoc.Writers.LaTeX.Table,
666 Text.Pandoc.Writers.LaTeX.Table,
667+ Text.Pandoc.Writers.LaTeX.Lang,
667 Text.Pandoc.Writers.LaTeX.Types,
668 Text.Pandoc.Writers.LaTeX.Types,
669+ Text.Pandoc.Writers.LaTeX.Citation,
670+ Text.Pandoc.Writers.LaTeX.Util,
671+ Text.Pandoc.Writers.Markdown.Types,
672+ Text.Pandoc.Writers.Markdown.Inline,
668 Text.Pandoc.Writers.Roff,
673 Text.Pandoc.Writers.Roff,
669 Text.Pandoc.Writers.Powerpoint.Presentation,
674 Text.Pandoc.Writers.Powerpoint.Presentation,
670 Text.Pandoc.Writers.Powerpoint.Output,
675 Text.Pandoc.Writers.Powerpoint.Output,
src/Text/Pandoc/Readers/LaTeX.hs+108−396
@@ -34,14 +34,14 @@ import qualified Data.Set as Set
34import Data.Text (Text)
34import Data.Text (Text)
35import qualified Data.Text as T
35import qualified Data.Text as T
36import System.FilePath (addExtension, replaceExtension, takeExtension)
36import System.FilePath (addExtension, replaceExtension, takeExtension)
37−import Text.Pandoc.BCP47 (Lang (..), renderLang)
37+import Text.Pandoc.BCP47 (renderLang)
38−import Text.Pandoc.Builder
38+import Text.Pandoc.Builder as B
39import Text.Pandoc.Class.PandocPure (PandocPure)
39import Text.Pandoc.Class.PandocPure (PandocPure)
40import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
40import Text.Pandoc.Class.PandocMonad (PandocMonad (..), getResourcePath,
41− readFileFromDirs, report, setResourcePath,
41+ readFileFromDirs, report,
42− translateTerm)
42+ setResourcePath)
43import Text.Pandoc.Error (PandocError (PandocParseError, PandocParsecError))
43import Text.Pandoc.Error (PandocError (PandocParseError, PandocParsecError))
44−import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
44+import Text.Pandoc.Highlighting (languagesByExtension)
45import Text.Pandoc.ImageSize (numUnit, showFl)
45import Text.Pandoc.ImageSize (numUnit, showFl)
46import Text.Pandoc.Logging
46import Text.Pandoc.Logging
47import Text.Pandoc.Options
47import Text.Pandoc.Options
@@ -49,7 +49,6 @@ import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline,
49 optional, space, spaces, withRaw, (<|>))
49 optional, space, spaces, withRaw, (<|>))
50import Text.Pandoc.Readers.LaTeX.Types (Tok (..), TokType (..))
50import Text.Pandoc.Readers.LaTeX.Types (Tok (..), TokType (..))
51import Text.Pandoc.Readers.LaTeX.Parsing
51import Text.Pandoc.Readers.LaTeX.Parsing
52−import Text.Pandoc.Readers.LaTeX.Accent (accentCommands)
53import Text.Pandoc.Readers.LaTeX.Citation (citationCommands, cites)
52import Text.Pandoc.Readers.LaTeX.Citation (citationCommands, cites)
54import Text.Pandoc.Readers.LaTeX.Math (dollarsMath, inlineEnvironments,
53import Text.Pandoc.Readers.LaTeX.Math (dollarsMath, inlineEnvironments,
55 inlineEnvironment,
54 inlineEnvironment,
@@ -58,13 +57,18 @@ import Text.Pandoc.Readers.LaTeX.Math (dollarsMath, inlineEnvironments,
58 theoremEnvironment)
57 theoremEnvironment)
59import Text.Pandoc.Readers.LaTeX.Table (tableEnvironments)
58import Text.Pandoc.Readers.LaTeX.Table (tableEnvironments)
60import Text.Pandoc.Readers.LaTeX.Macro (macroDef)
59import Text.Pandoc.Readers.LaTeX.Macro (macroDef)
61−import Text.Pandoc.Readers.LaTeX.Lang (polyglossiaLangToBCP47,
60+import Text.Pandoc.Readers.LaTeX.Lang (inlineLanguageCommands,
61+ enquoteCommands,
62 babelLangToBCP47, setDefaultLanguage)
62 babelLangToBCP47, setDefaultLanguage)
63import Text.Pandoc.Readers.LaTeX.SIunitx (siunitxCommands)
63import Text.Pandoc.Readers.LaTeX.SIunitx (siunitxCommands)
64+import Text.Pandoc.Readers.LaTeX.Inline (acronymCommands, refCommands,
65+ nameCommands, charCommands,
66+ accentCommands,
67+ biblatexInlineCommands,
68+ verbCommands, rawInlineOr,
69+ listingsLanguage)
64import Text.Pandoc.Shared
70import Text.Pandoc.Shared
65−import qualified Text.Pandoc.Translations as Translations
66import Text.Pandoc.Walk
71import Text.Pandoc.Walk
67−import qualified Text.Pandoc.Builder as B
68import Safe
72import Safe
69
73
70-- for debugging:
74-- for debugging:
@@ -290,18 +294,6 @@ quoted' f starter ender = do
290lit :: Text -> LP m Inlines
294lit :: Text -> LP m Inlines
291lit = pure . str
295lit = pure . str
292
296
293−enquote :: PandocMonad m => Bool -> Maybe Text -> LP m Inlines
294−enquote starred mblang = do
295− skipopts
296− let lang = mblang >>= babelLangToBCP47
297− let langspan = case lang of
298− Nothing -> id
299− Just l -> spanWith ("",[],[("lang", renderLang l)])
300− quoteContext <- sQuoteContext <$> getState
301− if starred || quoteContext == InDoubleQuote
302− then singleQuoted . langspan <$> withQuoteContext InSingleQuote tok
303− else doubleQuoted . langspan <$> withQuoteContext InDoubleQuote tok
304−
305blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks
297blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks
306blockquote cvariant mblang = do
298blockquote cvariant mblang = do
307 citepar <- if cvariant
299 citepar <- if cvariant
@@ -317,76 +309,6 @@ blockquote cvariant mblang = do
317 optional $ symbolIn (".:;?!" :: [Char]) -- currently ignored
309 optional $ symbolIn (".:;?!" :: [Char]) -- currently ignored
318 return $ blockQuote . langdiv $ (bs <> citepar)
310 return $ blockQuote . langdiv $ (bs <> citepar)
319
311
320−doAcronym :: PandocMonad m => Text -> LP m Inlines
321−doAcronym form = do
322− acro <- braced
323− return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
324− ("acronym-form", "singular+" <> form)])
325− $ str $ untokenize acro]
326−
327−doAcronymPlural :: PandocMonad m => Text -> LP m Inlines
328−doAcronymPlural form = do
329− acro <- braced
330− plural <- lit "s"
331− return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
332− ("acronym-form", "plural+" <> form)]) $
333− mconcat [str $ untokenize acro, plural]]
334−
335−doverb :: PandocMonad m => LP m Inlines
336−doverb = do
337− Tok _ Symbol t <- anySymbol
338− marker <- case T.uncons t of
339− Just (c, ts) | T.null ts -> return c
340− _ -> mzero
341− withVerbatimMode $
342− code . untokenize <$>
343− manyTill (notFollowedBy newlineTok >> verbTok marker) (symbol marker)
344−
345−verbTok :: PandocMonad m => Char -> LP m Tok
346−verbTok stopchar = do
347− t@(Tok pos toktype txt) <- anyTok
348− case T.findIndex (== stopchar) txt of
349− Nothing -> return t
350− Just i -> do
351− let (t1, t2) = T.splitAt i txt
352− inp <- getInput
353− setInput $ Tok (incSourceColumn pos i) Symbol (T.singleton stopchar)
354− : totoks (incSourceColumn pos (i + 1)) (T.drop 1 t2) ++ inp
355− return $ Tok pos toktype t1
356−
357−listingsLanguage :: [(Text, Text)] -> Maybe Text
358−listingsLanguage opts =
359− case lookup "language" opts of
360− Nothing -> Nothing
361− Just l -> fromListingsLanguage l `mplus` Just l
362−
363−dolstinline :: PandocMonad m => LP m Inlines
364−dolstinline = do
365− options <- option [] keyvals
366− let classes = maybeToList $ listingsLanguage options
367− doinlinecode classes
368−
369−domintinline :: PandocMonad m => LP m Inlines
370−domintinline = do
371− skipopts
372− cls <- untokenize <$> braced
373− doinlinecode [cls]
374−
375−doinlinecode :: PandocMonad m => [Text] -> LP m Inlines
376−doinlinecode classes = do
377− Tok _ Symbol t <- anySymbol
378− marker <- case T.uncons t of
379− Just (c, ts) | T.null ts -> return c
380− _ -> mzero
381− let stopchar = if marker == '{' then '}' else marker
382− withVerbatimMode $
383− codeWith ("",classes,[]) . T.map nlToSpace . untokenize <$>
384− manyTill (verbTok stopchar) (symbol stopchar)
385−
386−nlToSpace :: Char -> Char
387−nlToSpace '\n' = ' '
388−nlToSpace x = x
389−
390inlineCommand' :: PandocMonad m => LP m Inlines
312inlineCommand' :: PandocMonad m => LP m Inlines
391inlineCommand' = try $ do
313inlineCommand' = try $ do
392 Tok _ (CtrlSeq name) cmd <- anyControlSeq
314 Tok _ (CtrlSeq name) cmd <- anyControlSeq
@@ -405,9 +327,6 @@ inlineCommand' = try $ do
405tok :: PandocMonad m => LP m Inlines
327tok :: PandocMonad m => LP m Inlines
406tok = tokWith inline
328tok = tokWith inline
407
329
408−inBrackets :: Inlines -> Inlines
409−inBrackets x = str "[" <> x <> str "]"
410−
411unescapeURL :: Text -> Text
330unescapeURL :: Text -> Text
412unescapeURL = T.concat . go . T.splitOn "\\"
331unescapeURL = T.concat . go . T.splitOn "\\"
413 where
332 where
@@ -420,234 +339,101 @@ unescapeURL = T.concat . go . T.splitOn "\\"
420 | otherwise = "\\" <> t
339 | otherwise = "\\" <> t
421
340
422inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
341inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines)
423−inlineCommands =
342+inlineCommands = M.unions
424− M.union inlineLanguageCommands $
425− M.union (accentCommands tok) $
343+ [ accentCommands tok
426− M.union (citationCommands inline) $
344+ , citationCommands inline
427− M.union (siunitxCommands tok) $
345+ , siunitxCommands tok
346+ , acronymCommands
347+ , refCommands
348+ , nameCommands
349+ , verbCommands
350+ , charCommands
351+ , enquoteCommands tok
352+ , inlineLanguageCommands tok
353+ , biblatexInlineCommands tok
354+ , rest ]
355+ where
428− M.fromList
356+ rest = M.fromList
429− [ ("emph", extractSpaces emph <$> tok)
357+ [ ("emph", extractSpaces emph <$> tok)
430− , ("textit", extractSpaces emph <$> tok)
358+ , ("textit", extractSpaces emph <$> tok)
431− , ("textsl", extractSpaces emph <$> tok)
359+ , ("textsl", extractSpaces emph <$> tok)
432− , ("textsc", extractSpaces smallcaps <$> tok)
360+ , ("textsc", extractSpaces smallcaps <$> tok)
433− , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
361+ , ("textsf", extractSpaces (spanWith ("",["sans-serif"],[])) <$> tok)
434− , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
362+ , ("textmd", extractSpaces (spanWith ("",["medium"],[])) <$> tok)
435− , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
363+ , ("textrm", extractSpaces (spanWith ("",["roman"],[])) <$> tok)
436− , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
364+ , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok)
437− , ("texttt", ttfamily)
365+ , ("texttt", ttfamily)
438− , ("sout", extractSpaces strikeout <$> tok)
366+ , ("sout", extractSpaces strikeout <$> tok)
439− , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
367+ , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer
440− , ("lq", return (str "‘"))
441− , ("rq", return (str "’"))
442− , ("textquoteleft", return (str "‘"))
443− , ("textquoteright", return (str "’"))
444− , ("textquotedblleft", return (str "“"))
445− , ("textquotedblright", return (str "”"))
446− , ("textsuperscript", extractSpaces superscript <$> tok)
368+ , ("textsuperscript", extractSpaces superscript <$> tok)
447− , ("textsubscript", extractSpaces subscript <$> tok)
369+ , ("textsubscript", extractSpaces subscript <$> tok)
448− , ("textbackslash", lit "\\")
449− , ("backslash", lit "\\")
450− , ("slash", lit "/")
451− , ("textbf", extractSpaces strong <$> tok)
370+ , ("textbf", extractSpaces strong <$> tok)
452− , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
371+ , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
453− , ("underline", underline <$> tok)
372+ , ("underline", underline <$> tok)
454− , ("ldots", lit "…")
455− , ("vdots", lit "\8942")
456− , ("dots", lit "…")
457− , ("mdots", lit "…")
458− , ("sim", lit "~")
459− , ("sep", lit ",")
460− , ("label", rawInlineOr "label" dolabel)
461− , ("ref", rawInlineOr "ref" $ doref "ref")
462− , ("cref", rawInlineOr "cref" $ doref "ref") -- from cleveref.sty
463− , ("vref", rawInlineOr "vref" $ doref "ref+page") -- from varioref.sty
464− , ("eqref", rawInlineOr "eqref" $ doref "eqref") -- from amsmath.sty
465− , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
373+ , ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
466− , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
374+ , ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
467− , ("lettrine", rawInlineOr "lettrine" lettrine)
375+ , ("lettrine", rawInlineOr "lettrine" lettrine)
468− , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
376+ , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
469− , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
377+ , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
470− , ("ensuremath", mathInline . untokenize <$> braced)
378+ , ("ensuremath", mathInline . untokenize <$> braced)
471− , ("texorpdfstring", const <$> tok <*> tok)
379+ , ("texorpdfstring", const <$> tok <*> tok)
472− , ("P", lit "¶")
473− , ("S", lit "§")
474− , ("$", lit "$")
475− , ("%", lit "%")
476− , ("&", lit "&")
477− , ("#", lit "#")
478− , ("_", lit "_")
479− , ("{", lit "{")
480− , ("}", lit "}")
481− , ("qed", lit "\a0\x25FB")
482− -- old TeX commands
380+ -- old TeX commands
483− , ("em", extractSpaces emph <$> inlines)
381+ , ("em", extractSpaces emph <$> inlines)
484− , ("it", extractSpaces emph <$> inlines)
382+ , ("it", extractSpaces emph <$> inlines)
485− , ("sl", extractSpaces emph <$> inlines)
383+ , ("sl", extractSpaces emph <$> inlines)
486− , ("bf", extractSpaces strong <$> inlines)
384+ , ("bf", extractSpaces strong <$> inlines)
487− , ("tt", code . stringify . toList <$> inlines)
385+ , ("tt", code . stringify . toList <$> inlines)
488− , ("rm", inlines)
386+ , ("rm", inlines)
489− , ("itshape", extractSpaces emph <$> inlines)
387+ , ("itshape", extractSpaces emph <$> inlines)
490− , ("slshape", extractSpaces emph <$> inlines)
388+ , ("slshape", extractSpaces emph <$> inlines)
491− , ("scshape", extractSpaces smallcaps <$> inlines)
389+ , ("scshape", extractSpaces smallcaps <$> inlines)
492− , ("bfseries", extractSpaces strong <$> inlines)
390+ , ("bfseries", extractSpaces strong <$> inlines)
493− , ("MakeUppercase", makeUppercase <$> tok)
391+ , ("MakeUppercase", makeUppercase <$> tok)
494− , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
392+ , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
495− , ("uppercase", makeUppercase <$> tok)
393+ , ("uppercase", makeUppercase <$> tok)
496− , ("MakeLowercase", makeLowercase <$> tok)
394+ , ("MakeLowercase", makeLowercase <$> tok)
497− , ("MakeTextLowercase", makeLowercase <$> tok)
395+ , ("MakeTextLowercase", makeLowercase <$> tok)
498− , ("lowercase", makeLowercase <$> tok)
396+ , ("lowercase", makeLowercase <$> tok)
499− , ("/", pure mempty) -- italic correction
500− , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState
501− guard $ not inTableCell
502− optional rawopt
503− spaces))
504− , (",", lit "\8198")
505− , ("@", pure mempty)
506− , (" ", lit "\160")
507− , ("ps", pure $ str "PS." <> space)
508− , ("TeX", lit "TeX")
509− , ("LaTeX", lit "LaTeX")
510− , ("bar", lit "|")
511− , ("textless", lit "<")
512− , ("textgreater", lit ">")
513− , ("thanks", skipopts >> note <$> grouped block)
397+ , ("thanks", skipopts >> note <$> grouped block)
514− , ("footnote", skipopts >> note <$> grouped block)
398+ , ("footnote", skipopts >> note <$> grouped block)
515− , ("passthrough", tok) -- \passthrough macro used by latex writer
399+ , ("passthrough", tok) -- \passthrough macro used by latex writer
516− -- for listings
400+ -- for listings
517− , ("verb", doverb)
518− , ("lstinline", dolstinline)
519− , ("mintinline", domintinline)
520− , ("Verb", doverb)
521− , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
401+ , ("url", (\url -> link url "" (str url)) . unescapeURL . untokenize <$>
522− bracedUrl)
402+ bracedUrl)
523− , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
403+ , ("nolinkurl", code . unescapeURL . untokenize <$> bracedUrl)
524− , ("href", do url <- bracedUrl
404+ , ("href", do url <- bracedUrl
525− sp
405+ sp
526− link (unescapeURL $ untokenize url) "" <$> tok)
406+ link (unescapeURL $ untokenize url) "" <$> tok)
527− , ("includegraphics", do options <- option [] keyvals
407+ , ("includegraphics", do options <- option [] keyvals
528− src <- braced
408+ src <- braced
529− mkImage options . unescapeURL . removeDoubleQuotes $
409+ mkImage options . unescapeURL . removeDoubleQuotes $
530− untokenize src)
410+ untokenize src)
531− , ("enquote*", enquote True Nothing)
532− , ("enquote", enquote False Nothing)
533− -- foreignquote is supposed to use native quote marks
534− , ("foreignquote*", braced >>= enquote True . Just . untokenize)
535− , ("foreignquote", braced >>= enquote False . Just . untokenize)
536− -- hypehnquote uses regular quotes
537− , ("hyphenquote*", braced >>= enquote True . Just . untokenize)
538− , ("hyphenquote", braced >>= enquote False . Just . untokenize)
539− , ("figurename", doTerm Translations.Figure)
540− , ("prefacename", doTerm Translations.Preface)
541− , ("refname", doTerm Translations.References)
542− , ("bibname", doTerm Translations.Bibliography)
543− , ("chaptername", doTerm Translations.Chapter)
544− , ("partname", doTerm Translations.Part)
545− , ("contentsname", doTerm Translations.Contents)
546− , ("listfigurename", doTerm Translations.ListOfFigures)
547− , ("listtablename", doTerm Translations.ListOfTables)
548− , ("indexname", doTerm Translations.Index)
549− , ("abstractname", doTerm Translations.Abstract)
550− , ("tablename", doTerm Translations.Table)
551− , ("enclname", doTerm Translations.Encl)
552− , ("ccname", doTerm Translations.Cc)
553− , ("headtoname", doTerm Translations.To)
554− , ("pagename", doTerm Translations.Page)
555− , ("seename", doTerm Translations.See)
556− , ("seealsoname", doTerm Translations.SeeAlso)
557− , ("proofname", doTerm Translations.Proof)
558− , ("glossaryname", doTerm Translations.Glossary)
559− , ("lstlistingname", doTerm Translations.Listing)
560− , ("hyperlink", hyperlink)
411+ , ("hyperlink", hyperlink)
561− , ("hypertarget", hypertargetInline)
412+ , ("hypertarget", hypertargetInline)
562− -- glossaries package
563− , ("gls", doAcronym "short")
564− , ("Gls", doAcronym "short")
565− , ("glsdesc", doAcronym "long")
566− , ("Glsdesc", doAcronym "long")
567− , ("GLSdesc", doAcronym "long")
568− , ("acrlong", doAcronym "long")
569− , ("Acrlong", doAcronym "long")
570− , ("acrfull", doAcronym "full")
571− , ("Acrfull", doAcronym "full")
572− , ("acrshort", doAcronym "abbrv")
573− , ("Acrshort", doAcronym "abbrv")
574− , ("glspl", doAcronymPlural "short")
575− , ("Glspl", doAcronymPlural "short")
576− , ("glsdescplural", doAcronymPlural "long")
577− , ("Glsdescplural", doAcronymPlural "long")
578− , ("GLSdescplural", doAcronymPlural "long")
579− -- acronyms package
580− , ("ac", doAcronym "short")
581− , ("acf", doAcronym "full")
582− , ("acs", doAcronym "abbrv")
583− , ("acl", doAcronym "long")
584− , ("acp", doAcronymPlural "short")
585− , ("acfp", doAcronymPlural "full")
586− , ("acsp", doAcronymPlural "abbrv")
587− , ("aclp", doAcronymPlural "long")
588− , ("Ac", doAcronym "short")
589− , ("Acf", doAcronym "full")
590− , ("Acs", doAcronym "abbrv")
591− , ("Acl", doAcronym "long")
592− , ("Acp", doAcronymPlural "short")
593− , ("Acfp", doAcronymPlural "full")
594− , ("Acsp", doAcronymPlural "abbrv")
595− , ("Aclp", doAcronymPlural "long")
596− -- hyphenat
413+ -- hyphenat
597− , ("bshyp", lit "\\\173")
598− , ("fshyp", lit "/\173")
599− , ("dothyp", lit ".\173")
600− , ("colonhyp", lit ":\173")
601− , ("hyp", lit "-")
602− , ("nohyphens", tok)
414+ , ("nohyphens", tok)
603− , ("textnhtt", ttfamily)
415+ , ("textnhtt", ttfamily)
604− , ("nhttfamily", ttfamily)
416+ , ("nhttfamily", ttfamily)
605− -- LaTeX colors
417+ -- LaTeX colors
606− , ("textcolor", coloredInline "color")
418+ , ("textcolor", coloredInline "color")
607− , ("colorbox", coloredInline "background-color")
419+ , ("colorbox", coloredInline "background-color")
608− -- fontawesome
609− , ("faCheck", lit "\10003")
610− , ("faClose", lit "\10007")
611− -- xspace
420+ -- xspace
612− , ("xspace", doxspace)
421+ , ("xspace", doxspace)
613− -- etoolbox
422+ -- etoolbox
614− , ("ifstrequal", ifstrequal)
423+ , ("ifstrequal", ifstrequal)
615− , ("newtoggle", braced >>= newToggle)
424+ , ("newtoggle", braced >>= newToggle)
616− , ("toggletrue", braced >>= setToggle True)
425+ , ("toggletrue", braced >>= setToggle True)
617− , ("togglefalse", braced >>= setToggle False)
426+ , ("togglefalse", braced >>= setToggle False)
618− , ("iftoggle", try $ ifToggle >> inline)
427+ , ("iftoggle", try $ ifToggle >> inline)
619− -- biblatex misc
620− , ("RN", romanNumeralUpper)
621− , ("Rn", romanNumeralLower)
622− -- babel
623− , ("foreignlanguage", foreignlanguage)
624− -- include
428+ -- include
625− , ("input", rawInlineOr "input" $ include "input")
429+ , ("input", rawInlineOr "input" $ include "input")
626− -- soul package
430+ -- soul package
627− , ("ul", underline <$> tok)
431+ , ("ul", underline <$> tok)
628− -- ulem package
432+ -- ulem package
629− , ("uline", underline <$> tok)
433+ , ("uline", underline <$> tok)
630− -- plain tex stuff that should just be passed through as raw tex
434+ -- plain tex stuff that should just be passed through as raw tex
631− , ("ifdim", ifdim)
435+ , ("ifdim", ifdim)
632− -- bibtex
633− , ("mkbibquote", spanWith nullAttr . doubleQuoted <$> tok)
634− , ("mkbibemph", spanWith nullAttr . emph <$> tok)
635− , ("mkbibitalic", spanWith nullAttr . emph <$> tok)
636− , ("mkbibbold", spanWith nullAttr . strong <$> tok)
637− , ("mkbibparens",
638− spanWith nullAttr . (\x -> str "(" <> x <> str ")") <$> tok)
639− , ("mkbibbrackets",
640− spanWith nullAttr . (\x -> str "[" <> x <> str "]") <$> tok)
641− , ("autocap", spanWith nullAttr <$> tok)
642− , ("textnormal", spanWith ("",["nodecor"],[]) <$> tok)
643− , ("bibstring",
644− (\x -> spanWith ("",[],[("bibstring",x)]) (str x)) . untokenize
645− <$> braced)
646− , ("adddot", pure (str "."))
647− , ("adddotspace", pure (spanWith nullAttr (str "." <> space)))
648− , ("addabbrvspace", pure space)
649− , ("hyphen", pure (str "-"))
650− ]
436+ ]
651
437
652lettrine :: PandocMonad m => LP m Inlines
438lettrine :: PandocMonad m => LP m Inlines
653lettrine = do
439lettrine = do
@@ -671,26 +457,6 @@ alterStr :: (Text -> Text) -> Inline -> Inline
671alterStr f (Str xs) = Str (f xs)
457alterStr f (Str xs) = Str (f xs)
672alterStr _ x = x
458alterStr _ x = x
673
459
674−foreignlanguage :: PandocMonad m => LP m Inlines
675−foreignlanguage = do
676− babelLang <- untokenize <$> braced
677− case babelLangToBCP47 babelLang of
678− Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
679− _ -> tok
680−
681−inlineLanguageCommands :: PandocMonad m => M.Map Text (LP m Inlines)
682−inlineLanguageCommands = M.fromList $ mk <$> M.toList polyglossiaLangToBCP47
683− where
684− mk (polyglossia, bcp47Func) =
685− ("text" <> polyglossia, inlineLanguage bcp47Func)
686−
687−inlineLanguage :: PandocMonad m => (Text -> Lang) -> LP m Inlines
688−inlineLanguage bcp47Func = do
689− o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
690− <$> rawopt
691− let lang = renderLang $ bcp47Func o
692− extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
693−
694hyperlink :: PandocMonad m => LP m Inlines
460hyperlink :: PandocMonad m => LP m Inlines
695hyperlink = try $ do
461hyperlink = try $ do
696 src <- untokenize <$> braced
462 src <- untokenize <$> braced
@@ -711,31 +477,6 @@ hypertargetInline = try $ do
711 ils <- grouped inline
477 ils <- grouped inline
712 return $ spanWith (ref, [], []) ils
478 return $ spanWith (ref, [], []) ils
713
479
714−romanNumeralUpper :: (PandocMonad m) => LP m Inlines
715−romanNumeralUpper =
716− str . toRomanNumeral <$> romanNumeralArg
717−
718−romanNumeralLower :: (PandocMonad m) => LP m Inlines
719−romanNumeralLower =
720− str . T.toLower . toRomanNumeral <$> romanNumeralArg
721−
722−romanNumeralArg :: (PandocMonad m) => LP m Int
723−romanNumeralArg = spaces *> (parser <|> inBraces)
724− where
725− inBraces = do
726− symbol '{'
727− spaces
728− res <- parser
729− spaces
730− symbol '}'
731− return res
732− parser = do
733− s <- untokenize <$> many1 (satisfyTok isWordTok)
734− let (digits, rest) = T.span isDigit s
735− unless (T.null rest) $
736− Prelude.fail "Non-digits in argument to \\Rn or \\RN"
737− safeRead digits
738−
739newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
480newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
740newToggle name = do
481newToggle name = do
741 updateState $ \st ->
482 updateState $ \st ->
@@ -766,9 +507,6 @@ ifToggle = do
766 report $ UndefinedToggle name' pos
507 report $ UndefinedToggle name' pos
767 return ()
508 return ()
768
509
769−doTerm :: PandocMonad m => Translations.Term -> LP m Inlines
770−doTerm term = str <$> translateTerm term
771−
772ifstrequal :: (PandocMonad m, Monoid a) => LP m a
510ifstrequal :: (PandocMonad m, Monoid a) => LP m a
773ifstrequal = do
511ifstrequal = do
774 str1 <- tok
512 str1 <- tok
@@ -789,13 +527,6 @@ coloredInline stylename = do
789ttfamily :: PandocMonad m => LP m Inlines
527ttfamily :: PandocMonad m => LP m Inlines
790ttfamily = code . stringify . toList <$> tok
528ttfamily = code . stringify . toList <$> tok
791
529
792−rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
793−rawInlineOr name' fallback = do
794− parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
795− if parseRaw
796− then rawInline "latex" <$> getRawCommand name' ("\\" <> name')
797− else fallback
798−
799processHBox :: Inlines -> Inlines
530processHBox :: Inlines -> Inlines
800processHBox = walk convert
531processHBox = walk convert
801 where
532 where
@@ -846,25 +577,6 @@ treatAsInline = Set.fromList
846 , "pagebreak"
577 , "pagebreak"
847 ]
578 ]
848
579
849−dolabel :: PandocMonad m => LP m Inlines
850−dolabel = do
851− v <- braced
852− let refstr = untokenize v
853− updateState $ \st ->
854− st{ sLastLabel = Just refstr }
855− return $ spanWith (refstr,[],[("label", refstr)])
856− $ inBrackets $ str $ untokenize v
857−
858−doref :: PandocMonad m => Text -> LP m Inlines
859−doref cls = do
860− v <- braced
861− let refstr = untokenize v
862− return $ linkWith ("",[],[ ("reference-type", cls)
863− , ("reference", refstr)])
864− ("#" <> refstr)
865− ""
866− (inBrackets $ str refstr)
867−
868lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
580lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
869lookupListDefault d = (fromMaybe d .) . lookupList
581lookupListDefault d = (fromMaybe d .) . lookupList
870 where lookupList l m = msum $ map (`M.lookup` m) l
582 where lookupList l m = msum $ map (`M.lookup` m) l
src/Text/Pandoc/Readers/LaTeX/Accent.hsdeleted−78
@@ -1,78 +0,0 @@
1−{-# LANGUAGE ViewPatterns #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−module Text.Pandoc.Readers.LaTeX.Accent
4− ( accentCommands )
5−where
6−
7−import Text.Pandoc.Class
8−import Text.Pandoc.Readers.LaTeX.Parsing
9−import Text.Pandoc.Builder as B
10−import qualified Data.Map as M
11−import Data.Text (Text)
12−import Data.Maybe (fromMaybe)
13−import Text.Pandoc.Parsing
14−import qualified Data.Text as T
15−import qualified Data.Text.Normalize as Normalize
16−
17−accentCommands :: PandocMonad m => LP m Inlines -> M.Map Text (LP m Inlines)
18−accentCommands tok =
19− let accent = accentWith tok
20− lit = pure . str
21− in M.fromList
22− [ ("aa", lit "å")
23− , ("AA", lit "Å")
24− , ("ss", lit "ß")
25− , ("o", lit "ø")
26− , ("O", lit "Ø")
27− , ("L", lit "Ł")
28− , ("l", lit "ł")
29− , ("ae", lit "æ")
30− , ("AE", lit "Æ")
31− , ("oe", lit "œ")
32− , ("OE", lit "Œ")
33− , ("pounds", lit "£")
34− , ("euro", lit "€")
35− , ("copyright", lit "©")
36− , ("textasciicircum", lit "^")
37− , ("textasciitilde", lit "~")
38− , ("H", accent '\779' Nothing) -- hungarumlaut
39− , ("`", accent '\768' (Just '`')) -- grave
40− , ("'", accent '\769' (Just '\'')) -- acute
41− , ("^", accent '\770' (Just '^')) -- circ
42− , ("~", accent '\771' (Just '~')) -- tilde
43− , ("\"", accent '\776' Nothing) -- umlaut
44− , (".", accent '\775' Nothing) -- dot
45− , ("=", accent '\772' Nothing) -- macron
46− , ("|", accent '\781' Nothing) -- vertical line above
47− , ("b", accent '\817' Nothing) -- macron below
48− , ("c", accent '\807' Nothing) -- cedilla
49− , ("G", accent '\783' Nothing) -- doublegrave
50− , ("h", accent '\777' Nothing) -- hookabove
51− , ("d", accent '\803' Nothing) -- dotbelow
52− , ("f", accent '\785' Nothing) -- inverted breve
53− , ("r", accent '\778' Nothing) -- ringabove
54− , ("t", accent '\865' Nothing) -- double inverted breve
55− , ("U", accent '\782' Nothing) -- double vertical line above
56− , ("v", accent '\780' Nothing) -- hacek
57− , ("u", accent '\774' Nothing) -- breve
58− , ("k", accent '\808' Nothing) -- ogonek
59− , ("textogonekcentered", accent '\808' Nothing) -- ogonek
60− , ("i", lit "ı") -- dotless i
61− , ("j", lit "ȷ") -- dotless j
62− , ("newtie", accent '\785' Nothing) -- inverted breve
63− , ("textcircled", accent '\8413' Nothing) -- combining circle
64− ]
65−
66−accentWith :: PandocMonad m
67− => LP m Inlines -> Char -> Maybe Char -> LP m Inlines
68−accentWith tok combiningAccent fallBack = try $ do
69− ils <- tok
70− case toList ils of
71− (Str (T.uncons -> Just (x, xs)) : ys) -> return $ fromList $
72− -- try to normalize to the combined character:
73− Str (Normalize.normalize Normalize.NFC
74− (T.pack [x, combiningAccent]) <> xs) : ys
75− [Space] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
76− [] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
77− _ -> return ils
78−
src/Text/Pandoc/Readers/LaTeX/Inline.hsnew file+397
@@ -0,0 +1,397 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ViewPatterns #-}
3+{- |
4+ Module : Text.Pandoc.Readers.LaTeX.Inline
5+ Copyright : Copyright (C) 2006-2021 John MacFarlane
6+ License : GNU GPL, version 2 or above
7+
8+ Maintainer : John MacFarlane <jgm@berkeley.edu>
9+ Stability : alpha
10+ Portability : portable
11+-}
12+module Text.Pandoc.Readers.LaTeX.Inline
13+ ( acronymCommands
14+ , verbCommands
15+ , charCommands
16+ , accentCommands
17+ , nameCommands
18+ , biblatexInlineCommands
19+ , refCommands
20+ , rawInlineOr
21+ , listingsLanguage
22+ )
23+where
24+
25+import qualified Data.Map as M
26+import Data.Text (Text)
27+import qualified Data.Text as T
28+import Text.Pandoc.Builder
29+import Text.Pandoc.Shared (toRomanNumeral, safeRead)
30+import Text.Pandoc.Readers.LaTeX.Types (Tok (..), TokType (..))
31+import Control.Applicative (optional, (<|>))
32+import Control.Monad (guard, mzero, mplus, unless)
33+import Text.Pandoc.Class.PandocMonad (PandocMonad (..), translateTerm)
34+import Text.Pandoc.Readers.LaTeX.Parsing
35+import Text.Pandoc.Extensions (extensionEnabled, Extension(..))
36+import Text.Pandoc.Parsing (getOption, updateState, getState, notFollowedBy,
37+ manyTill, getInput, setInput, incSourceColumn,
38+ option, many1, try)
39+import Data.Char (isDigit)
40+import Text.Pandoc.Highlighting (fromListingsLanguage,)
41+import Data.Maybe (maybeToList, fromMaybe)
42+import Text.Pandoc.Options (ReaderOptions(..))
43+import qualified Data.Text.Normalize as Normalize
44+import qualified Text.Pandoc.Translations as Translations
45+
46+rawInlineOr :: PandocMonad m => Text -> LP m Inlines -> LP m Inlines
47+rawInlineOr name' fallback = do
48+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
49+ if parseRaw
50+ then rawInline "latex" <$> getRawCommand name' ("\\" <> name')
51+ else fallback
52+
53+dolabel :: PandocMonad m => LP m Inlines
54+dolabel = do
55+ v <- braced
56+ let refstr = untokenize v
57+ updateState $ \st ->
58+ st{ sLastLabel = Just refstr }
59+ return $ spanWith (refstr,[],[("label", refstr)])
60+ $ inBrackets $ str $ untokenize v
61+
62+doref :: PandocMonad m => Text -> LP m Inlines
63+doref cls = do
64+ v <- braced
65+ let refstr = untokenize v
66+ return $ linkWith ("",[],[ ("reference-type", cls)
67+ , ("reference", refstr)])
68+ ("#" <> refstr)
69+ ""
70+ (inBrackets $ str refstr)
71+
72+inBrackets :: Inlines -> Inlines
73+inBrackets x = str "[" <> x <> str "]"
74+
75+doTerm :: PandocMonad m => Translations.Term -> LP m Inlines
76+doTerm term = str <$> translateTerm term
77+
78+lit :: Text -> LP m Inlines
79+lit = pure . str
80+
81+doverb :: PandocMonad m => LP m Inlines
82+doverb = do
83+ Tok _ Symbol t <- anySymbol
84+ marker <- case T.uncons t of
85+ Just (c, ts) | T.null ts -> return c
86+ _ -> mzero
87+ withVerbatimMode $
88+ code . untokenize <$>
89+ manyTill (notFollowedBy newlineTok >> verbTok marker) (symbol marker)
90+
91+verbTok :: PandocMonad m => Char -> LP m Tok
92+verbTok stopchar = do
93+ t@(Tok pos toktype txt) <- anyTok
94+ case T.findIndex (== stopchar) txt of
95+ Nothing -> return t
96+ Just i -> do
97+ let (t1, t2) = T.splitAt i txt
98+ inp <- getInput
99+ setInput $ Tok (incSourceColumn pos i) Symbol (T.singleton stopchar)
100+ : totoks (incSourceColumn pos (i + 1)) (T.drop 1 t2) ++ inp
101+ return $ Tok pos toktype t1
102+
103+listingsLanguage :: [(Text, Text)] -> Maybe Text
104+listingsLanguage opts =
105+ case lookup "language" opts of
106+ Nothing -> Nothing
107+ Just l -> fromListingsLanguage l `mplus` Just l
108+
109+dolstinline :: PandocMonad m => LP m Inlines
110+dolstinline = do
111+ options <- option [] keyvals
112+ let classes = maybeToList $ listingsLanguage options
113+ doinlinecode classes
114+
115+domintinline :: PandocMonad m => LP m Inlines
116+domintinline = do
117+ skipopts
118+ cls <- untokenize <$> braced
119+ doinlinecode [cls]
120+
121+doinlinecode :: PandocMonad m => [Text] -> LP m Inlines
122+doinlinecode classes = do
123+ Tok _ Symbol t <- anySymbol
124+ marker <- case T.uncons t of
125+ Just (c, ts) | T.null ts -> return c
126+ _ -> mzero
127+ let stopchar = if marker == '{' then '}' else marker
128+ withVerbatimMode $
129+ codeWith ("",classes,[]) . T.map nlToSpace . untokenize <$>
130+ manyTill (verbTok stopchar) (symbol stopchar)
131+
132+nlToSpace :: Char -> Char
133+nlToSpace '\n' = ' '
134+nlToSpace x = x
135+
136+romanNumeralUpper :: (PandocMonad m) => LP m Inlines
137+romanNumeralUpper =
138+ str . toRomanNumeral <$> romanNumeralArg
139+
140+romanNumeralLower :: (PandocMonad m) => LP m Inlines
141+romanNumeralLower =
142+ str . T.toLower . toRomanNumeral <$> romanNumeralArg
143+
144+romanNumeralArg :: (PandocMonad m) => LP m Int
145+romanNumeralArg = spaces *> (parser <|> inBraces)
146+ where
147+ inBraces = do
148+ symbol '{'
149+ spaces
150+ res <- parser
151+ spaces
152+ symbol '}'
153+ return res
154+ parser = do
155+ s <- untokenize <$> many1 (satisfyTok isWordTok)
156+ let (digits, rest) = T.span isDigit s
157+ unless (T.null rest) $
158+ Prelude.fail "Non-digits in argument to \\Rn or \\RN"
159+ safeRead digits
160+
161+accentWith :: PandocMonad m
162+ => LP m Inlines -> Char -> Maybe Char -> LP m Inlines
163+accentWith tok combiningAccent fallBack = try $ do
164+ ils <- tok
165+ case toList ils of
166+ (Str (T.uncons -> Just (x, xs)) : ys) -> return $ fromList $
167+ -- try to normalize to the combined character:
168+ Str (Normalize.normalize Normalize.NFC
169+ (T.pack [x, combiningAccent]) <> xs) : ys
170+ [Space] -> return $ str $ T.singleton
171+ $ fromMaybe combiningAccent fallBack
172+ [] -> return $ str $ T.singleton
173+ $ fromMaybe combiningAccent fallBack
174+ _ -> return ils
175+
176+
177+verbCommands :: PandocMonad m => M.Map Text (LP m Inlines)
178+verbCommands = M.fromList
179+ [ ("verb", doverb)
180+ , ("lstinline", dolstinline)
181+ , ("mintinline", domintinline)
182+ , ("Verb", doverb)
183+ ]
184+
185+accentCommands :: PandocMonad m => LP m Inlines -> M.Map Text (LP m Inlines)
186+accentCommands tok =
187+ let accent = accentWith tok
188+ in M.fromList
189+ [ ("aa", lit "å")
190+ , ("AA", lit "Å")
191+ , ("ss", lit "ß")
192+ , ("o", lit "ø")
193+ , ("O", lit "Ø")
194+ , ("L", lit "Ł")
195+ , ("l", lit "ł")
196+ , ("ae", lit "æ")
197+ , ("AE", lit "Æ")
198+ , ("oe", lit "œ")
199+ , ("OE", lit "Œ")
200+ , ("pounds", lit "£")
201+ , ("euro", lit "€")
202+ , ("copyright", lit "©")
203+ , ("textasciicircum", lit "^")
204+ , ("textasciitilde", lit "~")
205+ , ("H", accent '\779' Nothing) -- hungarumlaut
206+ , ("`", accent '\768' (Just '`')) -- grave
207+ , ("'", accent '\769' (Just '\'')) -- acute
208+ , ("^", accent '\770' (Just '^')) -- circ
209+ , ("~", accent '\771' (Just '~')) -- tilde
210+ , ("\"", accent '\776' Nothing) -- umlaut
211+ , (".", accent '\775' Nothing) -- dot
212+ , ("=", accent '\772' Nothing) -- macron
213+ , ("|", accent '\781' Nothing) -- vertical line above
214+ , ("b", accent '\817' Nothing) -- macron below
215+ , ("c", accent '\807' Nothing) -- cedilla
216+ , ("G", accent '\783' Nothing) -- doublegrave
217+ , ("h", accent '\777' Nothing) -- hookabove
218+ , ("d", accent '\803' Nothing) -- dotbelow
219+ , ("f", accent '\785' Nothing) -- inverted breve
220+ , ("r", accent '\778' Nothing) -- ringabove
221+ , ("t", accent '\865' Nothing) -- double inverted breve
222+ , ("U", accent '\782' Nothing) -- double vertical line above
223+ , ("v", accent '\780' Nothing) -- hacek
224+ , ("u", accent '\774' Nothing) -- breve
225+ , ("k", accent '\808' Nothing) -- ogonek
226+ , ("textogonekcentered", accent '\808' Nothing) -- ogonek
227+ , ("i", lit "ı") -- dotless i
228+ , ("j", lit "ȷ") -- dotless j
229+ , ("newtie", accent '\785' Nothing) -- inverted breve
230+ , ("textcircled", accent '\8413' Nothing) -- combining circle
231+ ]
232+
233+charCommands :: PandocMonad m => M.Map Text (LP m Inlines)
234+charCommands = M.fromList
235+ [ ("ldots", lit "…")
236+ , ("vdots", lit "\8942")
237+ , ("dots", lit "…")
238+ , ("mdots", lit "…")
239+ , ("sim", lit "~")
240+ , ("sep", lit ",")
241+ , ("P", lit "¶")
242+ , ("S", lit "§")
243+ , ("$", lit "$")
244+ , ("%", lit "%")
245+ , ("&", lit "&")
246+ , ("#", lit "#")
247+ , ("_", lit "_")
248+ , ("{", lit "{")
249+ , ("}", lit "}")
250+ , ("qed", lit "\a0\x25FB")
251+ , ("lq", return (str "‘"))
252+ , ("rq", return (str "’"))
253+ , ("textquoteleft", return (str "‘"))
254+ , ("textquoteright", return (str "’"))
255+ , ("textquotedblleft", return (str "“"))
256+ , ("textquotedblright", return (str "”"))
257+ , ("/", pure mempty) -- italic correction
258+ , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState
259+ guard $ not inTableCell
260+ optional rawopt
261+ spaces))
262+ , (",", lit "\8198")
263+ , ("@", pure mempty)
264+ , (" ", lit "\160")
265+ , ("ps", pure $ str "PS." <> space)
266+ , ("TeX", lit "TeX")
267+ , ("LaTeX", lit "LaTeX")
268+ , ("bar", lit "|")
269+ , ("textless", lit "<")
270+ , ("textgreater", lit ">")
271+ , ("textbackslash", lit "\\")
272+ , ("backslash", lit "\\")
273+ , ("slash", lit "/")
274+ -- fontawesome
275+ , ("faCheck", lit "\10003")
276+ , ("faClose", lit "\10007")
277+ -- hyphenat
278+ , ("bshyp", lit "\\\173")
279+ , ("fshyp", lit "/\173")
280+ , ("dothyp", lit ".\173")
281+ , ("colonhyp", lit ":\173")
282+ , ("hyp", lit "-")
283+ ]
284+
285+biblatexInlineCommands :: PandocMonad m
286+ => LP m Inlines -> M.Map Text (LP m Inlines)
287+biblatexInlineCommands tok = M.fromList
288+ -- biblatex misc
289+ [ ("RN", romanNumeralUpper)
290+ , ("Rn", romanNumeralLower)
291+ , ("mkbibquote", spanWith nullAttr . doubleQuoted <$> tok)
292+ , ("mkbibemph", spanWith nullAttr . emph <$> tok)
293+ , ("mkbibitalic", spanWith nullAttr . emph <$> tok)
294+ , ("mkbibbold", spanWith nullAttr . strong <$> tok)
295+ , ("mkbibparens",
296+ spanWith nullAttr . (\x -> str "(" <> x <> str ")") <$> tok)
297+ , ("mkbibbrackets",
298+ spanWith nullAttr . (\x -> str "[" <> x <> str "]") <$> tok)
299+ , ("autocap", spanWith nullAttr <$> tok)
300+ , ("textnormal", spanWith ("",["nodecor"],[]) <$> tok)
301+ , ("bibstring",
302+ (\x -> spanWith ("",[],[("bibstring",x)]) (str x)) . untokenize
303+ <$> braced)
304+ , ("adddot", pure (str "."))
305+ , ("adddotspace", pure (spanWith nullAttr (str "." <> space)))
306+ , ("addabbrvspace", pure space)
307+ , ("hyphen", pure (str "-"))
308+ ]
309+
310+nameCommands :: PandocMonad m => M.Map Text (LP m Inlines)
311+nameCommands = M.fromList
312+ [ ("figurename", doTerm Translations.Figure)
313+ , ("prefacename", doTerm Translations.Preface)
314+ , ("refname", doTerm Translations.References)
315+ , ("bibname", doTerm Translations.Bibliography)
316+ , ("chaptername", doTerm Translations.Chapter)
317+ , ("partname", doTerm Translations.Part)
318+ , ("contentsname", doTerm Translations.Contents)
319+ , ("listfigurename", doTerm Translations.ListOfFigures)
320+ , ("listtablename", doTerm Translations.ListOfTables)
321+ , ("indexname", doTerm Translations.Index)
322+ , ("abstractname", doTerm Translations.Abstract)
323+ , ("tablename", doTerm Translations.Table)
324+ , ("enclname", doTerm Translations.Encl)
325+ , ("ccname", doTerm Translations.Cc)
326+ , ("headtoname", doTerm Translations.To)
327+ , ("pagename", doTerm Translations.Page)
328+ , ("seename", doTerm Translations.See)
329+ , ("seealsoname", doTerm Translations.SeeAlso)
330+ , ("proofname", doTerm Translations.Proof)
331+ , ("glossaryname", doTerm Translations.Glossary)
332+ , ("lstlistingname", doTerm Translations.Listing)
333+ ]
334+
335+refCommands :: PandocMonad m => M.Map Text (LP m Inlines)
336+refCommands = M.fromList
337+ [ ("label", rawInlineOr "label" dolabel)
338+ , ("ref", rawInlineOr "ref" $ doref "ref")
339+ , ("cref", rawInlineOr "cref" $ doref "ref") -- from cleveref.sty
340+ , ("vref", rawInlineOr "vref" $ doref "ref+page") -- from varioref.sty
341+ , ("eqref", rawInlineOr "eqref" $ doref "eqref") -- from amsmath.sty
342+ ]
343+
344+acronymCommands :: PandocMonad m => M.Map Text (LP m Inlines)
345+acronymCommands = M.fromList
346+ -- glossaries package
347+ [ ("gls", doAcronym "short")
348+ , ("Gls", doAcronym "short")
349+ , ("glsdesc", doAcronym "long")
350+ , ("Glsdesc", doAcronym "long")
351+ , ("GLSdesc", doAcronym "long")
352+ , ("acrlong", doAcronym "long")
353+ , ("Acrlong", doAcronym "long")
354+ , ("acrfull", doAcronym "full")
355+ , ("Acrfull", doAcronym "full")
356+ , ("acrshort", doAcronym "abbrv")
357+ , ("Acrshort", doAcronym "abbrv")
358+ , ("glspl", doAcronymPlural "short")
359+ , ("Glspl", doAcronymPlural "short")
360+ , ("glsdescplural", doAcronymPlural "long")
361+ , ("Glsdescplural", doAcronymPlural "long")
362+ , ("GLSdescplural", doAcronymPlural "long")
363+ -- acronyms package
364+ , ("ac", doAcronym "short")
365+ , ("acf", doAcronym "full")
366+ , ("acs", doAcronym "abbrv")
367+ , ("acl", doAcronym "long")
368+ , ("acp", doAcronymPlural "short")
369+ , ("acfp", doAcronymPlural "full")
370+ , ("acsp", doAcronymPlural "abbrv")
371+ , ("aclp", doAcronymPlural "long")
372+ , ("Ac", doAcronym "short")
373+ , ("Acf", doAcronym "full")
374+ , ("Acs", doAcronym "abbrv")
375+ , ("Acl", doAcronym "long")
376+ , ("Acp", doAcronymPlural "short")
377+ , ("Acfp", doAcronymPlural "full")
378+ , ("Acsp", doAcronymPlural "abbrv")
379+ , ("Aclp", doAcronymPlural "long")
380+ ]
381+
382+doAcronym :: PandocMonad m => Text -> LP m Inlines
383+doAcronym form = do
384+ acro <- braced
385+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
386+ ("acronym-form", "singular+" <> form)])
387+ $ str $ untokenize acro]
388+
389+doAcronymPlural :: PandocMonad m => Text -> LP m Inlines
390+doAcronymPlural form = do
391+ acro <- braced
392+ let plural = str "s"
393+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
394+ ("acronym-form", "plural+" <> form)]) $
395+ mconcat [str $ untokenize acro, plural]]
396+
397+
src/Text/Pandoc/Readers/LaTeX/Lang.hs+60−2
@@ -15,15 +15,73 @@ module Text.Pandoc.Readers.LaTeX.Lang
15 ( setDefaultLanguage
15 ( setDefaultLanguage
16 , polyglossiaLangToBCP47
16 , polyglossiaLangToBCP47
17 , babelLangToBCP47
17 , babelLangToBCP47
18+ , enquoteCommands
19+ , inlineLanguageCommands
18 )
20 )
19where
21where
20import qualified Data.Map as M
22import qualified Data.Map as M
23+import Data.Text (Text)
21import qualified Data.Text as T
24import qualified Data.Text as T
25+import Text.Pandoc.Shared (extractSpaces)
22import Text.Pandoc.BCP47 (Lang(..), renderLang)
26import Text.Pandoc.BCP47 (Lang(..), renderLang)
23import Text.Pandoc.Class (PandocMonad(..), setTranslations)
27import Text.Pandoc.Class (PandocMonad(..), setTranslations)
24import Text.Pandoc.Readers.LaTeX.Parsing
28import Text.Pandoc.Readers.LaTeX.Parsing
25−import Text.Pandoc.Parsing (updateState, option)
29+import Text.Pandoc.Parsing (updateState, option, getState, QuoteContext(..),
30+ withQuoteContext)
26−import Text.Pandoc.Builder (Blocks, setMeta, str)
31+import Text.Pandoc.Builder (Blocks, Inlines, setMeta, str, spanWith,
32+ singleQuoted, doubleQuoted)
33+
34+enquote :: PandocMonad m
35+ => LP m Inlines
36+ -> Bool -> Maybe Text -> LP m Inlines
37+enquote tok starred mblang = do
38+ skipopts
39+ let lang = mblang >>= babelLangToBCP47
40+ let langspan = case lang of
41+ Nothing -> id
42+ Just l -> spanWith ("",[],[("lang", renderLang l)])
43+ quoteContext <- sQuoteContext <$> getState
44+ if starred || quoteContext == InDoubleQuote
45+ then singleQuoted . langspan <$> withQuoteContext InSingleQuote tok
46+ else doubleQuoted . langspan <$> withQuoteContext InDoubleQuote tok
47+
48+enquoteCommands :: PandocMonad m
49+ => LP m Inlines -> M.Map Text (LP m Inlines)
50+enquoteCommands tok = M.fromList
51+ [ ("enquote*", enquote tok True Nothing)
52+ , ("enquote", enquote tok False Nothing)
53+ -- foreignquote is supposed to use native quote marks
54+ , ("foreignquote*", braced >>= enquote tok True . Just . untokenize)
55+ , ("foreignquote", braced >>= enquote tok False . Just . untokenize)
56+ -- hypehnquote uses regular quotes
57+ , ("hyphenquote*", braced >>= enquote tok True . Just . untokenize)
58+ , ("hyphenquote", braced >>= enquote tok False . Just . untokenize)
59+ ]
60+
61+foreignlanguage :: PandocMonad m => LP m Inlines -> LP m Inlines
62+foreignlanguage tok = do
63+ babelLang <- untokenize <$> braced
64+ case babelLangToBCP47 babelLang of
65+ Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
66+ _ -> tok
67+
68+inlineLanguageCommands :: PandocMonad m
69+ => LP m Inlines -> M.Map Text (LP m Inlines)
70+inlineLanguageCommands tok =
71+ M.fromList $
72+ ("foreignlanguage", foreignlanguage tok) :
73+ (mk <$> M.toList polyglossiaLangToBCP47)
74+ where
75+ mk (polyglossia, bcp47Func) =
76+ ("text" <> polyglossia, inlineLanguage tok bcp47Func)
77+
78+inlineLanguage :: PandocMonad m
79+ => LP m Inlines -> (Text -> Lang) -> LP m Inlines
80+inlineLanguage tok bcp47Func = do
81+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
82+ <$> rawopt
83+ let lang = renderLang $ bcp47Func o
84+ extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
27
85
28setDefaultLanguage :: PandocMonad m => LP m Blocks
86setDefaultLanguage :: PandocMonad m => LP m Blocks
29setDefaultLanguage = do
87setDefaultLanguage = do
src/Text/Pandoc/Writers/LaTeX.hs+15−551
@@ -18,11 +18,9 @@ module Text.Pandoc.Writers.LaTeX (
18 writeLaTeX
18 writeLaTeX
19 , writeBeamer
19 , writeBeamer
20 ) where
20 ) where
21−import Control.Applicative ((<|>))
22import Control.Monad.State.Strict
21import Control.Monad.State.Strict
23−import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isSpace,
22+import Data.Char (isDigit)
24− isPunctuation, ord)
25−import Data.List (foldl', intersperse, nubBy, (\\), uncons)
23+import Data.List (intersperse, nubBy, (\\))
26import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, isNothing)
24import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, isNothing)
27import qualified Data.Map as M
25import qualified Data.Map as M
28import Data.Text (Text)
26import Data.Text (Text)
@@ -34,7 +32,7 @@ import Text.Pandoc.BCP47 (Lang (..), getLang, renderLang)
34import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
32import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
35import Text.Pandoc.Definition
33import Text.Pandoc.Definition
36import Text.Pandoc.Highlighting (formatLaTeXBlock, formatLaTeXInline, highlight,
34import Text.Pandoc.Highlighting (formatLaTeXBlock, formatLaTeXInline, highlight,
37− styleToLaTeX, toListingsLanguage)
35+ styleToLaTeX)
38import Text.Pandoc.ImageSize
36import Text.Pandoc.ImageSize
39import Text.Pandoc.Logging
37import Text.Pandoc.Logging
40import Text.Pandoc.Options
38import Text.Pandoc.Options
@@ -44,10 +42,15 @@ import Text.Pandoc.Slides
44import Text.Pandoc.Walk (query, walk, walkM)
42import Text.Pandoc.Walk (query, walk, walkM)
45import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
43import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
46import Text.Pandoc.Writers.LaTeX.Table (tableToLaTeX)
44import Text.Pandoc.Writers.LaTeX.Table (tableToLaTeX)
45+import Text.Pandoc.Writers.LaTeX.Citation (citationsToNatbib,
46+ citationsToBiblatex)
47import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState (..), startingState)
47import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState (..), startingState)
48+import Text.Pandoc.Writers.LaTeX.Lang (toPolyglossia, toBabel)
49+import Text.Pandoc.Writers.LaTeX.Util (stringToLaTeX, StringContext(..),
50+ toLabel, inCmd,
51+ wrapDiv, hypertarget, labelFor,
52+ getListingsLanguage, mbBraced)
48import Text.Pandoc.Writers.Shared
53import Text.Pandoc.Writers.Shared
49−import Text.Printf (printf)
50−import qualified Data.Text.Normalize as Normalize
51import qualified Text.Pandoc.Writers.AnnotatedTable as Ann
54import qualified Text.Pandoc.Writers.AnnotatedTable as Ann
52
55
53-- | Convert Pandoc to LaTeX.
56-- | Convert Pandoc to LaTeX.
@@ -241,152 +244,6 @@ pandocToLaTeX options (Pandoc meta blocks) = do
241 Nothing -> main
244 Nothing -> main
242 Just tpl -> renderTemplate tpl context'
245 Just tpl -> renderTemplate tpl context'
243
246
244−data StringContext = TextString
245− | URLString
246− | CodeString
247− deriving (Eq)
248−
249−-- escape things as needed for LaTeX
250−stringToLaTeX :: PandocMonad m => StringContext -> Text -> LW m Text
251−stringToLaTeX context zs = do
252− opts <- gets stOptions
253− return $ T.pack $
254− foldr (go opts context) mempty $ T.unpack $
255− if writerPreferAscii opts
256− then Normalize.normalize Normalize.NFD zs
257− else zs
258− where
259− go :: WriterOptions -> StringContext -> Char -> String -> String
260− go opts ctx x xs =
261− let ligatures = isEnabled Ext_smart opts && ctx == TextString
262− isUrl = ctx == URLString
263− mbAccentCmd =
264− if writerPreferAscii opts && ctx == TextString
265− then uncons xs >>= \(c,_) -> lookupAccent c
266− else Nothing
267− emits s =
268− case mbAccentCmd of
269− Just cmd ->
270− cmd <> "{" <> s <> "}" <> drop 1 xs -- drop combining accent
271− Nothing -> s <> xs
272− emitc c =
273− case mbAccentCmd of
274− Just cmd ->
275− cmd <> "{" <> [c] <> "}" <> drop 1 xs -- drop combining accent
276− Nothing -> c : xs
277− emitcseq cs =
278− case xs of
279− c:_ | isLetter c
280− , ctx == TextString
281− -> cs <> " " <> xs
282− | isSpace c -> cs <> "{}" <> xs
283− | ctx == TextString
284− -> cs <> xs
285− _ -> cs <> "{}" <> xs
286− emitquote cs =
287− case xs of
288− '`':_ -> cs <> "\\," <> xs -- add thin space
289− '\'':_ -> cs <> "\\," <> xs -- add thin space
290− _ -> cs <> xs
291− in case x of
292− '?' | ligatures -> -- avoid ?` ligature
293− case xs of
294− '`':_ -> emits "?{}"
295− _ -> emitc x
296− '!' | ligatures -> -- avoid !` ligature
297− case xs of
298− '`':_ -> emits "!{}"
299− _ -> emitc x
300− '{' -> emits "\\{"
301− '}' -> emits "\\}"
302− '`' | ctx == CodeString -> emitcseq "\\textasciigrave"
303− '$' | not isUrl -> emits "\\$"
304− '%' -> emits "\\%"
305− '&' -> emits "\\&"
306− '_' | not isUrl -> emits "\\_"
307− '#' -> emits "\\#"
308− '-' | not isUrl -> case xs of
309− -- prevent adjacent hyphens from forming ligatures
310− ('-':_) -> emits "-\\/"
311− _ -> emitc '-'
312− '~' | not isUrl -> emitcseq "\\textasciitilde"
313− '^' -> emits "\\^{}"
314− '\\'| isUrl -> emitc '/' -- NB. / works as path sep even on Windows
315− | otherwise -> emitcseq "\\textbackslash"
316− '|' | not isUrl -> emitcseq "\\textbar"
317− '<' -> emitcseq "\\textless"
318− '>' -> emitcseq "\\textgreater"
319− '[' -> emits "{[}" -- to avoid interpretation as
320− ']' -> emits "{]}" -- optional arguments
321− '\'' | ctx == CodeString -> emitcseq "\\textquotesingle"
322− '\160' -> emits "~"
323− '\x200B' -> emits "\\hspace{0pt}" -- zero-width space
324− '\x202F' -> emits "\\,"
325− '\x2026' -> emitcseq "\\ldots"
326− '\x2018' | ligatures -> emitquote "`"
327− '\x2019' | ligatures -> emitquote "'"
328− '\x201C' | ligatures -> emitquote "``"
329− '\x201D' | ligatures -> emitquote "''"
330− '\x2014' | ligatures -> emits "---"
331− '\x2013' | ligatures -> emits "--"
332− _ | writerPreferAscii opts
333− -> case x of
334− 'ı' -> emitcseq "\\i"
335− 'ȷ' -> emitcseq "\\j"
336− 'å' -> emitcseq "\\aa"
337− 'Å' -> emitcseq "\\AA"
338− 'ß' -> emitcseq "\\ss"
339− 'ø' -> emitcseq "\\o"
340− 'Ø' -> emitcseq "\\O"
341− 'Ł' -> emitcseq "\\L"
342− 'ł' -> emitcseq "\\l"
343− 'æ' -> emitcseq "\\ae"
344− 'Æ' -> emitcseq "\\AE"
345− 'œ' -> emitcseq "\\oe"
346− 'Œ' -> emitcseq "\\OE"
347− '£' -> emitcseq "\\pounds"
348− '€' -> emitcseq "\\euro"
349− '©' -> emitcseq "\\copyright"
350− _ -> emitc x
351− | otherwise -> emitc x
352−
353−lookupAccent :: Char -> Maybe String
354−lookupAccent '\779' = Just "\\H"
355−lookupAccent '\768' = Just "\\`"
356−lookupAccent '\769' = Just "\\'"
357−lookupAccent '\770' = Just "\\^"
358−lookupAccent '\771' = Just "\\~"
359−lookupAccent '\776' = Just "\\\""
360−lookupAccent '\775' = Just "\\."
361−lookupAccent '\772' = Just "\\="
362−lookupAccent '\781' = Just "\\|"
363−lookupAccent '\817' = Just "\\b"
364−lookupAccent '\807' = Just "\\c"
365−lookupAccent '\783' = Just "\\G"
366−lookupAccent '\777' = Just "\\h"
367−lookupAccent '\803' = Just "\\d"
368−lookupAccent '\785' = Just "\\f"
369−lookupAccent '\778' = Just "\\r"
370−lookupAccent '\865' = Just "\\t"
371−lookupAccent '\782' = Just "\\U"
372−lookupAccent '\780' = Just "\\v"
373−lookupAccent '\774' = Just "\\u"
374−lookupAccent '\808' = Just "\\k"
375−lookupAccent '\8413' = Just "\\textcircled"
376−lookupAccent _ = Nothing
377−
378−toLabel :: PandocMonad m => Text -> LW m Text
379−toLabel z = go `fmap` stringToLaTeX URLString z
380− where
381− go = T.concatMap $ \x -> case x of
382− _ | (isLetter x || isDigit x) && isAscii x -> T.singleton x
383− | x `elemText` "_-+=:;." -> T.singleton x
384− | otherwise -> T.pack $ "ux" <> printf "%x" (ord x)
385−
386−-- | Puts contents into LaTeX command.
387−inCmd :: Text -> Doc Text -> Doc Text
388−inCmd cmd contents = char '\\' <> literal cmd <> braces contents
389−
390toSlides :: PandocMonad m => [Block] -> LW m [Block]
247toSlides :: PandocMonad m => [Block] -> LW m [Block]
391toSlides bs = do
248toSlides bs = do
392 opts <- gets stOptions
249 opts <- gets stOptions
@@ -851,81 +708,6 @@ sectionHeader classes ident level lst = do
851 braces txtNoNotes
708 braces txtNoNotes
852 else empty
709 else empty
853
710
854−mapAlignment :: Text -> Text
855−mapAlignment a = case a of
856− "top" -> "T"
857− "top-baseline" -> "t"
858− "bottom" -> "b"
859− "center" -> "c"
860− _ -> a
861−
862−wrapDiv :: PandocMonad m => Attr -> Doc Text -> LW m (Doc Text)
863−wrapDiv (_,classes,kvs) t = do
864− beamer <- gets stBeamer
865− let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
866− lang <- toLang $ lookup "lang" kvs
867− let wrapColumns = if beamer && "columns" `elem` classes
868− then \contents ->
869− let valign = maybe "T" mapAlignment (lookup "align" kvs)
870− totalwidth = maybe [] (\x -> ["totalwidth=" <> x])
871− (lookup "totalwidth" kvs)
872− onlytextwidth = filter ("onlytextwidth" ==) classes
873− options = text $ T.unpack $ T.intercalate "," $
874− valign : totalwidth ++ onlytextwidth
875− in inCmd "begin" "columns" <> brackets options
876− $$ contents
877− $$ inCmd "end" "columns"
878− else id
879− wrapColumn = if beamer && "column" `elem` classes
880− then \contents ->
881− let valign =
882− maybe ""
883− (brackets . text . T.unpack . mapAlignment)
884− (lookup "align" kvs)
885− w = maybe "0.48" fromPct (lookup "width" kvs)
886− in inCmd "begin" "column" <>
887− valign <>
888− braces (literal w <> "\\textwidth")
889− $$ contents
890− $$ inCmd "end" "column"
891− else id
892− fromPct xs =
893− case T.unsnoc xs of
894− Just (ds, '%') -> case safeRead ds of
895− Just digits -> showFl (digits / 100 :: Double)
896− Nothing -> xs
897− _ -> xs
898− wrapDir = case lookup "dir" kvs of
899− Just "rtl" -> align "RTL"
900− Just "ltr" -> align "LTR"
901− _ -> id
902− wrapLang txt = case lang of
903− Just lng -> let (l, o) = toPolyglossiaEnv lng
904− ops = if T.null o
905− then ""
906− else brackets $ literal o
907− in inCmd "begin" (literal l) <> ops
908− $$ blankline <> txt <> blankline
909− $$ inCmd "end" (literal l)
910− Nothing -> txt
911− return $ wrapColumns . wrapColumn . wrapDir . wrapLang $ t
912−
913−hypertarget :: PandocMonad m => Bool -> Text -> Doc Text -> LW m (Doc Text)
914−hypertarget _ "" x = return x
915−hypertarget addnewline ident x = do
916− ref <- literal `fmap` toLabel ident
917− return $ text "\\hypertarget"
918− <> braces ref
919− <> braces ((if addnewline && not (isEmpty x)
920− then "%" <> cr
921− else empty) <> x)
922−
923−labelFor :: PandocMonad m => Text -> LW m (Doc Text)
924−labelFor "" = return empty
925−labelFor ident = do
926− ref <- literal `fmap` toLabel ident
927− return $ text "\\label" <> braces ref
928−
929-- | Convert list of inline elements to LaTeX.
711-- | Convert list of inline elements to LaTeX.
930inlineListToLaTeX :: PandocMonad m
712inlineListToLaTeX :: PandocMonad m
931 => [Inline] -- ^ Inlines to convert
713 => [Inline] -- ^ Inlines to convert
@@ -950,10 +732,6 @@ inlineListToLaTeX lst = hcat <$>
950 fixInitialLineBreaks xs
732 fixInitialLineBreaks xs
951 fixInitialLineBreaks xs = xs
733 fixInitialLineBreaks xs = xs
952
734
953−isQuoted :: Inline -> Bool
954−isQuoted (Quoted _ _) = True
955−isQuoted _ = False
956−
957-- | Convert inline element to LaTeX
735-- | Convert inline element to LaTeX
958inlineToLaTeX :: PandocMonad m
736inlineToLaTeX :: PandocMonad m
959 => Inline -- ^ Inline to convert
737 => Inline -- ^ Inline to convert
@@ -1014,8 +792,8 @@ inlineToLaTeX (Cite cits lst) = do
1014 st <- get
792 st <- get
1015 let opts = stOptions st
793 let opts = stOptions st
1016 case writerCiteMethod opts of
794 case writerCiteMethod opts of
1017− Natbib -> citationsToNatbib cits
795+ Natbib -> citationsToNatbib inlineListToLaTeX cits
1018− Biblatex -> citationsToBiblatex cits
796+ Biblatex -> citationsToBiblatex inlineListToLaTeX cits
1019 _ -> inlineListToLaTeX lst
797 _ -> inlineListToLaTeX lst
1020
798
1021inlineToLaTeX (Code (_,classes,kvs) str) = do
799inlineToLaTeX (Code (_,classes,kvs) str) = do
@@ -1089,6 +867,9 @@ inlineToLaTeX (Quoted qt lst) = do
1089 if isEnabled Ext_smart opts
867 if isEnabled Ext_smart opts
1090 then char '`' <> inner <> char '\''
868 then char '`' <> inner <> char '\''
1091 else char '\x2018' <> inner <> char '\x2019'
869 else char '\x2018' <> inner <> char '\x2019'
870+ where
871+ isQuoted (Quoted _ _) = True
872+ isQuoted _ = False
1092inlineToLaTeX (Str str) = do
873inlineToLaTeX (Str str) = do
1093 setEmptyLine False
874 setEmptyLine False
1094 liftM literal $ stringToLaTeX TextString str
875 liftM literal $ stringToLaTeX TextString str
@@ -1226,153 +1007,6 @@ protectCode x = [x]
1226setEmptyLine :: PandocMonad m => Bool -> LW m ()
1007setEmptyLine :: PandocMonad m => Bool -> LW m ()
1227setEmptyLine b = modify $ \st -> st{ stEmptyLine = b }
1008setEmptyLine b = modify $ \st -> st{ stEmptyLine = b }
1228
1009
1229−citationsToNatbib :: PandocMonad m => [Citation] -> LW m (Doc Text)
1230−citationsToNatbib
1231− [one]
1232− = citeCommand c p s k
1233− where
1234− Citation { citationId = k
1235− , citationPrefix = p
1236− , citationSuffix = s
1237− , citationMode = m
1238− }
1239− = one
1240− c = case m of
1241− AuthorInText -> "citet"
1242− SuppressAuthor -> "citeyearpar"
1243− NormalCitation -> "citep"
1244−
1245−citationsToNatbib cits
1246− | noPrefix (tail cits) && noSuffix (init cits) && ismode NormalCitation cits
1247− = citeCommand "citep" p s ks
1248− where
1249− noPrefix = all (null . citationPrefix)
1250− noSuffix = all (null . citationSuffix)
1251− ismode m = all ((==) m . citationMode)
1252− p = citationPrefix $
1253− head cits
1254− s = citationSuffix $
1255− last cits
1256− ks = T.intercalate ", " $ map citationId cits
1257−
1258−citationsToNatbib (c:cs) | citationMode c == AuthorInText = do
1259− author <- citeCommand "citeauthor" [] [] (citationId c)
1260− cits <- citationsToNatbib (c { citationMode = SuppressAuthor } : cs)
1261− return $ author <+> cits
1262−
1263−citationsToNatbib cits = do
1264− cits' <- mapM convertOne cits
1265− return $ text "\\citetext{" <> foldl' combineTwo empty cits' <> text "}"
1266− where
1267− combineTwo a b | isEmpty a = b
1268− | otherwise = a <> text "; " <> b
1269− convertOne Citation { citationId = k
1270− , citationPrefix = p
1271− , citationSuffix = s
1272− , citationMode = m
1273− }
1274− = case m of
1275− AuthorInText -> citeCommand "citealt" p s k
1276− SuppressAuthor -> citeCommand "citeyear" p s k
1277− NormalCitation -> citeCommand "citealp" p s k
1278−
1279−citeCommand :: PandocMonad m
1280− => Text -> [Inline] -> [Inline] -> Text -> LW m (Doc Text)
1281−citeCommand c p s k = do
1282− args <- citeArguments p s k
1283− return $ literal ("\\" <> c) <> args
1284−
1285−type Prefix = [Inline]
1286−type Suffix = [Inline]
1287−type CiteId = Text
1288−data CiteGroup = CiteGroup Prefix Suffix [CiteId]
1289−
1290−citeArgumentsList :: PandocMonad m
1291− => CiteGroup -> LW m (Doc Text)
1292−citeArgumentsList (CiteGroup _ _ []) = return empty
1293−citeArgumentsList (CiteGroup pfxs sfxs ids) = do
1294− pdoc <- inlineListToLaTeX pfxs
1295− sdoc <- inlineListToLaTeX sfxs'
1296− return $ optargs pdoc sdoc <>
1297− braces (literal (T.intercalate "," (reverse ids)))
1298− where sfxs' = stripLocatorBraces $ case sfxs of
1299− (Str t : r) -> case T.uncons t of
1300− Just (x, xs)
1301− | T.null xs
1302− , isPunctuation x -> dropWhile (== Space) r
1303− | isPunctuation x -> Str xs : r
1304− _ -> sfxs
1305− _ -> sfxs
1306− optargs pdoc sdoc = case (isEmpty pdoc, isEmpty sdoc) of
1307− (True, True ) -> empty
1308− (True, False) -> brackets sdoc
1309− (_ , _ ) -> brackets pdoc <> brackets sdoc
1310−
1311−citeArguments :: PandocMonad m
1312− => [Inline] -> [Inline] -> Text -> LW m (Doc Text)
1313−citeArguments p s k = citeArgumentsList (CiteGroup p s [k])
1314−
1315−-- strip off {} used to define locator in pandoc-citeproc; see #5722
1316−stripLocatorBraces :: [Inline] -> [Inline]
1317−stripLocatorBraces = walk go
1318− where go (Str xs) = Str $ T.filter (\c -> c /= '{' && c /= '}') xs
1319− go x = x
1320−
1321−citationsToBiblatex :: PandocMonad m => [Citation] -> LW m (Doc Text)
1322−citationsToBiblatex
1323− [one]
1324− = citeCommand cmd p s k
1325− where
1326− Citation { citationId = k
1327− , citationPrefix = p
1328− , citationSuffix = s
1329− , citationMode = m
1330− } = one
1331− cmd = case m of
1332− SuppressAuthor -> "autocite*"
1333− AuthorInText -> "textcite"
1334− NormalCitation -> "autocite"
1335−
1336−citationsToBiblatex (c:cs)
1337− | all (\cit -> null (citationPrefix cit) && null (citationSuffix cit)) (c:cs)
1338− = do
1339− let cmd = case citationMode c of
1340− SuppressAuthor -> "\\autocite*"
1341− AuthorInText -> "\\textcite"
1342− NormalCitation -> "\\autocite"
1343− return $ text cmd <>
1344− braces (literal (T.intercalate "," (map citationId (c:cs))))
1345− | otherwise
1346− = do
1347− let cmd = case citationMode c of
1348− SuppressAuthor -> "\\autocites*"
1349− AuthorInText -> "\\textcites"
1350− NormalCitation -> "\\autocites"
1351−
1352− groups <- mapM citeArgumentsList (reverse (foldl' grouper [] (c:cs)))
1353−
1354− return $ text cmd <> mconcat groups
1355−
1356− where grouper prev cit = case prev of
1357− ((CiteGroup oPfx oSfx ids):rest)
1358− | null oSfx && null pfx -> CiteGroup oPfx sfx (cid:ids) : rest
1359− _ -> CiteGroup pfx sfx [cid] : prev
1360− where pfx = citationPrefix cit
1361− sfx = citationSuffix cit
1362− cid = citationId cit
1363−
1364−citationsToBiblatex _ = return empty
1365−
1366−-- Determine listings language from list of class attributes.
1367−getListingsLanguage :: [Text] -> Maybe Text
1368−getListingsLanguage xs
1369− = foldr ((<|>) . toListingsLanguage) Nothing xs
1370−
1371−mbBraced :: Text -> Text
1372−mbBraced x = if not (T.all isAlphaNum x)
1373− then "{" <> x <> "}"
1374− else x
1375−
1376-- Extract a key from divs and spans
1010-- Extract a key from divs and spans
1377extract :: Text -> Block -> [Text]
1011extract :: Text -> Block -> [Text]
1378extract key (Div attr _) = lookKey key attr
1012extract key (Div attr _) = lookKey key attr
@@ -1390,174 +1024,4 @@ extractInline _ _ = []
1390lookKey :: Text -> Attr -> [Text]
1024lookKey :: Text -> Attr -> [Text]
1391lookKey key (_,_,kvs) = maybe [] T.words $ lookup key kvs
1025lookKey key (_,_,kvs) = maybe [] T.words $ lookup key kvs
1392
1026
1393−-- In environments \Arabic instead of \arabic is used
1394−toPolyglossiaEnv :: Lang -> (Text, Text)
1395−toPolyglossiaEnv l =
1396− case toPolyglossia l of
1397− ("arabic", o) -> ("Arabic", o)
1398− x -> x
1399−
1400−-- Takes a list of the constituents of a BCP 47 language code and
1401−-- converts it to a Polyglossia (language, options) tuple
1402−-- http://mirrors.ctan.org/macros/latex/contrib/polyglossia/polyglossia.pdf
1403−toPolyglossia :: Lang -> (Text, Text)
1404−toPolyglossia (Lang "ar" _ "DZ" _) = ("arabic", "locale=algeria")
1405−toPolyglossia (Lang "ar" _ "IQ" _) = ("arabic", "locale=mashriq")
1406−toPolyglossia (Lang "ar" _ "JO" _) = ("arabic", "locale=mashriq")
1407−toPolyglossia (Lang "ar" _ "LB" _) = ("arabic", "locale=mashriq")
1408−toPolyglossia (Lang "ar" _ "LY" _) = ("arabic", "locale=libya")
1409−toPolyglossia (Lang "ar" _ "MA" _) = ("arabic", "locale=morocco")
1410−toPolyglossia (Lang "ar" _ "MR" _) = ("arabic", "locale=mauritania")
1411−toPolyglossia (Lang "ar" _ "PS" _) = ("arabic", "locale=mashriq")
1412−toPolyglossia (Lang "ar" _ "SY" _) = ("arabic", "locale=mashriq")
1413−toPolyglossia (Lang "ar" _ "TN" _) = ("arabic", "locale=tunisia")
1414−toPolyglossia (Lang "de" _ _ vars)
1415− | "1901" `elem` vars = ("german", "spelling=old")
1416−toPolyglossia (Lang "de" _ "AT" vars)
1417− | "1901" `elem` vars = ("german", "variant=austrian, spelling=old")
1418−toPolyglossia (Lang "de" _ "AT" _) = ("german", "variant=austrian")
1419−toPolyglossia (Lang "de" _ "CH" vars)
1420− | "1901" `elem` vars = ("german", "variant=swiss, spelling=old")
1421−toPolyglossia (Lang "de" _ "CH" _) = ("german", "variant=swiss")
1422−toPolyglossia (Lang "de" _ _ _) = ("german", "")
1423−toPolyglossia (Lang "dsb" _ _ _) = ("lsorbian", "")
1424−toPolyglossia (Lang "el" _ "polyton" _) = ("greek", "variant=poly")
1425−toPolyglossia (Lang "en" _ "AU" _) = ("english", "variant=australian")
1426−toPolyglossia (Lang "en" _ "CA" _) = ("english", "variant=canadian")
1427−toPolyglossia (Lang "en" _ "GB" _) = ("english", "variant=british")
1428−toPolyglossia (Lang "en" _ "NZ" _) = ("english", "variant=newzealand")
1429−toPolyglossia (Lang "en" _ "UK" _) = ("english", "variant=british")
1430−toPolyglossia (Lang "en" _ "US" _) = ("english", "variant=american")
1431−toPolyglossia (Lang "grc" _ _ _) = ("greek", "variant=ancient")
1432−toPolyglossia (Lang "hsb" _ _ _) = ("usorbian", "")
1433−toPolyglossia (Lang "la" _ _ vars)
1434− | "x-classic" `elem` vars = ("latin", "variant=classic")
1435−toPolyglossia (Lang "pt" _ "BR" _) = ("portuguese", "variant=brazilian")
1436−toPolyglossia (Lang "sl" _ _ _) = ("slovenian", "")
1437−toPolyglossia x = (commonFromBcp47 x, "")
1438
1027
1439−-- Takes a list of the constituents of a BCP 47 language code and
1440−-- converts it to a Babel language string.
1441−-- http://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf
1442−-- List of supported languages (slightly outdated):
1443−-- http://tug.ctan.org/language/hyph-utf8/doc/generic/hyph-utf8/hyphenation.pdf
1444−toBabel :: Lang -> Text
1445−toBabel (Lang "de" _ "AT" vars)
1446− | "1901" `elem` vars = "austrian"
1447− | otherwise = "naustrian"
1448−toBabel (Lang "de" _ "CH" vars)
1449− | "1901" `elem` vars = "swissgerman"
1450− | otherwise = "nswissgerman"
1451−toBabel (Lang "de" _ _ vars)
1452− | "1901" `elem` vars = "german"
1453− | otherwise = "ngerman"
1454−toBabel (Lang "dsb" _ _ _) = "lowersorbian"
1455−toBabel (Lang "el" _ _ vars)
1456− | "polyton" `elem` vars = "polutonikogreek"
1457−toBabel (Lang "en" _ "AU" _) = "australian"
1458−toBabel (Lang "en" _ "CA" _) = "canadian"
1459−toBabel (Lang "en" _ "GB" _) = "british"
1460−toBabel (Lang "en" _ "NZ" _) = "newzealand"
1461−toBabel (Lang "en" _ "UK" _) = "british"
1462−toBabel (Lang "en" _ "US" _) = "american"
1463−toBabel (Lang "fr" _ "CA" _) = "canadien"
1464−toBabel (Lang "fra" _ _ vars)
1465− | "aca" `elem` vars = "acadian"
1466−toBabel (Lang "grc" _ _ _) = "polutonikogreek"
1467−toBabel (Lang "hsb" _ _ _) = "uppersorbian"
1468−toBabel (Lang "la" _ _ vars)
1469− | "x-classic" `elem` vars = "classiclatin"
1470−toBabel (Lang "pt" _ "BR" _) = "brazilian"
1471−toBabel (Lang "sl" _ _ _) = "slovene"
1472−toBabel x = commonFromBcp47 x
1473−
1474−-- Takes a list of the constituents of a BCP 47 language code
1475−-- and converts it to a string shared by Babel and Polyglossia.
1476−-- https://tools.ietf.org/html/bcp47#section-2.1
1477−commonFromBcp47 :: Lang -> Text
1478−commonFromBcp47 (Lang "sr" "Cyrl" _ _) = "serbianc"
1479−commonFromBcp47 (Lang "zh" "Latn" _ vars)
1480− | "pinyin" `elem` vars = "pinyin"
1481−commonFromBcp47 (Lang l _ _ _) = fromIso l
1482− where
1483− fromIso "af" = "afrikaans"
1484− fromIso "am" = "amharic"
1485− fromIso "ar" = "arabic"
1486− fromIso "as" = "assamese"
1487− fromIso "ast" = "asturian"
1488− fromIso "bg" = "bulgarian"
1489− fromIso "bn" = "bengali"
1490− fromIso "bo" = "tibetan"
1491− fromIso "br" = "breton"
1492− fromIso "ca" = "catalan"
1493− fromIso "cy" = "welsh"
1494− fromIso "cs" = "czech"
1495− fromIso "cop" = "coptic"
1496− fromIso "da" = "danish"
1497− fromIso "dv" = "divehi"
1498− fromIso "el" = "greek"
1499− fromIso "en" = "english"
1500− fromIso "eo" = "esperanto"
1501− fromIso "es" = "spanish"
1502− fromIso "et" = "estonian"
1503− fromIso "eu" = "basque"
1504− fromIso "fa" = "farsi"
1505− fromIso "fi" = "finnish"
1506− fromIso "fr" = "french"
1507− fromIso "fur" = "friulan"
1508− fromIso "ga" = "irish"
1509− fromIso "gd" = "scottish"
1510− fromIso "gez" = "ethiopic"
1511− fromIso "gl" = "galician"
1512− fromIso "he" = "hebrew"
1513− fromIso "hi" = "hindi"
1514− fromIso "hr" = "croatian"
1515− fromIso "hu" = "magyar"
1516− fromIso "hy" = "armenian"
1517− fromIso "ia" = "interlingua"
1518− fromIso "id" = "indonesian"
1519− fromIso "ie" = "interlingua"
1520− fromIso "is" = "icelandic"
1521− fromIso "it" = "italian"
1522− fromIso "ja" = "japanese"
1523− fromIso "km" = "khmer"
1524− fromIso "kmr" = "kurmanji"
1525− fromIso "kn" = "kannada"
1526− fromIso "ko" = "korean"
1527− fromIso "la" = "latin"
1528− fromIso "lo" = "lao"
1529− fromIso "lt" = "lithuanian"
1530− fromIso "lv" = "latvian"
1531− fromIso "ml" = "malayalam"
1532− fromIso "mn" = "mongolian"
1533− fromIso "mr" = "marathi"
1534− fromIso "nb" = "norsk"
1535− fromIso "nl" = "dutch"
1536− fromIso "nn" = "nynorsk"
1537− fromIso "no" = "norsk"
1538− fromIso "nqo" = "nko"
1539− fromIso "oc" = "occitan"
1540− fromIso "pa" = "panjabi"
1541− fromIso "pl" = "polish"
1542− fromIso "pms" = "piedmontese"
1543− fromIso "pt" = "portuguese"
1544− fromIso "rm" = "romansh"
1545− fromIso "ro" = "romanian"
1546− fromIso "ru" = "russian"
1547− fromIso "sa" = "sanskrit"
1548− fromIso "se" = "samin"
1549− fromIso "sk" = "slovak"
1550− fromIso "sq" = "albanian"
1551− fromIso "sr" = "serbian"
1552− fromIso "sv" = "swedish"
1553− fromIso "syr" = "syriac"
1554− fromIso "ta" = "tamil"
1555− fromIso "te" = "telugu"
1556− fromIso "th" = "thai"
1557− fromIso "ti" = "ethiopic"
1558− fromIso "tk" = "turkmen"
1559− fromIso "tr" = "turkish"
1560− fromIso "uk" = "ukrainian"
1561− fromIso "ur" = "urdu"
1562− fromIso "vi" = "vietnamese"
1563− fromIso _ = ""
src/Text/Pandoc/Writers/LaTeX/Citation.hsnew file+181
@@ -0,0 +1,181 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{- |
3+ Module : Text.Pandoc.Writers.LaTeX.Citation
4+ Copyright : Copyright (C) 2006-2021 John MacFarlane
5+ License : GNU GPL, version 2 or above
6+
7+ Maintainer : John MacFarlane <jgm@berkeley.edu>
8+ Stability : alpha
9+ Portability : portable
10+-}
11+module Text.Pandoc.Writers.LaTeX.Citation
12+ ( citationsToNatbib,
13+ citationsToBiblatex
14+ ) where
15+
16+import Data.Text (Text)
17+import Data.Char (isPunctuation)
18+import qualified Data.Text as T
19+import Text.Pandoc.Class.PandocMonad (PandocMonad)
20+import Text.Pandoc.Definition
21+import Data.List (foldl')
22+import Text.DocLayout (Doc, brackets, empty, (<+>), text, isEmpty, literal,
23+ braces)
24+import Text.Pandoc.Walk
25+import Text.Pandoc.Writers.LaTeX.Types ( LW )
26+
27+citationsToNatbib :: PandocMonad m
28+ => ([Inline] -> LW m (Doc Text))
29+ -> [Citation]
30+ -> LW m (Doc Text)
31+citationsToNatbib inlineListToLaTeX [one]
32+ = citeCommand inlineListToLaTeX c p s k
33+ where
34+ Citation { citationId = k
35+ , citationPrefix = p
36+ , citationSuffix = s
37+ , citationMode = m
38+ }
39+ = one
40+ c = case m of
41+ AuthorInText -> "citet"
42+ SuppressAuthor -> "citeyearpar"
43+ NormalCitation -> "citep"
44+
45+citationsToNatbib inlineListToLaTeX cits
46+ | noPrefix (tail cits) && noSuffix (init cits) && ismode NormalCitation cits
47+ = citeCommand inlineListToLaTeX "citep" p s ks
48+ where
49+ noPrefix = all (null . citationPrefix)
50+ noSuffix = all (null . citationSuffix)
51+ ismode m = all ((==) m . citationMode)
52+ p = citationPrefix $
53+ head cits
54+ s = citationSuffix $
55+ last cits
56+ ks = T.intercalate ", " $ map citationId cits
57+
58+citationsToNatbib inlineListToLaTeX (c:cs)
59+ | citationMode c == AuthorInText = do
60+ author <- citeCommand inlineListToLaTeX "citeauthor" [] [] (citationId c)
61+ cits <- citationsToNatbib inlineListToLaTeX
62+ (c { citationMode = SuppressAuthor } : cs)
63+ return $ author <+> cits
64+
65+citationsToNatbib inlineListToLaTeX cits = do
66+ cits' <- mapM convertOne cits
67+ return $ text "\\citetext{" <> foldl' combineTwo empty cits' <> text "}"
68+ where
69+ citeCommand' = citeCommand inlineListToLaTeX
70+ combineTwo a b | isEmpty a = b
71+ | otherwise = a <> text "; " <> b
72+ convertOne Citation { citationId = k
73+ , citationPrefix = p
74+ , citationSuffix = s
75+ , citationMode = m
76+ }
77+ = case m of
78+ AuthorInText -> citeCommand' "citealt" p s k
79+ SuppressAuthor -> citeCommand' "citeyear" p s k
80+ NormalCitation -> citeCommand' "citealp" p s k
81+
82+citeCommand :: PandocMonad m
83+ => ([Inline] -> LW m (Doc Text))
84+ -> Text
85+ -> [Inline]
86+ -> [Inline]
87+ -> Text
88+ -> LW m (Doc Text)
89+citeCommand inlineListToLaTeX c p s k = do
90+ args <- citeArguments inlineListToLaTeX p s k
91+ return $ literal ("\\" <> c) <> args
92+
93+type Prefix = [Inline]
94+type Suffix = [Inline]
95+type CiteId = Text
96+data CiteGroup = CiteGroup Prefix Suffix [CiteId]
97+
98+citeArgumentsList :: PandocMonad m
99+ => ([Inline] -> LW m (Doc Text))
100+ -> CiteGroup
101+ -> LW m (Doc Text)
102+citeArgumentsList _inlineListToLaTeX (CiteGroup _ _ []) = return empty
103+citeArgumentsList inlineListToLaTeX (CiteGroup pfxs sfxs ids) = do
104+ pdoc <- inlineListToLaTeX pfxs
105+ sdoc <- inlineListToLaTeX sfxs'
106+ return $ optargs pdoc sdoc <>
107+ braces (literal (T.intercalate "," (reverse ids)))
108+ where sfxs' = stripLocatorBraces $ case sfxs of
109+ (Str t : r) -> case T.uncons t of
110+ Just (x, xs)
111+ | T.null xs
112+ , isPunctuation x -> dropWhile (== Space) r
113+ | isPunctuation x -> Str xs : r
114+ _ -> sfxs
115+ _ -> sfxs
116+ optargs pdoc sdoc = case (isEmpty pdoc, isEmpty sdoc) of
117+ (True, True ) -> empty
118+ (True, False) -> brackets sdoc
119+ (_ , _ ) -> brackets pdoc <> brackets sdoc
120+
121+citeArguments :: PandocMonad m
122+ => ([Inline] -> LW m (Doc Text))
123+ -> [Inline]
124+ -> [Inline]
125+ -> Text
126+ -> LW m (Doc Text)
127+citeArguments inlineListToLaTeX p s k =
128+ citeArgumentsList inlineListToLaTeX (CiteGroup p s [k])
129+
130+-- strip off {} used to define locator in pandoc-citeproc; see #5722
131+stripLocatorBraces :: [Inline] -> [Inline]
132+stripLocatorBraces = walk go
133+ where go (Str xs) = Str $ T.filter (\c -> c /= '{' && c /= '}') xs
134+ go x = x
135+
136+citationsToBiblatex :: PandocMonad m
137+ => ([Inline] -> LW m (Doc Text))
138+ -> [Citation] -> LW m (Doc Text)
139+citationsToBiblatex inlineListToLaTeX [one]
140+ = citeCommand inlineListToLaTeX cmd p s k
141+ where
142+ Citation { citationId = k
143+ , citationPrefix = p
144+ , citationSuffix = s
145+ , citationMode = m
146+ } = one
147+ cmd = case m of
148+ SuppressAuthor -> "autocite*"
149+ AuthorInText -> "textcite"
150+ NormalCitation -> "autocite"
151+
152+citationsToBiblatex inlineListToLaTeX (c:cs)
153+ | all (\cit -> null (citationPrefix cit) && null (citationSuffix cit)) (c:cs)
154+ = do
155+ let cmd = case citationMode c of
156+ SuppressAuthor -> "\\autocite*"
157+ AuthorInText -> "\\textcite"
158+ NormalCitation -> "\\autocite"
159+ return $ text cmd <>
160+ braces (literal (T.intercalate "," (map citationId (c:cs))))
161+ | otherwise
162+ = do
163+ let cmd = case citationMode c of
164+ SuppressAuthor -> "\\autocites*"
165+ AuthorInText -> "\\textcites"
166+ NormalCitation -> "\\autocites"
167+
168+ groups <- mapM (citeArgumentsList inlineListToLaTeX)
169+ (reverse (foldl' grouper [] (c:cs)))
170+
171+ return $ text cmd <> mconcat groups
172+
173+ where grouper prev cit = case prev of
174+ ((CiteGroup oPfx oSfx ids):rest)
175+ | null oSfx && null pfx -> CiteGroup oPfx sfx (cid:ids) : rest
176+ _ -> CiteGroup pfx sfx [cid] : prev
177+ where pfx = citationPrefix cit
178+ sfx = citationSuffix cit
179+ cid = citationId cit
180+
181+citationsToBiblatex _ _ = return empty
src/Text/Pandoc/Writers/LaTeX/Lang.hsnew file+191
@@ -0,0 +1,191 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{- |
4+ Module : Text.Pandoc.Writers.LaTeX.Lang
5+ Copyright : Copyright (C) 2006-2021 John MacFarlane
6+ License : GNU GPL, version 2 or above
7+
8+ Maintainer : John MacFarlane <jgm@berkeley.edu>
9+ Stability : alpha
10+ Portability : portable
11+-}
12+module Text.Pandoc.Writers.LaTeX.Lang
13+ ( toPolyglossiaEnv,
14+ toPolyglossia,
15+ toBabel
16+ ) where
17+import Data.Text (Text)
18+import Text.Pandoc.BCP47 (Lang (..))
19+
20+
21+-- In environments \Arabic instead of \arabic is used
22+toPolyglossiaEnv :: Lang -> (Text, Text)
23+toPolyglossiaEnv l =
24+ case toPolyglossia l of
25+ ("arabic", o) -> ("Arabic", o)
26+ x -> x
27+
28+-- Takes a list of the constituents of a BCP 47 language code and
29+-- converts it to a Polyglossia (language, options) tuple
30+-- http://mirrors.ctan.org/macros/latex/contrib/polyglossia/polyglossia.pdf
31+toPolyglossia :: Lang -> (Text, Text)
32+toPolyglossia (Lang "ar" _ "DZ" _) = ("arabic", "locale=algeria")
33+toPolyglossia (Lang "ar" _ "IQ" _) = ("arabic", "locale=mashriq")
34+toPolyglossia (Lang "ar" _ "JO" _) = ("arabic", "locale=mashriq")
35+toPolyglossia (Lang "ar" _ "LB" _) = ("arabic", "locale=mashriq")
36+toPolyglossia (Lang "ar" _ "LY" _) = ("arabic", "locale=libya")
37+toPolyglossia (Lang "ar" _ "MA" _) = ("arabic", "locale=morocco")
38+toPolyglossia (Lang "ar" _ "MR" _) = ("arabic", "locale=mauritania")
39+toPolyglossia (Lang "ar" _ "PS" _) = ("arabic", "locale=mashriq")
40+toPolyglossia (Lang "ar" _ "SY" _) = ("arabic", "locale=mashriq")
41+toPolyglossia (Lang "ar" _ "TN" _) = ("arabic", "locale=tunisia")
42+toPolyglossia (Lang "de" _ _ vars)
43+ | "1901" `elem` vars = ("german", "spelling=old")
44+toPolyglossia (Lang "de" _ "AT" vars)
45+ | "1901" `elem` vars = ("german", "variant=austrian, spelling=old")
46+toPolyglossia (Lang "de" _ "AT" _) = ("german", "variant=austrian")
47+toPolyglossia (Lang "de" _ "CH" vars)
48+ | "1901" `elem` vars = ("german", "variant=swiss, spelling=old")
49+toPolyglossia (Lang "de" _ "CH" _) = ("german", "variant=swiss")
50+toPolyglossia (Lang "de" _ _ _) = ("german", "")
51+toPolyglossia (Lang "dsb" _ _ _) = ("lsorbian", "")
52+toPolyglossia (Lang "el" _ "polyton" _) = ("greek", "variant=poly")
53+toPolyglossia (Lang "en" _ "AU" _) = ("english", "variant=australian")
54+toPolyglossia (Lang "en" _ "CA" _) = ("english", "variant=canadian")
55+toPolyglossia (Lang "en" _ "GB" _) = ("english", "variant=british")
56+toPolyglossia (Lang "en" _ "NZ" _) = ("english", "variant=newzealand")
57+toPolyglossia (Lang "en" _ "UK" _) = ("english", "variant=british")
58+toPolyglossia (Lang "en" _ "US" _) = ("english", "variant=american")
59+toPolyglossia (Lang "grc" _ _ _) = ("greek", "variant=ancient")
60+toPolyglossia (Lang "hsb" _ _ _) = ("usorbian", "")
61+toPolyglossia (Lang "la" _ _ vars)
62+ | "x-classic" `elem` vars = ("latin", "variant=classic")
63+toPolyglossia (Lang "pt" _ "BR" _) = ("portuguese", "variant=brazilian")
64+toPolyglossia (Lang "sl" _ _ _) = ("slovenian", "")
65+toPolyglossia x = (commonFromBcp47 x, "")
66+
67+-- Takes a list of the constituents of a BCP 47 language code and
68+-- converts it to a Babel language string.
69+-- http://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf
70+-- List of supported languages (slightly outdated):
71+-- http://tug.ctan.org/language/hyph-utf8/doc/generic/hyph-utf8/hyphenation.pdf
72+toBabel :: Lang -> Text
73+toBabel (Lang "de" _ "AT" vars)
74+ | "1901" `elem` vars = "austrian"
75+ | otherwise = "naustrian"
76+toBabel (Lang "de" _ "CH" vars)
77+ | "1901" `elem` vars = "swissgerman"
78+ | otherwise = "nswissgerman"
79+toBabel (Lang "de" _ _ vars)
80+ | "1901" `elem` vars = "german"
81+ | otherwise = "ngerman"
82+toBabel (Lang "dsb" _ _ _) = "lowersorbian"
83+toBabel (Lang "el" _ _ vars)
84+ | "polyton" `elem` vars = "polutonikogreek"
85+toBabel (Lang "en" _ "AU" _) = "australian"
86+toBabel (Lang "en" _ "CA" _) = "canadian"
87+toBabel (Lang "en" _ "GB" _) = "british"
88+toBabel (Lang "en" _ "NZ" _) = "newzealand"
89+toBabel (Lang "en" _ "UK" _) = "british"
90+toBabel (Lang "en" _ "US" _) = "american"
91+toBabel (Lang "fr" _ "CA" _) = "canadien"
92+toBabel (Lang "fra" _ _ vars)
93+ | "aca" `elem` vars = "acadian"
94+toBabel (Lang "grc" _ _ _) = "polutonikogreek"
95+toBabel (Lang "hsb" _ _ _) = "uppersorbian"
96+toBabel (Lang "la" _ _ vars)
97+ | "x-classic" `elem` vars = "classiclatin"
98+toBabel (Lang "pt" _ "BR" _) = "brazilian"
99+toBabel (Lang "sl" _ _ _) = "slovene"
100+toBabel x = commonFromBcp47 x
101+
102+-- Takes a list of the constituents of a BCP 47 language code
103+-- and converts it to a string shared by Babel and Polyglossia.
104+-- https://tools.ietf.org/html/bcp47#section-2.1
105+commonFromBcp47 :: Lang -> Text
106+commonFromBcp47 (Lang "sr" "Cyrl" _ _) = "serbianc"
107+commonFromBcp47 (Lang "zh" "Latn" _ vars)
108+ | "pinyin" `elem` vars = "pinyin"
109+commonFromBcp47 (Lang l _ _ _) = fromIso l
110+ where
111+ fromIso "af" = "afrikaans"
112+ fromIso "am" = "amharic"
113+ fromIso "ar" = "arabic"
114+ fromIso "as" = "assamese"
115+ fromIso "ast" = "asturian"
116+ fromIso "bg" = "bulgarian"
117+ fromIso "bn" = "bengali"
118+ fromIso "bo" = "tibetan"
119+ fromIso "br" = "breton"
120+ fromIso "ca" = "catalan"
121+ fromIso "cy" = "welsh"
122+ fromIso "cs" = "czech"
123+ fromIso "cop" = "coptic"
124+ fromIso "da" = "danish"
125+ fromIso "dv" = "divehi"
126+ fromIso "el" = "greek"
127+ fromIso "en" = "english"
128+ fromIso "eo" = "esperanto"
129+ fromIso "es" = "spanish"
130+ fromIso "et" = "estonian"
131+ fromIso "eu" = "basque"
132+ fromIso "fa" = "farsi"
133+ fromIso "fi" = "finnish"
134+ fromIso "fr" = "french"
135+ fromIso "fur" = "friulan"
136+ fromIso "ga" = "irish"
137+ fromIso "gd" = "scottish"
138+ fromIso "gez" = "ethiopic"
139+ fromIso "gl" = "galician"
140+ fromIso "he" = "hebrew"
141+ fromIso "hi" = "hindi"
142+ fromIso "hr" = "croatian"
143+ fromIso "hu" = "magyar"
144+ fromIso "hy" = "armenian"
145+ fromIso "ia" = "interlingua"
146+ fromIso "id" = "indonesian"
147+ fromIso "ie" = "interlingua"
148+ fromIso "is" = "icelandic"
149+ fromIso "it" = "italian"
150+ fromIso "ja" = "japanese"
151+ fromIso "km" = "khmer"
152+ fromIso "kmr" = "kurmanji"
153+ fromIso "kn" = "kannada"
154+ fromIso "ko" = "korean"
155+ fromIso "la" = "latin"
156+ fromIso "lo" = "lao"
157+ fromIso "lt" = "lithuanian"
158+ fromIso "lv" = "latvian"
159+ fromIso "ml" = "malayalam"
160+ fromIso "mn" = "mongolian"
161+ fromIso "mr" = "marathi"
162+ fromIso "nb" = "norsk"
163+ fromIso "nl" = "dutch"
164+ fromIso "nn" = "nynorsk"
165+ fromIso "no" = "norsk"
166+ fromIso "nqo" = "nko"
167+ fromIso "oc" = "occitan"
168+ fromIso "pa" = "panjabi"
169+ fromIso "pl" = "polish"
170+ fromIso "pms" = "piedmontese"
171+ fromIso "pt" = "portuguese"
172+ fromIso "rm" = "romansh"
173+ fromIso "ro" = "romanian"
174+ fromIso "ru" = "russian"
175+ fromIso "sa" = "sanskrit"
176+ fromIso "se" = "samin"
177+ fromIso "sk" = "slovak"
178+ fromIso "sq" = "albanian"
179+ fromIso "sr" = "serbian"
180+ fromIso "sv" = "swedish"
181+ fromIso "syr" = "syriac"
182+ fromIso "ta" = "tamil"
183+ fromIso "te" = "telugu"
184+ fromIso "th" = "thai"
185+ fromIso "ti" = "ethiopic"
186+ fromIso "tk" = "turkmen"
187+ fromIso "tr" = "turkish"
188+ fromIso "uk" = "ukrainian"
189+ fromIso "ur" = "urdu"
190+ fromIso "vi" = "vietnamese"
191+ fromIso _ = ""
src/Text/Pandoc/Writers/LaTeX/Util.hsnew file+274
@@ -0,0 +1,274 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{- |
3+ Module : Text.Pandoc.Writers.LaTeX.Util
4+ Copyright : Copyright (C) 2006-2021 John MacFarlane
5+ License : GNU GPL, version 2 or above
6+
7+ Maintainer : John MacFarlane <jgm@berkeley.edu>
8+ Stability : alpha
9+ Portability : portable
10+-}
11+module Text.Pandoc.Writers.LaTeX.Util (
12+ stringToLaTeX
13+ , StringContext(..)
14+ , toLabel
15+ , inCmd
16+ , wrapDiv
17+ , hypertarget
18+ , labelFor
19+ , getListingsLanguage
20+ , mbBraced
21+ )
22+where
23+
24+import Control.Applicative ((<|>))
25+import Text.Pandoc.Class (PandocMonad, toLang)
26+import Text.Pandoc.Options (WriterOptions(..), isEnabled)
27+import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState(..))
28+import Text.Pandoc.Writers.LaTeX.Lang (toPolyglossiaEnv)
29+import Text.Pandoc.Highlighting (toListingsLanguage)
30+import Text.DocLayout
31+import Text.Pandoc.Definition
32+import Text.Pandoc.ImageSize (showFl)
33+import Control.Monad.State.Strict (gets)
34+import Data.Text (Text)
35+import qualified Data.Text as T
36+import Text.Pandoc.Extensions (Extension(Ext_smart))
37+import Data.Char (isLetter, isSpace, isDigit, isAscii, ord, isAlphaNum)
38+import Text.Printf (printf)
39+import Text.Pandoc.Shared (safeRead, elemText)
40+import qualified Data.Text.Normalize as Normalize
41+import Data.List (uncons)
42+
43+data StringContext = TextString
44+ | URLString
45+ | CodeString
46+ deriving (Eq)
47+
48+-- escape things as needed for LaTeX
49+stringToLaTeX :: PandocMonad m => StringContext -> Text -> LW m Text
50+stringToLaTeX context zs = do
51+ opts <- gets stOptions
52+ return $ T.pack $
53+ foldr (go opts context) mempty $ T.unpack $
54+ if writerPreferAscii opts
55+ then Normalize.normalize Normalize.NFD zs
56+ else zs
57+ where
58+ go :: WriterOptions -> StringContext -> Char -> String -> String
59+ go opts ctx x xs =
60+ let ligatures = isEnabled Ext_smart opts && ctx == TextString
61+ isUrl = ctx == URLString
62+ mbAccentCmd =
63+ if writerPreferAscii opts && ctx == TextString
64+ then uncons xs >>= \(c,_) -> lookupAccent c
65+ else Nothing
66+ emits s =
67+ case mbAccentCmd of
68+ Just cmd ->
69+ cmd <> "{" <> s <> "}" <> drop 1 xs -- drop combining accent
70+ Nothing -> s <> xs
71+ emitc c =
72+ case mbAccentCmd of
73+ Just cmd ->
74+ cmd <> "{" <> [c] <> "}" <> drop 1 xs -- drop combining accent
75+ Nothing -> c : xs
76+ emitcseq cs =
77+ case xs of
78+ c:_ | isLetter c
79+ , ctx == TextString
80+ -> cs <> " " <> xs
81+ | isSpace c -> cs <> "{}" <> xs
82+ | ctx == TextString
83+ -> cs <> xs
84+ _ -> cs <> "{}" <> xs
85+ emitquote cs =
86+ case xs of
87+ '`':_ -> cs <> "\\," <> xs -- add thin space
88+ '\'':_ -> cs <> "\\," <> xs -- add thin space
89+ _ -> cs <> xs
90+ in case x of
91+ '?' | ligatures -> -- avoid ?` ligature
92+ case xs of
93+ '`':_ -> emits "?{}"
94+ _ -> emitc x
95+ '!' | ligatures -> -- avoid !` ligature
96+ case xs of
97+ '`':_ -> emits "!{}"
98+ _ -> emitc x
99+ '{' -> emits "\\{"
100+ '}' -> emits "\\}"
101+ '`' | ctx == CodeString -> emitcseq "\\textasciigrave"
102+ '$' | not isUrl -> emits "\\$"
103+ '%' -> emits "\\%"
104+ '&' -> emits "\\&"
105+ '_' | not isUrl -> emits "\\_"
106+ '#' -> emits "\\#"
107+ '-' | not isUrl -> case xs of
108+ -- prevent adjacent hyphens from forming ligatures
109+ ('-':_) -> emits "-\\/"
110+ _ -> emitc '-'
111+ '~' | not isUrl -> emitcseq "\\textasciitilde"
112+ '^' -> emits "\\^{}"
113+ '\\'| isUrl -> emitc '/' -- NB. / works as path sep even on Windows
114+ | otherwise -> emitcseq "\\textbackslash"
115+ '|' | not isUrl -> emitcseq "\\textbar"
116+ '<' -> emitcseq "\\textless"
117+ '>' -> emitcseq "\\textgreater"
118+ '[' -> emits "{[}" -- to avoid interpretation as
119+ ']' -> emits "{]}" -- optional arguments
120+ '\'' | ctx == CodeString -> emitcseq "\\textquotesingle"
121+ '\160' -> emits "~"
122+ '\x200B' -> emits "\\hspace{0pt}" -- zero-width space
123+ '\x202F' -> emits "\\,"
124+ '\x2026' -> emitcseq "\\ldots"
125+ '\x2018' | ligatures -> emitquote "`"
126+ '\x2019' | ligatures -> emitquote "'"
127+ '\x201C' | ligatures -> emitquote "``"
128+ '\x201D' | ligatures -> emitquote "''"
129+ '\x2014' | ligatures -> emits "---"
130+ '\x2013' | ligatures -> emits "--"
131+ _ | writerPreferAscii opts
132+ -> case x of
133+ 'ı' -> emitcseq "\\i"
134+ 'ȷ' -> emitcseq "\\j"
135+ 'å' -> emitcseq "\\aa"
136+ 'Å' -> emitcseq "\\AA"
137+ 'ß' -> emitcseq "\\ss"
138+ 'ø' -> emitcseq "\\o"
139+ 'Ø' -> emitcseq "\\O"
140+ 'Ł' -> emitcseq "\\L"
141+ 'ł' -> emitcseq "\\l"
142+ 'æ' -> emitcseq "\\ae"
143+ 'Æ' -> emitcseq "\\AE"
144+ 'œ' -> emitcseq "\\oe"
145+ 'Œ' -> emitcseq "\\OE"
146+ '£' -> emitcseq "\\pounds"
147+ '€' -> emitcseq "\\euro"
148+ '©' -> emitcseq "\\copyright"
149+ _ -> emitc x
150+ | otherwise -> emitc x
151+
152+lookupAccent :: Char -> Maybe String
153+lookupAccent '\779' = Just "\\H"
154+lookupAccent '\768' = Just "\\`"
155+lookupAccent '\769' = Just "\\'"
156+lookupAccent '\770' = Just "\\^"
157+lookupAccent '\771' = Just "\\~"
158+lookupAccent '\776' = Just "\\\""
159+lookupAccent '\775' = Just "\\."
160+lookupAccent '\772' = Just "\\="
161+lookupAccent '\781' = Just "\\|"
162+lookupAccent '\817' = Just "\\b"
163+lookupAccent '\807' = Just "\\c"
164+lookupAccent '\783' = Just "\\G"
165+lookupAccent '\777' = Just "\\h"
166+lookupAccent '\803' = Just "\\d"
167+lookupAccent '\785' = Just "\\f"
168+lookupAccent '\778' = Just "\\r"
169+lookupAccent '\865' = Just "\\t"
170+lookupAccent '\782' = Just "\\U"
171+lookupAccent '\780' = Just "\\v"
172+lookupAccent '\774' = Just "\\u"
173+lookupAccent '\808' = Just "\\k"
174+lookupAccent '\8413' = Just "\\textcircled"
175+lookupAccent _ = Nothing
176+
177+toLabel :: PandocMonad m => Text -> LW m Text
178+toLabel z = go `fmap` stringToLaTeX URLString z
179+ where
180+ go = T.concatMap $ \x -> case x of
181+ _ | (isLetter x || isDigit x) && isAscii x -> T.singleton x
182+ | x `elemText` "_-+=:;." -> T.singleton x
183+ | otherwise -> T.pack $ "ux" <> printf "%x" (ord x)
184+
185+-- | Puts contents into LaTeX command.
186+inCmd :: Text -> Doc Text -> Doc Text
187+inCmd cmd contents = char '\\' <> literal cmd <> braces contents
188+
189+mapAlignment :: Text -> Text
190+mapAlignment a = case a of
191+ "top" -> "T"
192+ "top-baseline" -> "t"
193+ "bottom" -> "b"
194+ "center" -> "c"
195+ _ -> a
196+
197+wrapDiv :: PandocMonad m => Attr -> Doc Text -> LW m (Doc Text)
198+wrapDiv (_,classes,kvs) t = do
199+ beamer <- gets stBeamer
200+ let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
201+ lang <- toLang $ lookup "lang" kvs
202+ let wrapColumns = if beamer && "columns" `elem` classes
203+ then \contents ->
204+ let valign = maybe "T" mapAlignment (lookup "align" kvs)
205+ totalwidth = maybe [] (\x -> ["totalwidth=" <> x])
206+ (lookup "totalwidth" kvs)
207+ onlytextwidth = filter ("onlytextwidth" ==) classes
208+ options = text $ T.unpack $ T.intercalate "," $
209+ valign : totalwidth ++ onlytextwidth
210+ in inCmd "begin" "columns" <> brackets options
211+ $$ contents
212+ $$ inCmd "end" "columns"
213+ else id
214+ wrapColumn = if beamer && "column" `elem` classes
215+ then \contents ->
216+ let valign =
217+ maybe ""
218+ (brackets . text . T.unpack . mapAlignment)
219+ (lookup "align" kvs)
220+ w = maybe "0.48" fromPct (lookup "width" kvs)
221+ in inCmd "begin" "column" <>
222+ valign <>
223+ braces (literal w <> "\\textwidth")
224+ $$ contents
225+ $$ inCmd "end" "column"
226+ else id
227+ fromPct xs =
228+ case T.unsnoc xs of
229+ Just (ds, '%') -> case safeRead ds of
230+ Just digits -> showFl (digits / 100 :: Double)
231+ Nothing -> xs
232+ _ -> xs
233+ wrapDir = case lookup "dir" kvs of
234+ Just "rtl" -> align "RTL"
235+ Just "ltr" -> align "LTR"
236+ _ -> id
237+ wrapLang txt = case lang of
238+ Just lng -> let (l, o) = toPolyglossiaEnv lng
239+ ops = if T.null o
240+ then ""
241+ else brackets $ literal o
242+ in inCmd "begin" (literal l) <> ops
243+ $$ blankline <> txt <> blankline
244+ $$ inCmd "end" (literal l)
245+ Nothing -> txt
246+ return $ wrapColumns . wrapColumn . wrapDir . wrapLang $ t
247+
248+hypertarget :: PandocMonad m => Bool -> Text -> Doc Text -> LW m (Doc Text)
249+hypertarget _ "" x = return x
250+hypertarget addnewline ident x = do
251+ ref <- literal `fmap` toLabel ident
252+ return $ text "\\hypertarget"
253+ <> braces ref
254+ <> braces ((if addnewline && not (isEmpty x)
255+ then "%" <> cr
256+ else empty) <> x)
257+
258+labelFor :: PandocMonad m => Text -> LW m (Doc Text)
259+labelFor "" = return empty
260+labelFor ident = do
261+ ref <- literal `fmap` toLabel ident
262+ return $ text "\\label" <> braces ref
263+
264+-- Determine listings language from list of class attributes.
265+getListingsLanguage :: [Text] -> Maybe Text
266+getListingsLanguage xs
267+ = foldr ((<|>) . toListingsLanguage) Nothing xs
268+
269+mbBraced :: Text -> Text
270+mbBraced x = if not (T.all isAlphaNum x)
271+ then "{" <> x <> "}"
272+ else x
273+
274+
src/Text/Pandoc/Writers/Markdown.hs+6−591
@@ -22,15 +22,13 @@ module Text.Pandoc.Writers.Markdown (
22 writePlain) where
22 writePlain) where
23import Control.Monad.Reader
23import Control.Monad.Reader
24import Control.Monad.State.Strict
24import Control.Monad.State.Strict
25−import Data.Char (isAlphaNum, isDigit)
26import Data.Default
25import Data.Default
27−import Data.List (find, intersperse, sortOn, transpose)
26+import Data.List (intersperse, sortOn, transpose)
28import qualified Data.Map as M
27import qualified Data.Map as M
29import Data.Maybe (fromMaybe, mapMaybe)
28import Data.Maybe (fromMaybe, mapMaybe)
30import qualified Data.Set as Set
29import qualified Data.Set as Set
31import Data.Text (Text)
30import Data.Text (Text)
32import qualified Data.Text as T
31import qualified Data.Text as T
33−import Network.HTTP (urlEncode)
34import Text.HTML.TagSoup (Tag (..), isTagText, parseTags)
32import Text.HTML.TagSoup (Tag (..), isTagText, parseTags)
35import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
33import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
36import Text.Pandoc.Definition
34import Text.Pandoc.Definition
@@ -44,59 +42,11 @@ import Text.Pandoc.Templates (renderTemplate)
44import Text.DocTemplates (Val(..), Context(..), FromContext(..))
42import Text.DocTemplates (Val(..), Context(..), FromContext(..))
45import Text.Pandoc.Walk
43import Text.Pandoc.Walk
46import Text.Pandoc.Writers.HTML (writeHtml5String)
44import Text.Pandoc.Writers.HTML (writeHtml5String)
47−import Text.Pandoc.Writers.Math (texMathToInlines)
45+import Text.Pandoc.Writers.Markdown.Inline (inlineListToMarkdown)
48−import Text.Pandoc.XML (toHtml5Entities)
46+import Text.Pandoc.Writers.Markdown.Types (MarkdownVariant(..),
49−import Data.Coerce (coerce)
50−
51−type Notes = [[Block]]
52−type Ref = (Text, Target, Attr)
53−type Refs = [Ref]
54−
55−type MD m = ReaderT WriterEnv (StateT WriterState m)
56−
57−evalMD :: PandocMonad m => MD m a -> WriterEnv -> WriterState -> m a
47+ WriterState(..),
58−evalMD md env st = evalStateT (runReaderT md env) st
59−
60−data WriterEnv = WriterEnv { envInList :: Bool
48+ WriterEnv(..),
61− , envVariant :: MarkdownVariant
49+ Ref, Refs, MD, evalMD)
62− , envRefShortcutable :: Bool
63− , envBlockLevel :: Int
64− , envEscapeSpaces :: Bool
65− }
66−
67−data MarkdownVariant =
68− PlainText
69− | Commonmark
70− | Markdown
71− deriving (Show, Eq)
72−
73−instance Default WriterEnv
74− where def = WriterEnv { envInList = False
75− , envVariant = Markdown
76− , envRefShortcutable = True
77− , envBlockLevel = 0
78− , envEscapeSpaces = False
79− }
80−
81−data WriterState = WriterState { stNotes :: Notes
82− , stPrevRefs :: Refs
83− , stRefs :: Refs
84− , stKeys :: M.Map Key
85− (M.Map (Target, Attr) Int)
86− , stLastIdx :: Int
87− , stIds :: Set.Set Text
88− , stNoteNum :: Int
89− }
90−
91−instance Default WriterState
92− where def = WriterState{ stNotes = []
93− , stPrevRefs = []
94− , stRefs = []
95− , stKeys = M.empty
96− , stLastIdx = 0
97− , stIds = Set.empty
98− , stNoteNum = 1
99− }
100
50
101-- | Convert Pandoc to Markdown.
51-- | Convert Pandoc to Markdown.
102writeMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> m Text
52writeMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> m Text
@@ -297,49 +247,6 @@ noteToMarkdown opts num blocks = do
297 then hang (writerTabStop opts) (marker <> spacer) contents
247 then hang (writerTabStop opts) (marker <> spacer) contents
298 else marker <> spacer <> contents
248 else marker <> spacer <> contents
299
249
300−-- | Escape special characters for Markdown.
301−escapeText :: WriterOptions -> Text -> Text
302−escapeText opts = T.pack . go . T.unpack
303− where
304− go [] = []
305− go (c:cs) =
306− case c of
307− '<' | isEnabled Ext_all_symbols_escapable opts ->
308− '\\' : '<' : go cs
309− | otherwise -> "&lt;" ++ go cs
310− '>' | isEnabled Ext_all_symbols_escapable opts ->
311− '\\' : '>' : go cs
312− | otherwise -> "&gt;" ++ go cs
313− '@' | isEnabled Ext_citations opts ->
314− case cs of
315− (d:_)
316− | isAlphaNum d || d == '_'
317− -> '\\':'@':go cs
318− _ -> '@':go cs
319− _ | c `elem` ['\\','`','*','_','[',']','#'] ->
320− '\\':c:go cs
321− '|' | isEnabled Ext_pipe_tables opts -> '\\':'|':go cs
322− '^' | isEnabled Ext_superscript opts -> '\\':'^':go cs
323− '~' | isEnabled Ext_subscript opts ||
324− isEnabled Ext_strikeout opts -> '\\':'~':go cs
325− '$' | isEnabled Ext_tex_math_dollars opts -> '\\':'$':go cs
326− '\'' | isEnabled Ext_smart opts -> '\\':'\'':go cs
327− '"' | isEnabled Ext_smart opts -> '\\':'"':go cs
328− '-' | isEnabled Ext_smart opts ->
329− case cs of
330− '-':_ -> '\\':'-':go cs
331− _ -> '-':go cs
332− '.' | isEnabled Ext_smart opts ->
333− case cs of
334− '.':'.':rest -> '\\':'.':'.':'.':go rest
335− _ -> '.':go cs
336− _ -> case cs of
337− '_':x:xs
338− | isEnabled Ext_intraword_underscores opts
339− , isAlphaNum c
340− , isAlphaNum x -> c : '_' : x : go xs
341− _ -> c : go cs
342−
343attrsToMarkdown :: Attr -> Doc Text
250attrsToMarkdown :: Attr -> Doc Text
344attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
251attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
345 where attribId = case attribs of
252 where attribId = case attribs of
@@ -912,499 +819,7 @@ blockListToMarkdown opts blocks = do
912 | otherwise = RawBlock "markdown" "&nbsp;\n"
819 | otherwise = RawBlock "markdown" "&nbsp;\n"
913 mconcat <$> mapM (blockToMarkdown opts) (fixBlocks blocks)
820 mconcat <$> mapM (blockToMarkdown opts) (fixBlocks blocks)
914
821
915−getKey :: Doc Text -> Key
916−getKey = toKey . render Nothing
917−
918−findUsableIndex :: [Text] -> Int -> Int
919−findUsableIndex lbls i = if tshow i `elem` lbls
920− then findUsableIndex lbls (i + 1)
921− else i
922−
923−getNextIndex :: PandocMonad m => MD m Int
924−getNextIndex = do
925− prevRefs <- gets stPrevRefs
926− refs <- gets stRefs
927− i <- (+ 1) <$> gets stLastIdx
928− modify $ \s -> s{ stLastIdx = i }
929− let refLbls = map (\(r,_,_) -> r) $ prevRefs ++ refs
930− return $ findUsableIndex refLbls i
931−
932−-- | Get reference for target; if none exists, create unique one and return.
933−-- Prefer label if possible; otherwise, generate a unique key.
934−getReference :: PandocMonad m => Attr -> Doc Text -> Target -> MD m Text
935−getReference attr label target = do
936− refs <- gets stRefs
937− case find (\(_,t,a) -> t == target && a == attr) refs of
938− Just (ref, _, _) -> return ref
939− Nothing -> do
940− keys <- gets stKeys
941− let key = getKey label
942− let rawkey = coerce key
943− case M.lookup key keys of
944− Nothing -> do -- no other refs with this label
945− (lab', idx) <- if T.null rawkey ||
946− T.length rawkey > 999 ||
947− T.any (\c -> c == '[' || c == ']') rawkey
948− then do
949− i <- getNextIndex
950− return (tshow i, i)
951− else
952− return (render Nothing label, 0)
953− modify (\s -> s{
954− stRefs = (lab', target, attr) : refs,
955− stKeys = M.insert (getKey label)
956− (M.insert (target, attr) idx mempty)
957− (stKeys s) })
958− return lab'
959−
960− Just km -> -- we have refs with this label
961− case M.lookup (target, attr) km of
962− Just i -> do
963− let lab' = render Nothing $
964− label <> if i == 0
965− then mempty
966− else literal (tshow i)
967− -- make sure it's in stRefs; it may be
968− -- a duplicate that was printed in a previous
969− -- block:
970− when ((lab', target, attr) `notElem` refs) $
971− modify (\s -> s{
972− stRefs = (lab', target, attr) : refs })
973− return lab'
974− Nothing -> do -- but this one is to a new target
975− i <- getNextIndex
976− let lab' = tshow i
977− modify (\s -> s{
978− stRefs = (lab', target, attr) : refs,
979− stKeys = M.insert key
980− (M.insert (target, attr) i km)
981− (stKeys s) })
982− return lab'
983−
984−-- | Convert list of Pandoc inline elements to markdown.
985−inlineListToMarkdown :: PandocMonad m => WriterOptions -> [Inline] -> MD m (Doc Text)
986−inlineListToMarkdown opts lst = do
987− inlist <- asks envInList
988− go (if inlist then avoidBadWrapsInList lst else lst)
989− where go [] = return empty
990− go (x@Math{}:y@(Str t):zs)
991− | T.all isDigit (T.take 1 t) -- starts with digit -- see #7058
992− = liftM2 (<>) (inlineToMarkdown opts x)
993− (go (RawInline (Format "html") "<!-- -->" : y : zs))
994− go (i:is) = case i of
995− Link {} -> case is of
996− -- If a link is followed by another link, or '[', '(' or ':'
997− -- then we don't shortcut
998− Link {}:_ -> unshortcutable
999− Space:Link {}:_ -> unshortcutable
1000− Space:(Str(thead -> Just '[')):_ -> unshortcutable
1001− Space:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
1002− Space:(Cite _ _):_ -> unshortcutable
1003− SoftBreak:Link {}:_ -> unshortcutable
1004− SoftBreak:(Str(thead -> Just '[')):_ -> unshortcutable
1005− SoftBreak:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
1006− SoftBreak:(Cite _ _):_ -> unshortcutable
1007− LineBreak:Link {}:_ -> unshortcutable
1008− LineBreak:(Str(thead -> Just '[')):_ -> unshortcutable
1009− LineBreak:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
1010− LineBreak:(Cite _ _):_ -> unshortcutable
1011− (Cite _ _):_ -> unshortcutable
1012− Str (thead -> Just '['):_ -> unshortcutable
1013− Str (thead -> Just '('):_ -> unshortcutable
1014− Str (thead -> Just ':'):_ -> unshortcutable
1015− (RawInline _ (thead -> Just '[')):_ -> unshortcutable
1016− (RawInline _ (thead -> Just '(')):_ -> unshortcutable
1017− (RawInline _ (thead -> Just ':')):_ -> unshortcutable
1018− (RawInline _ (T.stripPrefix " [" -> Just _ )):_ -> unshortcutable
1019− _ -> shortcutable
1020− _ -> shortcutable
1021− where shortcutable = liftM2 (<>) (inlineToMarkdown opts i) (go is)
1022− unshortcutable = do
1023− iMark <- local
1024− (\env -> env { envRefShortcutable = False })
1025− (inlineToMarkdown opts i)
1026− fmap (iMark <>) (go is)
1027− thead = fmap fst . T.uncons
1028−
1029−isSp :: Inline -> Bool
1030−isSp Space = True
1031−isSp SoftBreak = True
1032−isSp _ = False
1033−
1034−avoidBadWrapsInList :: [Inline] -> [Inline]
1035−avoidBadWrapsInList [] = []
1036−avoidBadWrapsInList (s:Str (T.uncons -> Just ('>',cs)):xs) | isSp s =
1037− Str (" >" <> cs) : avoidBadWrapsInList xs
1038−avoidBadWrapsInList [s, Str (T.uncons -> Just (c, cs))]
1039− | T.null cs && isSp s && c `elem` ['-','*','+'] = [Str $ T.pack [' ', c]]
1040−avoidBadWrapsInList (s:Str (T.uncons -> Just (c, cs)):Space:xs)
1041− | T.null cs && isSp s && c `elem` ['-','*','+'] =
1042− Str (T.pack [' ', c]) : Space : avoidBadWrapsInList xs
1043−avoidBadWrapsInList (s:Str cs:Space:xs)
1044− | isSp s && isOrderedListMarker cs =
1045− Str (" " <> cs) : Space : avoidBadWrapsInList xs
1046−avoidBadWrapsInList [s, Str cs]
1047− | isSp s && isOrderedListMarker cs = [Str $ " " <> cs]
1048−avoidBadWrapsInList (x:xs) = x : avoidBadWrapsInList xs
1049−
1050−isOrderedListMarker :: Text -> Bool
1051−isOrderedListMarker xs = not (T.null xs) && (T.last xs `elem` ['.',')']) &&
1052− isRight (runParser (anyOrderedListMarker >> eof)
1053− defaultParserState "" xs)
1054−
1055−isRight :: Either a b -> Bool
1056−isRight (Right _) = True
1057−isRight (Left _) = False
1058−
1059−-- | Convert Pandoc inline element to markdown.
1060−inlineToMarkdown :: PandocMonad m => WriterOptions -> Inline -> MD m (Doc Text)
1061−inlineToMarkdown opts (Span ("",["emoji"],kvs) [Str s]) =
1062− case lookup "data-emoji" kvs of
1063− Just emojiname | isEnabled Ext_emoji opts ->
1064− return $ ":" <> literal emojiname <> ":"
1065− _ -> inlineToMarkdown opts (Str s)
1066−inlineToMarkdown opts (Span attrs ils) = do
1067− variant <- asks envVariant
1068− contents <- inlineListToMarkdown opts ils
1069− return $ case attrs of
1070− (_,["csl-block"],_) -> (cr <>)
1071− (_,["csl-left-margin"],_) -> (cr <>)
1072− (_,["csl-indent"],_) -> (cr <>)
1073− _ -> id
1074− $ case variant of
1075− PlainText -> contents
1076− _ | attrs == nullAttr -> contents
1077− | isEnabled Ext_bracketed_spans opts ->
1078− let attrs' = if attrs /= nullAttr
1079− then attrsToMarkdown attrs
1080− else empty
1081− in "[" <> contents <> "]" <> attrs'
1082− | isEnabled Ext_raw_html opts ||
1083− isEnabled Ext_native_spans opts ->
1084− tagWithAttrs "span" attrs <> contents <> literal "</span>"
1085− | otherwise -> contents
1086−inlineToMarkdown _ (Emph []) = return empty
1087−inlineToMarkdown opts (Emph lst) = do
1088− variant <- asks envVariant
1089− contents <- inlineListToMarkdown opts lst
1090− return $ case variant of
1091− PlainText
1092− | isEnabled Ext_gutenberg opts -> "_" <> contents <> "_"
1093− | otherwise -> contents
1094− _ -> "*" <> contents <> "*"
1095−inlineToMarkdown _ (Underline []) = return empty
1096−inlineToMarkdown opts (Underline lst) = do
1097− variant <- asks envVariant
1098− contents <- inlineListToMarkdown opts lst
1099− case variant of
1100− PlainText -> return contents
1101− _ | isEnabled Ext_bracketed_spans opts ->
1102− return $ "[" <> contents <> "]" <> "{.ul}"
1103− | isEnabled Ext_native_spans opts ->
1104− return $ tagWithAttrs "span" ("", ["underline"], [])
1105− <> contents
1106− <> literal "</span>"
1107− | isEnabled Ext_raw_html opts ->
1108− return $ "<u>" <> contents <> "</u>"
1109− | otherwise -> inlineToMarkdown opts (Emph lst)
1110−inlineToMarkdown _ (Strong []) = return empty
1111−inlineToMarkdown opts (Strong lst) = do
1112− variant <- asks envVariant
1113− case variant of
1114− PlainText ->
1115− inlineListToMarkdown opts $
1116− if isEnabled Ext_gutenberg opts
1117− then capitalize lst
1118− else lst
1119− _ -> do
1120− contents <- inlineListToMarkdown opts lst
1121− return $ "**" <> contents <> "**"
1122−inlineToMarkdown _ (Strikeout []) = return empty
1123−inlineToMarkdown opts (Strikeout lst) = do
1124− contents <- inlineListToMarkdown opts lst
1125− return $ if isEnabled Ext_strikeout opts
1126− then "~~" <> contents <> "~~"
1127− else if isEnabled Ext_raw_html opts
1128− then "<s>" <> contents <> "</s>"
1129− else contents
1130−inlineToMarkdown _ (Superscript []) = return empty
1131−inlineToMarkdown opts (Superscript lst) =
1132− local (\env -> env {envEscapeSpaces = envVariant env == Markdown}) $ do
1133− contents <- inlineListToMarkdown opts lst
1134− if isEnabled Ext_superscript opts
1135− then return $ "^" <> contents <> "^"
1136− else if isEnabled Ext_raw_html opts
1137− then return $ "<sup>" <> contents <> "</sup>"
1138− else
1139− case traverse toSuperscriptInline lst of
1140− Just xs' | not (writerPreferAscii opts)
1141− -> inlineListToMarkdown opts xs'
1142− _ -> do
1143− let rendered = render Nothing contents
1144− return $
1145− case mapM toSuperscript (T.unpack rendered) of
1146− Just r -> literal $ T.pack r
1147− Nothing -> literal $ "^(" <> rendered <> ")"
1148−inlineToMarkdown _ (Subscript []) = return empty
1149−inlineToMarkdown opts (Subscript lst) =
1150− local (\env -> env {envEscapeSpaces = envVariant env == Markdown}) $ do
1151− contents <- inlineListToMarkdown opts lst
1152− if isEnabled Ext_subscript opts
1153− then return $ "~" <> contents <> "~"
1154− else if isEnabled Ext_raw_html opts
1155− then return $ "<sub>" <> contents <> "</sub>"
1156− else
1157− case traverse toSubscriptInline lst of
1158− Just xs' | not (writerPreferAscii opts)
1159− -> inlineListToMarkdown opts xs'
1160− _ -> do
1161− let rendered = render Nothing contents
1162− return $
1163− case mapM toSuperscript (T.unpack rendered) of
1164− Just r -> literal $ T.pack r
1165− Nothing -> literal $ "_(" <> rendered <> ")"
1166−inlineToMarkdown opts (SmallCaps lst) = do
1167− variant <- asks envVariant
1168− if variant /= PlainText &&
1169− (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
1170− then inlineToMarkdown opts (Span ("",["smallcaps"],[]) lst)
1171− else inlineListToMarkdown opts $ capitalize lst
1172−inlineToMarkdown opts (Quoted SingleQuote lst) = do
1173− contents <- inlineListToMarkdown opts lst
1174− return $ if isEnabled Ext_smart opts
1175− then "'" <> contents <> "'"
1176− else
1177− if writerPreferAscii opts
1178− then "&lsquo;" <> contents <> "&rsquo;"
1179− else "‘" <> contents <> "’"
1180−inlineToMarkdown opts (Quoted DoubleQuote lst) = do
1181− contents <- inlineListToMarkdown opts lst
1182− return $ if isEnabled Ext_smart opts
1183− then "\"" <> contents <> "\""
1184− else
1185− if writerPreferAscii opts
1186− then "&ldquo;" <> contents <> "&rdquo;"
1187− else "“" <> contents <> "”"
1188−inlineToMarkdown opts (Code attr str) = do
1189− let tickGroups = filter (T.any (== '`')) $ T.group str
1190− let longest = if null tickGroups
1191− then 0
1192− else maximum $ map T.length tickGroups
1193− let marker = T.replicate (longest + 1) "`"
1194− let spacer = if longest == 0 then "" else " "
1195− let attrs = if isEnabled Ext_inline_code_attributes opts && attr /= nullAttr
1196− then attrsToMarkdown attr
1197− else empty
1198− variant <- asks envVariant
1199− case variant of
1200− PlainText -> return $ literal str
1201− _ -> return $ literal
1202− (marker <> spacer <> str <> spacer <> marker) <> attrs
1203−inlineToMarkdown opts (Str str) = do
1204− variant <- asks envVariant
1205− let str' = (if writerPreferAscii opts
1206− then toHtml5Entities
1207− else id) .
1208− (if isEnabled Ext_smart opts
1209− then unsmartify opts
1210− else id) .
1211− (if variant == PlainText
1212− then id
1213− else escapeText opts) $ str
1214− return $ literal str'
1215−inlineToMarkdown opts (Math InlineMath str) =
1216− case writerHTMLMathMethod opts of
1217− WebTeX url -> inlineToMarkdown opts
1218− (Image nullAttr [Str str] (url <> T.pack (urlEncode $ T.unpack str), str))
1219− _ | isEnabled Ext_tex_math_dollars opts ->
1220− return $ "$" <> literal str <> "$"
1221− | isEnabled Ext_tex_math_single_backslash opts ->
1222− return $ "\\(" <> literal str <> "\\)"
1223− | isEnabled Ext_tex_math_double_backslash opts ->
1224− return $ "\\\\(" <> literal str <> "\\\\)"
1225− | otherwise -> do
1226− variant <- asks envVariant
1227− texMathToInlines InlineMath str >>=
1228− inlineListToMarkdown opts .
1229− (if variant == PlainText then makeMathPlainer else id)
1230−inlineToMarkdown opts (Math DisplayMath str) =
1231− case writerHTMLMathMethod opts of
1232− WebTeX url -> (\x -> blankline <> x <> blankline) `fmap`
1233− inlineToMarkdown opts (Image nullAttr [Str str]
1234− (url <> T.pack (urlEncode $ T.unpack str), str))
1235− _ | isEnabled Ext_tex_math_dollars opts ->
1236− return $ "$$" <> literal str <> "$$"
1237− | isEnabled Ext_tex_math_single_backslash opts ->
1238− return $ "\\[" <> literal str <> "\\]"
1239− | isEnabled Ext_tex_math_double_backslash opts ->
1240− return $ "\\\\[" <> literal str <> "\\\\]"
1241− | otherwise -> (\x -> cr <> x <> cr) `fmap`
1242− (texMathToInlines DisplayMath str >>= inlineListToMarkdown opts)
1243−inlineToMarkdown opts il@(RawInline f str) = do
1244− let tickGroups = filter (T.any (== '`')) $ T.group str
1245− let numticks = if null tickGroups
1246− then 1
1247− else 1 + maximum (map T.length tickGroups)
1248− variant <- asks envVariant
1249− let Format fmt = f
1250− let rawAttribInline = return $
1251− literal (T.replicate numticks "`") <> literal str <>
1252− literal (T.replicate numticks "`") <> literal "{=" <> literal fmt <> literal "}"
1253− let renderEmpty = mempty <$ report (InlineNotRendered il)
1254− case variant of
1255− PlainText -> renderEmpty
1256− Commonmark
1257− | f `elem` ["gfm", "commonmark", "commonmark_x", "markdown"]
1258− -> return $ literal str
1259− Markdown
1260− | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
1261− "markdown_mmd", "markdown_strict"]
1262− -> return $ literal str
1263− _ | isEnabled Ext_raw_attribute opts -> rawAttribInline
1264− | f `elem` ["html", "html5", "html4"]
1265− , isEnabled Ext_raw_html opts
1266− -> return $ literal str
1267− | f `elem` ["latex", "tex"]
1268− , isEnabled Ext_raw_tex opts
1269− -> return $ literal str
1270− _ -> renderEmpty
1271−
1272−
1273−inlineToMarkdown opts LineBreak = do
1274− variant <- asks envVariant
1275− if variant == PlainText || isEnabled Ext_hard_line_breaks opts
1276− then return cr
1277− else return $
1278− if isEnabled Ext_escaped_line_breaks opts
1279− then "\\" <> cr
1280− else " " <> cr
1281−inlineToMarkdown _ Space = do
1282− escapeSpaces <- asks envEscapeSpaces
1283− return $ if escapeSpaces then "\\ " else space
1284−inlineToMarkdown opts SoftBreak = do
1285− escapeSpaces <- asks envEscapeSpaces
1286− let space' = if escapeSpaces then "\\ " else space
1287− return $ case writerWrapText opts of
1288− WrapNone -> space'
1289− WrapAuto -> space'
1290− WrapPreserve -> cr
1291−inlineToMarkdown opts (Cite [] lst) = inlineListToMarkdown opts lst
1292−inlineToMarkdown opts (Cite (c:cs) lst)
1293− | not (isEnabled Ext_citations opts) = inlineListToMarkdown opts lst
1294− | otherwise =
1295− if citationMode c == AuthorInText
1296− then do
1297− suffs <- inlineListToMarkdown opts $ citationSuffix c
1298− rest <- mapM convertOne cs
1299− let inbr = suffs <+> joincits rest
1300− br = if isEmpty inbr then empty else char '[' <> inbr <> char ']'
1301− return $ literal ("@" <> citationId c) <+> br
1302− else do
1303− cits <- mapM convertOne (c:cs)
1304− return $ literal "[" <> joincits cits <> literal "]"
1305− where
1306− joincits = hcat . intersperse (literal "; ") . filter (not . isEmpty)
1307− convertOne Citation { citationId = k
1308− , citationPrefix = pinlines
1309− , citationSuffix = sinlines
1310− , citationMode = m }
1311− = do
1312− pdoc <- inlineListToMarkdown opts pinlines
1313− sdoc <- inlineListToMarkdown opts sinlines
1314− let k' = literal (modekey m <> "@" <> k)
1315− r = case sinlines of
1316− Str (T.uncons -> Just (y,_)):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
1317− _ -> k' <+> sdoc
1318− return $ pdoc <+> r
1319− modekey SuppressAuthor = "-"
1320− modekey _ = ""
1321−inlineToMarkdown opts lnk@(Link attr txt (src, tit)) = do
1322− variant <- asks envVariant
1323− linktext <- inlineListToMarkdown opts txt
1324− let linktitle = if T.null tit
1325− then empty
1326− else literal $ " \"" <> tit <> "\""
1327− let srcSuffix = fromMaybe src (T.stripPrefix "mailto:" src)
1328− let useAuto = isURI src &&
1329− case txt of
1330− [Str s] | escapeURI s == srcSuffix -> True
1331− _ -> False
1332− let useRefLinks = writerReferenceLinks opts && not useAuto
1333− shortcutable <- asks envRefShortcutable
1334− let useShortcutRefLinks = shortcutable &&
1335− isEnabled Ext_shortcut_reference_links opts
1336− reftext <- if useRefLinks
1337− then literal <$> getReference attr linktext (src, tit)
1338− else return mempty
1339− case variant of
1340− PlainText
1341− | useAuto -> return $ literal srcSuffix
1342− | otherwise -> return linktext
1343− _ | useAuto -> return $ "<" <> literal srcSuffix <> ">"
1344− | useRefLinks ->
1345− let first = "[" <> linktext <> "]"
1346− second = if getKey linktext == getKey reftext
1347− then if useShortcutRefLinks
1348− then ""
1349− else "[]"
1350− else "[" <> reftext <> "]"
1351− in return $ first <> second
1352− | isEnabled Ext_raw_html opts
1353− , not (isEnabled Ext_link_attributes opts)
1354− , attr /= nullAttr -> -- use raw HTML to render attributes
1355− literal . T.strip <$>
1356− writeHtml5String opts{ writerTemplate = Nothing }
1357− (Pandoc nullMeta [Plain [lnk]])
1358− | otherwise -> return $
1359− "[" <> linktext <> "](" <> literal src <> linktitle <> ")" <>
1360− linkAttributes opts attr
1361−inlineToMarkdown opts img@(Image attr alternate (source, tit))
1362− | isEnabled Ext_raw_html opts &&
1363− not (isEnabled Ext_link_attributes opts) &&
1364− attr /= nullAttr = -- use raw HTML
1365− literal . T.strip <$>
1366− writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
1367− | otherwise = do
1368− variant <- asks envVariant
1369− let txt = if null alternate || alternate == [Str source]
1370− -- to prevent autolinks
1371− then [Str ""]
1372− else alternate
1373− linkPart <- inlineToMarkdown opts (Link attr txt (source, tit))
1374− return $ case variant of
1375− PlainText -> "[" <> linkPart <> "]"
1376− _ -> "!" <> linkPart
1377−inlineToMarkdown opts (Note contents) = do
1378− modify (\st -> st{ stNotes = contents : stNotes st })
1379− st <- get
1380− let ref = literal $ writerIdentifierPrefix opts <> tshow (stNoteNum st + length (stNotes st) - 1)
1381− if isEnabled Ext_footnotes opts
1382− then return $ "[^" <> ref <> "]"
1383− else return $ "[" <> ref <> "]"
1384−
1385−makeMathPlainer :: [Inline] -> [Inline]
1386−makeMathPlainer = walk go
1387− where
1388− go (Emph xs) = Span nullAttr xs
1389− go x = x
1390−
1391lineBreakToSpace :: Inline -> Inline
822lineBreakToSpace :: Inline -> Inline
1392lineBreakToSpace LineBreak = Space
823lineBreakToSpace LineBreak = Space
1393lineBreakToSpace SoftBreak = Space
824lineBreakToSpace SoftBreak = Space
1394lineBreakToSpace x = x
825lineBreakToSpace x = x
1395−
1396−toSubscriptInline :: Inline -> Maybe Inline
1397−toSubscriptInline Space = Just Space
1398−toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils
1399−toSubscriptInline (Str s) = Str . T.pack <$> traverse toSubscript (T.unpack s)
1400−toSubscriptInline LineBreak = Just LineBreak
1401−toSubscriptInline SoftBreak = Just SoftBreak
1402−toSubscriptInline _ = Nothing
1403−
1404−toSuperscriptInline :: Inline -> Maybe Inline
1405−toSuperscriptInline Space = Just Space
1406−toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils
1407−toSuperscriptInline (Str s) = Str . T.pack <$> traverse toSuperscript (T.unpack s)
1408−toSuperscriptInline LineBreak = Just LineBreak
1409−toSuperscriptInline SoftBreak = Just SoftBreak
1410−toSuperscriptInline _ = Nothing
src/Text/Pandoc/Writers/Markdown/Inline.hsnew file+601
@@ -0,0 +1,601 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE ViewPatterns #-}
4+{- |
5+ Module : Text.Pandoc.Writers.Markdown.Inline
6+ Copyright : Copyright (C) 2006-2021 John MacFarlane
7+ License : GNU GPL, version 2 or above
8+
9+ Maintainer : John MacFarlane <jgm@berkeley.edu>
10+ Stability : alpha
11+ Portability : portable
12+-}
13+module Text.Pandoc.Writers.Markdown.Inline (
14+ inlineListToMarkdown
15+ ) where
16+import Control.Monad.Reader
17+import Control.Monad.State.Strict
18+import Data.Char (isAlphaNum, isDigit)
19+import Data.List (find, intersperse)
20+import qualified Data.Map as M
21+import Data.Maybe (fromMaybe)
22+import Data.Text (Text)
23+import qualified Data.Text as T
24+import Network.HTTP (urlEncode)
25+import Text.Pandoc.Class.PandocMonad (PandocMonad, report)
26+import Text.Pandoc.Definition
27+import Text.Pandoc.Logging
28+import Text.Pandoc.Options
29+import Text.Pandoc.Parsing hiding (blankline, blanklines, char, space)
30+import Text.DocLayout
31+import Text.Pandoc.Shared
32+import Text.Pandoc.Writers.Shared
33+import Text.Pandoc.Walk
34+import Text.Pandoc.Writers.HTML (writeHtml5String)
35+import Text.Pandoc.Writers.Math (texMathToInlines)
36+import Text.Pandoc.XML (toHtml5Entities)
37+import Data.Coerce (coerce)
38+import Text.Pandoc.Writers.Markdown.Types (MarkdownVariant(..),
39+ WriterState(..),
40+ WriterEnv(..), MD)
41+
42+-- | Escape special characters for Markdown.
43+escapeText :: WriterOptions -> Text -> Text
44+escapeText opts = T.pack . go . T.unpack
45+ where
46+ go [] = []
47+ go (c:cs) =
48+ case c of
49+ '<' | isEnabled Ext_all_symbols_escapable opts ->
50+ '\\' : '<' : go cs
51+ | otherwise -> "&lt;" ++ go cs
52+ '>' | isEnabled Ext_all_symbols_escapable opts ->
53+ '\\' : '>' : go cs
54+ | otherwise -> "&gt;" ++ go cs
55+ '@' | isEnabled Ext_citations opts ->
56+ case cs of
57+ (d:_)
58+ | isAlphaNum d || d == '_'
59+ -> '\\':'@':go cs
60+ _ -> '@':go cs
61+ _ | c `elem` ['\\','`','*','_','[',']','#'] ->
62+ '\\':c:go cs
63+ '|' | isEnabled Ext_pipe_tables opts -> '\\':'|':go cs
64+ '^' | isEnabled Ext_superscript opts -> '\\':'^':go cs
65+ '~' | isEnabled Ext_subscript opts ||
66+ isEnabled Ext_strikeout opts -> '\\':'~':go cs
67+ '$' | isEnabled Ext_tex_math_dollars opts -> '\\':'$':go cs
68+ '\'' | isEnabled Ext_smart opts -> '\\':'\'':go cs
69+ '"' | isEnabled Ext_smart opts -> '\\':'"':go cs
70+ '-' | isEnabled Ext_smart opts ->
71+ case cs of
72+ '-':_ -> '\\':'-':go cs
73+ _ -> '-':go cs
74+ '.' | isEnabled Ext_smart opts ->
75+ case cs of
76+ '.':'.':rest -> '\\':'.':'.':'.':go rest
77+ _ -> '.':go cs
78+ _ -> case cs of
79+ '_':x:xs
80+ | isEnabled Ext_intraword_underscores opts
81+ , isAlphaNum c
82+ , isAlphaNum x -> c : '_' : x : go xs
83+ _ -> c : go cs
84+
85+attrsToMarkdown :: Attr -> Doc Text
86+attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
87+ where attribId = case attribs of
88+ ("",_,_) -> empty
89+ (i,_,_) -> "#" <> escAttr i
90+ attribClasses = case attribs of
91+ (_,[],_) -> empty
92+ (_,cs,_) -> hsep $
93+ map (escAttr . ("."<>))
94+ cs
95+ attribKeys = case attribs of
96+ (_,_,[]) -> empty
97+ (_,_,ks) -> hsep $
98+ map (\(k,v) -> escAttr k
99+ <> "=\"" <>
100+ escAttr v <> "\"") ks
101+ escAttr = mconcat . map escAttrChar . T.unpack
102+ escAttrChar '"' = literal "\\\""
103+ escAttrChar '\\' = literal "\\\\"
104+ escAttrChar c = literal $ T.singleton c
105+
106+linkAttributes :: WriterOptions -> Attr -> Doc Text
107+linkAttributes opts attr =
108+ if isEnabled Ext_link_attributes opts && attr /= nullAttr
109+ then attrsToMarkdown attr
110+ else empty
111+
112+getKey :: Doc Text -> Key
113+getKey = toKey . render Nothing
114+
115+findUsableIndex :: [Text] -> Int -> Int
116+findUsableIndex lbls i = if tshow i `elem` lbls
117+ then findUsableIndex lbls (i + 1)
118+ else i
119+
120+getNextIndex :: PandocMonad m => MD m Int
121+getNextIndex = do
122+ prevRefs <- gets stPrevRefs
123+ refs <- gets stRefs
124+ i <- (+ 1) <$> gets stLastIdx
125+ modify $ \s -> s{ stLastIdx = i }
126+ let refLbls = map (\(r,_,_) -> r) $ prevRefs ++ refs
127+ return $ findUsableIndex refLbls i
128+
129+-- | Get reference for target; if none exists, create unique one and return.
130+-- Prefer label if possible; otherwise, generate a unique key.
131+getReference :: PandocMonad m => Attr -> Doc Text -> Target -> MD m Text
132+getReference attr label target = do
133+ refs <- gets stRefs
134+ case find (\(_,t,a) -> t == target && a == attr) refs of
135+ Just (ref, _, _) -> return ref
136+ Nothing -> do
137+ keys <- gets stKeys
138+ let key = getKey label
139+ let rawkey = coerce key
140+ case M.lookup key keys of
141+ Nothing -> do -- no other refs with this label
142+ (lab', idx) <- if T.null rawkey ||
143+ T.length rawkey > 999 ||
144+ T.any (\c -> c == '[' || c == ']') rawkey
145+ then do
146+ i <- getNextIndex
147+ return (tshow i, i)
148+ else
149+ return (render Nothing label, 0)
150+ modify (\s -> s{
151+ stRefs = (lab', target, attr) : refs,
152+ stKeys = M.insert (getKey label)
153+ (M.insert (target, attr) idx mempty)
154+ (stKeys s) })
155+ return lab'
156+
157+ Just km -> -- we have refs with this label
158+ case M.lookup (target, attr) km of
159+ Just i -> do
160+ let lab' = render Nothing $
161+ label <> if i == 0
162+ then mempty
163+ else literal (tshow i)
164+ -- make sure it's in stRefs; it may be
165+ -- a duplicate that was printed in a previous
166+ -- block:
167+ when ((lab', target, attr) `notElem` refs) $
168+ modify (\s -> s{
169+ stRefs = (lab', target, attr) : refs })
170+ return lab'
171+ Nothing -> do -- but this one is to a new target
172+ i <- getNextIndex
173+ let lab' = tshow i
174+ modify (\s -> s{
175+ stRefs = (lab', target, attr) : refs,
176+ stKeys = M.insert key
177+ (M.insert (target, attr) i km)
178+ (stKeys s) })
179+ return lab'
180+
181+-- | Convert list of Pandoc inline elements to markdown.
182+inlineListToMarkdown :: PandocMonad m => WriterOptions -> [Inline] -> MD m (Doc Text)
183+inlineListToMarkdown opts lst = do
184+ inlist <- asks envInList
185+ go (if inlist then avoidBadWrapsInList lst else lst)
186+ where go [] = return empty
187+ go (x@Math{}:y@(Str t):zs)
188+ | T.all isDigit (T.take 1 t) -- starts with digit -- see #7058
189+ = liftM2 (<>) (inlineToMarkdown opts x)
190+ (go (RawInline (Format "html") "<!-- -->" : y : zs))
191+ go (i:is) = case i of
192+ Link {} -> case is of
193+ -- If a link is followed by another link, or '[', '(' or ':'
194+ -- then we don't shortcut
195+ Link {}:_ -> unshortcutable
196+ Space:Link {}:_ -> unshortcutable
197+ Space:(Str(thead -> Just '[')):_ -> unshortcutable
198+ Space:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
199+ Space:(Cite _ _):_ -> unshortcutable
200+ SoftBreak:Link {}:_ -> unshortcutable
201+ SoftBreak:(Str(thead -> Just '[')):_ -> unshortcutable
202+ SoftBreak:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
203+ SoftBreak:(Cite _ _):_ -> unshortcutable
204+ LineBreak:Link {}:_ -> unshortcutable
205+ LineBreak:(Str(thead -> Just '[')):_ -> unshortcutable
206+ LineBreak:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
207+ LineBreak:(Cite _ _):_ -> unshortcutable
208+ (Cite _ _):_ -> unshortcutable
209+ Str (thead -> Just '['):_ -> unshortcutable
210+ Str (thead -> Just '('):_ -> unshortcutable
211+ Str (thead -> Just ':'):_ -> unshortcutable
212+ (RawInline _ (thead -> Just '[')):_ -> unshortcutable
213+ (RawInline _ (thead -> Just '(')):_ -> unshortcutable
214+ (RawInline _ (thead -> Just ':')):_ -> unshortcutable
215+ (RawInline _ (T.stripPrefix " [" -> Just _ )):_ -> unshortcutable
216+ _ -> shortcutable
217+ _ -> shortcutable
218+ where shortcutable = liftM2 (<>) (inlineToMarkdown opts i) (go is)
219+ unshortcutable = do
220+ iMark <- local
221+ (\env -> env { envRefShortcutable = False })
222+ (inlineToMarkdown opts i)
223+ fmap (iMark <>) (go is)
224+ thead = fmap fst . T.uncons
225+
226+isSp :: Inline -> Bool
227+isSp Space = True
228+isSp SoftBreak = True
229+isSp _ = False
230+
231+avoidBadWrapsInList :: [Inline] -> [Inline]
232+avoidBadWrapsInList [] = []
233+avoidBadWrapsInList (s:Str (T.uncons -> Just ('>',cs)):xs) | isSp s =
234+ Str (" >" <> cs) : avoidBadWrapsInList xs
235+avoidBadWrapsInList [s, Str (T.uncons -> Just (c, cs))]
236+ | T.null cs && isSp s && c `elem` ['-','*','+'] = [Str $ T.pack [' ', c]]
237+avoidBadWrapsInList (s:Str (T.uncons -> Just (c, cs)):Space:xs)
238+ | T.null cs && isSp s && c `elem` ['-','*','+'] =
239+ Str (T.pack [' ', c]) : Space : avoidBadWrapsInList xs
240+avoidBadWrapsInList (s:Str cs:Space:xs)
241+ | isSp s && isOrderedListMarker cs =
242+ Str (" " <> cs) : Space : avoidBadWrapsInList xs
243+avoidBadWrapsInList [s, Str cs]
244+ | isSp s && isOrderedListMarker cs = [Str $ " " <> cs]
245+avoidBadWrapsInList (x:xs) = x : avoidBadWrapsInList xs
246+
247+isOrderedListMarker :: Text -> Bool
248+isOrderedListMarker xs = not (T.null xs) && (T.last xs `elem` ['.',')']) &&
249+ isRight (runParser (anyOrderedListMarker >> eof)
250+ defaultParserState "" xs)
251+ where
252+ isRight (Right _) = True
253+ isRight (Left _) = False
254+
255+-- | Convert Pandoc inline element to markdown.
256+inlineToMarkdown :: PandocMonad m => WriterOptions -> Inline -> MD m (Doc Text)
257+inlineToMarkdown opts (Span ("",["emoji"],kvs) [Str s]) =
258+ case lookup "data-emoji" kvs of
259+ Just emojiname | isEnabled Ext_emoji opts ->
260+ return $ ":" <> literal emojiname <> ":"
261+ _ -> inlineToMarkdown opts (Str s)
262+inlineToMarkdown opts (Span attrs ils) = do
263+ variant <- asks envVariant
264+ contents <- inlineListToMarkdown opts ils
265+ return $ case attrs of
266+ (_,["csl-block"],_) -> (cr <>)
267+ (_,["csl-left-margin"],_) -> (cr <>)
268+ (_,["csl-indent"],_) -> (cr <>)
269+ _ -> id
270+ $ case variant of
271+ PlainText -> contents
272+ _ | attrs == nullAttr -> contents
273+ | isEnabled Ext_bracketed_spans opts ->
274+ let attrs' = if attrs /= nullAttr
275+ then attrsToMarkdown attrs
276+ else empty
277+ in "[" <> contents <> "]" <> attrs'
278+ | isEnabled Ext_raw_html opts ||
279+ isEnabled Ext_native_spans opts ->
280+ tagWithAttrs "span" attrs <> contents <> literal "</span>"
281+ | otherwise -> contents
282+inlineToMarkdown _ (Emph []) = return empty
283+inlineToMarkdown opts (Emph lst) = do
284+ variant <- asks envVariant
285+ contents <- inlineListToMarkdown opts lst
286+ return $ case variant of
287+ PlainText
288+ | isEnabled Ext_gutenberg opts -> "_" <> contents <> "_"
289+ | otherwise -> contents
290+ _ -> "*" <> contents <> "*"
291+inlineToMarkdown _ (Underline []) = return empty
292+inlineToMarkdown opts (Underline lst) = do
293+ variant <- asks envVariant
294+ contents <- inlineListToMarkdown opts lst
295+ case variant of
296+ PlainText -> return contents
297+ _ | isEnabled Ext_bracketed_spans opts ->
298+ return $ "[" <> contents <> "]" <> "{.ul}"
299+ | isEnabled Ext_native_spans opts ->
300+ return $ tagWithAttrs "span" ("", ["underline"], [])
301+ <> contents
302+ <> literal "</span>"
303+ | isEnabled Ext_raw_html opts ->
304+ return $ "<u>" <> contents <> "</u>"
305+ | otherwise -> inlineToMarkdown opts (Emph lst)
306+inlineToMarkdown _ (Strong []) = return empty
307+inlineToMarkdown opts (Strong lst) = do
308+ variant <- asks envVariant
309+ case variant of
310+ PlainText ->
311+ inlineListToMarkdown opts $
312+ if isEnabled Ext_gutenberg opts
313+ then capitalize lst
314+ else lst
315+ _ -> do
316+ contents <- inlineListToMarkdown opts lst
317+ return $ "**" <> contents <> "**"
318+inlineToMarkdown _ (Strikeout []) = return empty
319+inlineToMarkdown opts (Strikeout lst) = do
320+ contents <- inlineListToMarkdown opts lst
321+ return $ if isEnabled Ext_strikeout opts
322+ then "~~" <> contents <> "~~"
323+ else if isEnabled Ext_raw_html opts
324+ then "<s>" <> contents <> "</s>"
325+ else contents
326+inlineToMarkdown _ (Superscript []) = return empty
327+inlineToMarkdown opts (Superscript lst) =
328+ local (\env -> env {envEscapeSpaces = envVariant env == Markdown}) $ do
329+ contents <- inlineListToMarkdown opts lst
330+ if isEnabled Ext_superscript opts
331+ then return $ "^" <> contents <> "^"
332+ else if isEnabled Ext_raw_html opts
333+ then return $ "<sup>" <> contents <> "</sup>"
334+ else
335+ case traverse toSuperscriptInline lst of
336+ Just xs' | not (writerPreferAscii opts)
337+ -> inlineListToMarkdown opts xs'
338+ _ -> do
339+ let rendered = render Nothing contents
340+ return $
341+ case mapM toSuperscript (T.unpack rendered) of
342+ Just r -> literal $ T.pack r
343+ Nothing -> literal $ "^(" <> rendered <> ")"
344+inlineToMarkdown _ (Subscript []) = return empty
345+inlineToMarkdown opts (Subscript lst) =
346+ local (\env -> env {envEscapeSpaces = envVariant env == Markdown}) $ do
347+ contents <- inlineListToMarkdown opts lst
348+ if isEnabled Ext_subscript opts
349+ then return $ "~" <> contents <> "~"
350+ else if isEnabled Ext_raw_html opts
351+ then return $ "<sub>" <> contents <> "</sub>"
352+ else
353+ case traverse toSubscriptInline lst of
354+ Just xs' | not (writerPreferAscii opts)
355+ -> inlineListToMarkdown opts xs'
356+ _ -> do
357+ let rendered = render Nothing contents
358+ return $
359+ case mapM toSuperscript (T.unpack rendered) of
360+ Just r -> literal $ T.pack r
361+ Nothing -> literal $ "_(" <> rendered <> ")"
362+inlineToMarkdown opts (SmallCaps lst) = do
363+ variant <- asks envVariant
364+ if variant /= PlainText &&
365+ (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
366+ then inlineToMarkdown opts (Span ("",["smallcaps"],[]) lst)
367+ else inlineListToMarkdown opts $ capitalize lst
368+inlineToMarkdown opts (Quoted SingleQuote lst) = do
369+ contents <- inlineListToMarkdown opts lst
370+ return $ if isEnabled Ext_smart opts
371+ then "'" <> contents <> "'"
372+ else
373+ if writerPreferAscii opts
374+ then "&lsquo;" <> contents <> "&rsquo;"
375+ else "‘" <> contents <> "’"
376+inlineToMarkdown opts (Quoted DoubleQuote lst) = do
377+ contents <- inlineListToMarkdown opts lst
378+ return $ if isEnabled Ext_smart opts
379+ then "\"" <> contents <> "\""
380+ else
381+ if writerPreferAscii opts
382+ then "&ldquo;" <> contents <> "&rdquo;"
383+ else "“" <> contents <> "”"
384+inlineToMarkdown opts (Code attr str) = do
385+ let tickGroups = filter (T.any (== '`')) $ T.group str
386+ let longest = if null tickGroups
387+ then 0
388+ else maximum $ map T.length tickGroups
389+ let marker = T.replicate (longest + 1) "`"
390+ let spacer = if longest == 0 then "" else " "
391+ let attrs = if isEnabled Ext_inline_code_attributes opts && attr /= nullAttr
392+ then attrsToMarkdown attr
393+ else empty
394+ variant <- asks envVariant
395+ case variant of
396+ PlainText -> return $ literal str
397+ _ -> return $ literal
398+ (marker <> spacer <> str <> spacer <> marker) <> attrs
399+inlineToMarkdown opts (Str str) = do
400+ variant <- asks envVariant
401+ let str' = (if writerPreferAscii opts
402+ then toHtml5Entities
403+ else id) .
404+ (if isEnabled Ext_smart opts
405+ then unsmartify opts
406+ else id) .
407+ (if variant == PlainText
408+ then id
409+ else escapeText opts) $ str
410+ return $ literal str'
411+inlineToMarkdown opts (Math InlineMath str) =
412+ case writerHTMLMathMethod opts of
413+ WebTeX url -> inlineToMarkdown opts
414+ (Image nullAttr [Str str] (url <> T.pack (urlEncode $ T.unpack str), str))
415+ _ | isEnabled Ext_tex_math_dollars opts ->
416+ return $ "$" <> literal str <> "$"
417+ | isEnabled Ext_tex_math_single_backslash opts ->
418+ return $ "\\(" <> literal str <> "\\)"
419+ | isEnabled Ext_tex_math_double_backslash opts ->
420+ return $ "\\\\(" <> literal str <> "\\\\)"
421+ | otherwise -> do
422+ variant <- asks envVariant
423+ texMathToInlines InlineMath str >>=
424+ inlineListToMarkdown opts .
425+ (if variant == PlainText then makeMathPlainer else id)
426+inlineToMarkdown opts (Math DisplayMath str) =
427+ case writerHTMLMathMethod opts of
428+ WebTeX url -> (\x -> blankline <> x <> blankline) `fmap`
429+ inlineToMarkdown opts (Image nullAttr [Str str]
430+ (url <> T.pack (urlEncode $ T.unpack str), str))
431+ _ | isEnabled Ext_tex_math_dollars opts ->
432+ return $ "$$" <> literal str <> "$$"
433+ | isEnabled Ext_tex_math_single_backslash opts ->
434+ return $ "\\[" <> literal str <> "\\]"
435+ | isEnabled Ext_tex_math_double_backslash opts ->
436+ return $ "\\\\[" <> literal str <> "\\\\]"
437+ | otherwise -> (\x -> cr <> x <> cr) `fmap`
438+ (texMathToInlines DisplayMath str >>= inlineListToMarkdown opts)
439+inlineToMarkdown opts il@(RawInline f str) = do
440+ let tickGroups = filter (T.any (== '`')) $ T.group str
441+ let numticks = if null tickGroups
442+ then 1
443+ else 1 + maximum (map T.length tickGroups)
444+ variant <- asks envVariant
445+ let Format fmt = f
446+ let rawAttribInline = return $
447+ literal (T.replicate numticks "`") <> literal str <>
448+ literal (T.replicate numticks "`") <> literal "{=" <> literal fmt <> literal "}"
449+ let renderEmpty = mempty <$ report (InlineNotRendered il)
450+ case variant of
451+ PlainText -> renderEmpty
452+ Commonmark
453+ | f `elem` ["gfm", "commonmark", "commonmark_x", "markdown"]
454+ -> return $ literal str
455+ Markdown
456+ | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
457+ "markdown_mmd", "markdown_strict"]
458+ -> return $ literal str
459+ _ | isEnabled Ext_raw_attribute opts -> rawAttribInline
460+ | f `elem` ["html", "html5", "html4"]
461+ , isEnabled Ext_raw_html opts
462+ -> return $ literal str
463+ | f `elem` ["latex", "tex"]
464+ , isEnabled Ext_raw_tex opts
465+ -> return $ literal str
466+ _ -> renderEmpty
467+
468+
469+inlineToMarkdown opts LineBreak = do
470+ variant <- asks envVariant
471+ if variant == PlainText || isEnabled Ext_hard_line_breaks opts
472+ then return cr
473+ else return $
474+ if isEnabled Ext_escaped_line_breaks opts
475+ then "\\" <> cr
476+ else " " <> cr
477+inlineToMarkdown _ Space = do
478+ escapeSpaces <- asks envEscapeSpaces
479+ return $ if escapeSpaces then "\\ " else space
480+inlineToMarkdown opts SoftBreak = do
481+ escapeSpaces <- asks envEscapeSpaces
482+ let space' = if escapeSpaces then "\\ " else space
483+ return $ case writerWrapText opts of
484+ WrapNone -> space'
485+ WrapAuto -> space'
486+ WrapPreserve -> cr
487+inlineToMarkdown opts (Cite [] lst) = inlineListToMarkdown opts lst
488+inlineToMarkdown opts (Cite (c:cs) lst)
489+ | not (isEnabled Ext_citations opts) = inlineListToMarkdown opts lst
490+ | otherwise =
491+ if citationMode c == AuthorInText
492+ then do
493+ suffs <- inlineListToMarkdown opts $ citationSuffix c
494+ rest <- mapM convertOne cs
495+ let inbr = suffs <+> joincits rest
496+ br = if isEmpty inbr then empty else char '[' <> inbr <> char ']'
497+ return $ literal ("@" <> citationId c) <+> br
498+ else do
499+ cits <- mapM convertOne (c:cs)
500+ return $ literal "[" <> joincits cits <> literal "]"
501+ where
502+ joincits = hcat . intersperse (literal "; ") . filter (not . isEmpty)
503+ convertOne Citation { citationId = k
504+ , citationPrefix = pinlines
505+ , citationSuffix = sinlines
506+ , citationMode = m }
507+ = do
508+ pdoc <- inlineListToMarkdown opts pinlines
509+ sdoc <- inlineListToMarkdown opts sinlines
510+ let k' = literal (modekey m <> "@" <> k)
511+ r = case sinlines of
512+ Str (T.uncons -> Just (y,_)):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
513+ _ -> k' <+> sdoc
514+ return $ pdoc <+> r
515+ modekey SuppressAuthor = "-"
516+ modekey _ = ""
517+inlineToMarkdown opts lnk@(Link attr txt (src, tit)) = do
518+ variant <- asks envVariant
519+ linktext <- inlineListToMarkdown opts txt
520+ let linktitle = if T.null tit
521+ then empty
522+ else literal $ " \"" <> tit <> "\""
523+ let srcSuffix = fromMaybe src (T.stripPrefix "mailto:" src)
524+ let useAuto = isURI src &&
525+ case txt of
526+ [Str s] | escapeURI s == srcSuffix -> True
527+ _ -> False
528+ let useRefLinks = writerReferenceLinks opts && not useAuto
529+ shortcutable <- asks envRefShortcutable
530+ let useShortcutRefLinks = shortcutable &&
531+ isEnabled Ext_shortcut_reference_links opts
532+ reftext <- if useRefLinks
533+ then literal <$> getReference attr linktext (src, tit)
534+ else return mempty
535+ case variant of
536+ PlainText
537+ | useAuto -> return $ literal srcSuffix
538+ | otherwise -> return linktext
539+ _ | useAuto -> return $ "<" <> literal srcSuffix <> ">"
540+ | useRefLinks ->
541+ let first = "[" <> linktext <> "]"
542+ second = if getKey linktext == getKey reftext
543+ then if useShortcutRefLinks
544+ then ""
545+ else "[]"
546+ else "[" <> reftext <> "]"
547+ in return $ first <> second
548+ | isEnabled Ext_raw_html opts
549+ , not (isEnabled Ext_link_attributes opts)
550+ , attr /= nullAttr -> -- use raw HTML to render attributes
551+ literal . T.strip <$>
552+ writeHtml5String opts{ writerTemplate = Nothing }
553+ (Pandoc nullMeta [Plain [lnk]])
554+ | otherwise -> return $
555+ "[" <> linktext <> "](" <> literal src <> linktitle <> ")" <>
556+ linkAttributes opts attr
557+inlineToMarkdown opts img@(Image attr alternate (source, tit))
558+ | isEnabled Ext_raw_html opts &&
559+ not (isEnabled Ext_link_attributes opts) &&
560+ attr /= nullAttr = -- use raw HTML
561+ literal . T.strip <$>
562+ writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
563+ | otherwise = do
564+ variant <- asks envVariant
565+ let txt = if null alternate || alternate == [Str source]
566+ -- to prevent autolinks
567+ then [Str ""]
568+ else alternate
569+ linkPart <- inlineToMarkdown opts (Link attr txt (source, tit))
570+ return $ case variant of
571+ PlainText -> "[" <> linkPart <> "]"
572+ _ -> "!" <> linkPart
573+inlineToMarkdown opts (Note contents) = do
574+ modify (\st -> st{ stNotes = contents : stNotes st })
575+ st <- get
576+ let ref = literal $ writerIdentifierPrefix opts <> tshow (stNoteNum st + length (stNotes st) - 1)
577+ if isEnabled Ext_footnotes opts
578+ then return $ "[^" <> ref <> "]"
579+ else return $ "[" <> ref <> "]"
580+
581+makeMathPlainer :: [Inline] -> [Inline]
582+makeMathPlainer = walk go
583+ where
584+ go (Emph xs) = Span nullAttr xs
585+ go x = x
586+
587+toSubscriptInline :: Inline -> Maybe Inline
588+toSubscriptInline Space = Just Space
589+toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils
590+toSubscriptInline (Str s) = Str . T.pack <$> traverse toSubscript (T.unpack s)
591+toSubscriptInline LineBreak = Just LineBreak
592+toSubscriptInline SoftBreak = Just SoftBreak
593+toSubscriptInline _ = Nothing
594+
595+toSuperscriptInline :: Inline -> Maybe Inline
596+toSuperscriptInline Space = Just Space
597+toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils
598+toSuperscriptInline (Str s) = Str . T.pack <$> traverse toSuperscript (T.unpack s)
599+toSuperscriptInline LineBreak = Just LineBreak
600+toSuperscriptInline SoftBreak = Just SoftBreak
601+toSuperscriptInline _ = Nothing
src/Text/Pandoc/Writers/Markdown/Types.hsnew file+81
@@ -0,0 +1,81 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{- |
3+ Module : Text.Pandoc.Writers.Markdown.Types
4+ Copyright : Copyright (C) 2006-2021 John MacFarlane
5+ License : GNU GPL, version 2 or above
6+
7+ Maintainer : John MacFarlane <jgm@berkeley.edu>
8+ Stability : alpha
9+ Portability : portable
10+-}
11+module Text.Pandoc.Writers.Markdown.Types (
12+ MarkdownVariant(..),
13+ WriterState(..),
14+ WriterEnv(..),
15+ Notes,
16+ Ref,
17+ Refs,
18+ MD,
19+ evalMD
20+ ) where
21+import Control.Monad.Reader
22+import Control.Monad.State.Strict
23+import Data.Default
24+import qualified Data.Map as M
25+import qualified Data.Set as Set
26+import Data.Text (Text)
27+import Text.Pandoc.Parsing (Key)
28+import Text.Pandoc.Class.PandocMonad (PandocMonad)
29+import Text.Pandoc.Definition
30+
31+type Notes = [[Block]]
32+type Ref = (Text, Target, Attr)
33+type Refs = [Ref]
34+
35+type MD m = ReaderT WriterEnv (StateT WriterState m)
36+
37+evalMD :: PandocMonad m => MD m a -> WriterEnv -> WriterState -> m a
38+evalMD md env st = evalStateT (runReaderT md env) st
39+
40+data WriterEnv = WriterEnv { envInList :: Bool
41+ , envVariant :: MarkdownVariant
42+ , envRefShortcutable :: Bool
43+ , envBlockLevel :: Int
44+ , envEscapeSpaces :: Bool
45+ }
46+
47+data MarkdownVariant =
48+ PlainText
49+ | Commonmark
50+ | Markdown
51+ deriving (Show, Eq)
52+
53+instance Default WriterEnv
54+ where def = WriterEnv { envInList = False
55+ , envVariant = Markdown
56+ , envRefShortcutable = True
57+ , envBlockLevel = 0
58+ , envEscapeSpaces = False
59+ }
60+
61+data WriterState = WriterState { stNotes :: Notes
62+ , stPrevRefs :: Refs
63+ , stRefs :: Refs
64+ , stKeys :: M.Map Key
65+ (M.Map (Target, Attr) Int)
66+ , stLastIdx :: Int
67+ , stIds :: Set.Set Text
68+ , stNoteNum :: Int
69+ }
70+
71+instance Default WriterState
72+ where def = WriterState{ stNotes = []
73+ , stPrevRefs = []
74+ , stRefs = []
75+ , stKeys = M.empty
76+ , stLastIdx = 0
77+ , stIds = Set.empty
78+ , stNoteNum = 1
79+ }
80+
81+
stack.yaml+1−10
@@ -7,20 +7,11 @@ packages:
7extra-deps:
7extra-deps:
8- hslua-1.3.0
8- hslua-1.3.0
9- hslua-module-path-0.1.0
9- hslua-module-path-0.1.0
10−- jira-wiki-markup-1.3.3
11−- commonmark-0.1.1.4
12−- commonmark-extensions-0.2.0.4
13−- commonmark-pandoc-0.2.0.1
14−- tasty-bench-0.2.1
15−- citeproc-0.3.0.7
16−- skylighting-0.10.4
17−- skylighting-core-0.10.4
18−- xml-conduit-1.9.1.0
19#- citeproc:
10#- citeproc:
20# git: https://github.com/jgm/citeproc.git
11# git: https://github.com/jgm/citeproc.git
21# commit: feb3b7580c6738eec3b23921f7c1739cfba611aa
12# commit: feb3b7580c6738eec3b23921f7c1739cfba611aa
22ghc-options:
13ghc-options:
23 "$locals": -fhide-source-paths -Wno-missing-home-modules
14 "$locals": -fhide-source-paths -Wno-missing-home-modules
24−resolver: lts-17.2
15+resolver: lts-17.5
25nix:
16nix:
26 packages: [zlib]
17 packages: [zlib]
trypandoc/trypandoc.hs−4
@@ -14,16 +14,12 @@ module Main where
14import Network.Wai.Handler.CGI
14import Network.Wai.Handler.CGI
15import Network.Wai.Middleware.Timeout (timeout)
15import Network.Wai.Middleware.Timeout (timeout)
16import Network.Wai
16import Network.Wai
17−import Control.Applicative ((<$>))
18import Data.Maybe (fromMaybe)
17import Data.Maybe (fromMaybe)
19import Network.HTTP.Types.Status (status200)
18import Network.HTTP.Types.Status (status200)
20import Network.HTTP.Types.Header (hContentType)
19import Network.HTTP.Types.Header (hContentType)
21import Network.HTTP.Types.URI (queryToQueryText)
20import Network.HTTP.Types.URI (queryToQueryText)
22import Text.Pandoc
21import Text.Pandoc
23−import Text.Pandoc.Writers.Math (defaultMathJaxURL)
24import Text.Pandoc.Highlighting (pygments)
22import Text.Pandoc.Highlighting (pygments)
25−import Text.Pandoc.Readers (getReader, Reader(..))
26−import Text.Pandoc.Writers (getWriter, Writer(..))
27import Text.Pandoc.Shared (tabFilter)
23import Text.Pandoc.Shared (tabFilter)
28import Data.Aeson
24import Data.Aeson
29import qualified Data.Text as T
25import qualified Data.Text as T