diff --git a/composite-paragraphs/LICENSE.txt b/composite-paragraphs/LICENSE.txt new file mode 100644 index 0000000..43106c1 --- /dev/null +++ b/composite-paragraphs/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright © 2021-2022 Bastien Dumont + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/composite-paragraphs/Makefile b/composite-paragraphs/Makefile new file mode 100644 index 0000000..bd59556 --- /dev/null +++ b/composite-paragraphs/Makefile @@ -0,0 +1,12 @@ +.PHONY: test + +PANDOC_COMMAND = pandoc -L composite-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/composite-paragraphs/README.md b/composite-paragraphs/README.md new file mode 100644 index 0000000..bea77af --- /dev/null +++ b/composite-paragraphs/README.md @@ -0,0 +1,45 @@ +# Composite paragraphs from Pandoc + +## Definition + +Composite paragraphs are paragraphs composed of different blocks: +normal text, quotations, tables,... This filter unindents all text blocks +but the first in a composite paragraph. + +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 composite paragraph in your MD file, simply wrap its +components in a Div with class `.composite-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/composite-paragraphs/composite-paragraphs.lua b/composite-paragraphs/composite-paragraphs.lua new file mode 100644 index 0000000..9993700 --- /dev/null +++ b/composite-paragraphs/composite-paragraphs.lua @@ -0,0 +1,75 @@ +--[[ +composite-paragraphs – unindent all blocks but the first in composite paragraphs + +Copyright © 2021-2022 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 composite-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(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(block.content) + end + is_after_first_block = true + end +end + +local function turn_to_composite_paragraph(div) + unindent_paragraphs_after_first_block(div.content) +end + +function Div(div) + if div.classes:includes('composite-paragraph') then + is_after_first_block = false + turn_to_composite_paragraph(div) + return div + end +end diff --git a/composite-paragraphs/output.docx b/composite-paragraphs/output.docx new file mode 100644 index 0000000..4e20fd8 Binary files /dev/null and b/composite-paragraphs/output.docx differ diff --git a/composite-paragraphs/sample.md b/composite-paragraphs/sample.md new file mode 100644 index 0000000..ab2d645 --- /dev/null +++ b/composite-paragraphs/sample.md @@ -0,0 +1,36 @@ +_Let's begin with a simple test case:_ + +::: {.composite-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:_ + +::: {.composite-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:_ + +::: {.composite-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/composite-paragraphs/tests/expected.context b/composite-paragraphs/tests/expected.context new file mode 100644 index 0000000..47d3239 --- /dev/null +++ b/composite-paragraphs/tests/expected.context @@ -0,0 +1,308 @@ +[ Para + [ Emph + [ Str "Let\8217s" + , Space + , Str "begin" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "simple" + , Space + , Str "test" + , Space + , Str "case:" + ] + ] +, Div + ( "" , [ "composite-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 + ( "" , [ "composite-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 + ( "" , [ "composite-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/composite-paragraphs/tests/expected.docx b/composite-paragraphs/tests/expected.docx new file mode 100644 index 0000000..c196f55 --- /dev/null +++ b/composite-paragraphs/tests/expected.docx @@ -0,0 +1,314 @@ +[ Para + [ Emph + [ Str "Let\8217s" + , Space + , Str "begin" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "simple" + , Space + , Str "test" + , Space + , Str "case:" + ] + ] +, Div + ( "" , [ "composite-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 + ( "" , [ "composite-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 + ( "" , [ "composite-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/composite-paragraphs/tests/expected.latex b/composite-paragraphs/tests/expected.latex new file mode 100644 index 0000000..2b992c6 --- /dev/null +++ b/composite-paragraphs/tests/expected.latex @@ -0,0 +1,308 @@ +[ Para + [ Emph + [ Str "Let\8217s" + , Space + , Str "begin" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "simple" + , Space + , Str "test" + , Space + , Str "case:" + ] + ] +, Div + ( "" , [ "composite-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 + ( "" , [ "composite-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 + ( "" , [ "composite-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." + ] + ] + ] +]