From 52240ea5de91a9d60efe6f2b17d310f8c4ab7baa Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Mon, 17 May 2021 22:12:18 +0200 Subject: [PATCH] Add complex-paragraphs --- complex-paragraphs/Makefile | 12 ++++ complex-paragraphs/README.md | 44 +++++++++++++ complex-paragraphs/complex-paragraphs.lua | 75 +++++++++++++++++++++++ complex-paragraphs/sample.md | 36 +++++++++++ complex-paragraphs/tests/expected.context | 19 ++++++ complex-paragraphs/tests/expected.docx | 19 ++++++ complex-paragraphs/tests/expected.latex | 19 ++++++ 7 files changed, 224 insertions(+) create mode 100644 complex-paragraphs/Makefile create mode 100644 complex-paragraphs/README.md create mode 100644 complex-paragraphs/complex-paragraphs.lua create mode 100644 complex-paragraphs/sample.md create mode 100644 complex-paragraphs/tests/expected.context create mode 100644 complex-paragraphs/tests/expected.docx create mode 100644 complex-paragraphs/tests/expected.latex diff --git a/complex-paragraphs/Makefile b/complex-paragraphs/Makefile new file mode 100644 index 00000000..081c086b --- /dev/null +++ b/complex-paragraphs/Makefile @@ -0,0 +1,12 @@ +.PHONY: test + +PANDOC_COMMAND = pandoc -L complex-paragraphs.lua -t native sample.md + +test: + TESTED_FORMAT=context $(PANDOC_COMMAND) -o tests/output.context \ + && diff tests/output.context tests/expected.context + TESTED_FORMAT=openxml $(PANDOC_COMMAND) -o tests/output.docx \ + && diff tests/output.docx tests/expected.docx + TESTED_FORMAT=latex $(PANDOC_COMMAND) -o tests/output.latex \ + && diff tests/output.latex tests/expected.latex \ + && rm tests/output.* diff --git a/complex-paragraphs/README.md b/complex-paragraphs/README.md new file mode 100644 index 00000000..868020eb --- /dev/null +++ b/complex-paragraphs/README.md @@ -0,0 +1,44 @@ +# Compose complex paragraphs + +## Definition + +Complex paragraphs are paragraphs composed of different blocks: +normal text, quotations, tables,... + +This concept makes sense only if you want to indent all paragraphs +by default, including paragraphs beginning after a quotation block +or a table, for instance. In that case, unindenting a text block means +that it is not to be seen as a new paragraph, but as a the +continuation of the previous text block that has been interrupted by +another block. If you want to prevent the indentation of all +paragraphs following certain types of blocks, please consider using +the [first-line-indent] filter instead. + +[first-line-indent]: https://github.com/pandoc/lua-filters/tree/master/first-line-indent + +## How to use this filter + +To create a complex paragraph in your MD file, simply wrap its +components in a Div with class `.complex-paragraph`. Some +examples are given in `sample.md`. + +## What it does + +For the moment, it only prevents the indentation of text blocks +other than the first one. More features can be requested. + +The Div itself is not removed from the AST, so that you can +pass it through other filters. + +## Output formats + +The following output formats are supported: + + * context + * docx + * latex + +Other formats can be added. PRs are welcome. If you prefer to +submit an issue instead, please specify what code should be +used in the targeted format in order to achieve what this filter +does. diff --git a/complex-paragraphs/complex-paragraphs.lua b/complex-paragraphs/complex-paragraphs.lua new file mode 100644 index 00000000..02e604a6 --- /dev/null +++ b/complex-paragraphs/complex-paragraphs.lua @@ -0,0 +1,75 @@ +--[[ +complex-paragraphs – compose complex paragraphs + +Copyright © 2021 Bastien Dumont + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +]] + +local is_after_first_block +local RAW_ATTRIBUTE + +if FORMAT == 'native' then + RAW_ATTRIBUTE = pandoc.system.environment().TESTED_FORMAT +elseif FORMAT == 'docx' then + RAW_ATTRIBUTE = 'openxml' +elseif FORMAT == 'context' or FORMAT == 'latex' then + RAW_ATTRIBUTE = FORMAT +else + error(FORMAT .. + ' output not supported by complex-paragraphs.lua\n') +end + +local function make_noindent_code() + if RAW_ATTRIBUTE == 'context' then + return '\\noindentation{}' + elseif RAW_ATTRIBUTE == 'openxml' then + return '' .. + '' .. + '' .. + '' + elseif RAW_ATTRIBUTE == 'latex' then + return '\\noindent{}' + end +end + +local noindent_rawinline = + pandoc.RawInline(RAW_ATTRIBUTE, make_noindent_code()) + +local function turn_to_nonindented_textblock(para) + para.c:insert(1, noindent_rawinline) +end + +local function unindent_paragraphs_after_first_block_in_complex_para(blocks) + for i = 1, #blocks do + block = blocks[i] + if block.t == 'Para' and is_after_first_block then + turn_to_nonindented_textblock(block) + elseif block.t == 'Div' then + unindent_paragraphs_after_first_block_in_complex_para(block.content) + end + is_after_first_block = true + end +end + +local function turn_to_complex_paragraph(div) + unindent_paragraphs_after_first_block_in_complex_para(div.content) +end + +function Div(div) + if div.classes[1] == 'complex-paragraph' then + is_after_first_block = false + turn_to_complex_paragraph(div) + return div + end +end diff --git a/complex-paragraphs/sample.md b/complex-paragraphs/sample.md new file mode 100644 index 00000000..331162a9 --- /dev/null +++ b/complex-paragraphs/sample.md @@ -0,0 +1,36 @@ +_Let's begin with a simple test case:_ + +::: {.complex-paragraph} +When Clovis came in front of the soldier, he smashed his head with +his axe, saying: + + > Remember the vase at Soissons! + +This was an allusion to the vase that the soldier had broken so that +it could not be returned to Remigius. +::: + +_It is not necessary for the first block to be normal text:_ + +::: {.complex-paragraph} + > Remember the vase at Soissons! + +This was an allusion to the vase that the soldier had broken so that +it could not be returned to Remigius. +::: + +_Nested Divs are supported:_ + +::: {.complex-paragraph} +::: {.narrative} +When Clovis came in front of the soldier, he smashed his head with +his axe, saying: + + > Remember the vase at Soissons! +::: +::: {.explanation} +This was an allusion to the vase that the soldier had broken so that +it could not be returned to Remigius. +::: +::: + diff --git a/complex-paragraphs/tests/expected.context b/complex-paragraphs/tests/expected.context new file mode 100644 index 00000000..0c63972b --- /dev/null +++ b/complex-paragraphs/tests/expected.context @@ -0,0 +1,19 @@ +[Para [Emph [Str "Let\8217s",Space,Str "begin",Space,Str "with",Space,Str "a",Space,Str "simple",Space,Str "test",Space,Str "case:"]] +,Div ("",["complex-paragraph"],[]) + [Para [Str "When",Space,Str "Clovis",Space,Str "came",Space,Str "in",Space,Str "front",Space,Str "of",Space,Str "the",Space,Str "soldier,",Space,Str "he",Space,Str "smashed",Space,Str "his",Space,Str "head",Space,Str "with",SoftBreak,Str "his",Space,Str "axe,",Space,Str "saying:"] + ,BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]] + ,Para [RawInline (Format "context") "\\noindentation{}",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]] +,Para [Emph [Str "It",Space,Str "is",Space,Str "not",Space,Str "necessary",Space,Str "for",Space,Str "the",Space,Str "first",Space,Str "block",Space,Str "to",Space,Str "be",Space,Str "normal",Space,Str "text:"]] +,Div ("",["complex-paragraph"],[]) + [BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]] + ,Para [RawInline (Format "context") "\\noindentation{}",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]] +,Para [Emph [Str "Nested",Space,Str "Divs",Space,Str "are",Space,Str "supported:"]] +,Div ("",["complex-paragraph"],[]) + [Div ("",["narrative"],[]) + [Para [Str "When",Space,Str "Clovis",Space,Str "came",Space,Str "in",Space,Str "front",Space,Str "of",Space,Str "the",Space,Str "soldier,",Space,Str "he",Space,Str "smashed",Space,Str "his",Space,Str "head",Space,Str "with",SoftBreak,Str "his",Space,Str "axe,",Space,Str "saying:"] + ,BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]]] + ,Div ("",["explanation"],[]) + [Para [RawInline (Format "context") "\\noindentation{}",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]]]] diff --git a/complex-paragraphs/tests/expected.docx b/complex-paragraphs/tests/expected.docx new file mode 100644 index 00000000..62eb4ff1 --- /dev/null +++ b/complex-paragraphs/tests/expected.docx @@ -0,0 +1,19 @@ +[Para [Emph [Str "Let\8217s",Space,Str "begin",Space,Str "with",Space,Str "a",Space,Str "simple",Space,Str "test",Space,Str "case:"]] +,Div ("",["complex-paragraph"],[]) + [Para [Str "When",Space,Str "Clovis",Space,Str "came",Space,Str "in",Space,Str "front",Space,Str "of",Space,Str "the",Space,Str "soldier,",Space,Str "he",Space,Str "smashed",Space,Str "his",Space,Str "head",Space,Str "with",SoftBreak,Str "his",Space,Str "axe,",Space,Str "saying:"] + ,BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]] + ,Para [RawInline (Format "openxml") "",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]] +,Para [Emph [Str "It",Space,Str "is",Space,Str "not",Space,Str "necessary",Space,Str "for",Space,Str "the",Space,Str "first",Space,Str "block",Space,Str "to",Space,Str "be",Space,Str "normal",Space,Str "text:"]] +,Div ("",["complex-paragraph"],[]) + [BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]] + ,Para [RawInline (Format "openxml") "",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]] +,Para [Emph [Str "Nested",Space,Str "Divs",Space,Str "are",Space,Str "supported:"]] +,Div ("",["complex-paragraph"],[]) + [Div ("",["narrative"],[]) + [Para [Str "When",Space,Str "Clovis",Space,Str "came",Space,Str "in",Space,Str "front",Space,Str "of",Space,Str "the",Space,Str "soldier,",Space,Str "he",Space,Str "smashed",Space,Str "his",Space,Str "head",Space,Str "with",SoftBreak,Str "his",Space,Str "axe,",Space,Str "saying:"] + ,BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]]] + ,Div ("",["explanation"],[]) + [Para [RawInline (Format "openxml") "",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]]]] diff --git a/complex-paragraphs/tests/expected.latex b/complex-paragraphs/tests/expected.latex new file mode 100644 index 00000000..b6773f01 --- /dev/null +++ b/complex-paragraphs/tests/expected.latex @@ -0,0 +1,19 @@ +[Para [Emph [Str "Let\8217s",Space,Str "begin",Space,Str "with",Space,Str "a",Space,Str "simple",Space,Str "test",Space,Str "case:"]] +,Div ("",["complex-paragraph"],[]) + [Para [Str "When",Space,Str "Clovis",Space,Str "came",Space,Str "in",Space,Str "front",Space,Str "of",Space,Str "the",Space,Str "soldier,",Space,Str "he",Space,Str "smashed",Space,Str "his",Space,Str "head",Space,Str "with",SoftBreak,Str "his",Space,Str "axe,",Space,Str "saying:"] + ,BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]] + ,Para [RawInline (Format "latex") "\\noindent{}",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]] +,Para [Emph [Str "It",Space,Str "is",Space,Str "not",Space,Str "necessary",Space,Str "for",Space,Str "the",Space,Str "first",Space,Str "block",Space,Str "to",Space,Str "be",Space,Str "normal",Space,Str "text:"]] +,Div ("",["complex-paragraph"],[]) + [BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]] + ,Para [RawInline (Format "latex") "\\noindent{}",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]] +,Para [Emph [Str "Nested",Space,Str "Divs",Space,Str "are",Space,Str "supported:"]] +,Div ("",["complex-paragraph"],[]) + [Div ("",["narrative"],[]) + [Para [Str "When",Space,Str "Clovis",Space,Str "came",Space,Str "in",Space,Str "front",Space,Str "of",Space,Str "the",Space,Str "soldier,",Space,Str "he",Space,Str "smashed",Space,Str "his",Space,Str "head",Space,Str "with",SoftBreak,Str "his",Space,Str "axe,",Space,Str "saying:"] + ,BlockQuote + [Para [Str "Remember",Space,Str "the",Space,Str "vase",Space,Str "at",Space,Str "Soissons!"]]] + ,Div ("",["explanation"],[]) + [Para [RawInline (Format "latex") "\\noindent{}",Str "This",Space,Str "was",Space,Str "an",Space,Str "allusion",Space,Str "to",Space,Str "the",Space,Str "vase",Space,Str "that",Space,Str "the",Space,Str "soldier",Space,Str "had",Space,Str "broken",Space,Str "so",Space,Str "that",SoftBreak,Str "it",Space,Str "could",Space,Str "not",Space,Str "be",Space,Str "returned",Space,Str "to",Space,Str "Remigius."]]]]