diff --git a/include-code-files/Makefile b/include-code-files/Makefile new file mode 100644 index 00000000..6b169e09 --- /dev/null +++ b/include-code-files/Makefile @@ -0,0 +1,10 @@ +DIFF ?= diff --strip-trailing-cr -u + +test: sample.md include-code-files.lua + @pandoc --lua-filter=include-code-files.lua --to=native $< \ + | $(DIFF) expected.native - + +expected.native: sample.md include-code-files.lua + pandoc --lua-filter=include-code-files.lua --output $@ $< + +.PHONY: test diff --git a/include-code-files/README.md b/include-code-files/README.md new file mode 100644 index 00000000..e52ef279 --- /dev/null +++ b/include-code-files/README.md @@ -0,0 +1,54 @@ +# include-code-files + +Filter to include code from source files. + +The filter is largely inspired by [pandoc-include-code](https://github.com/owickstrom/pandoc-include-code). + +## Usage + +The filter recognizes code blocks with the `include` attribute present. It +swaps the content of the code block with contents from a file. + +### Including Files + +The simplest way to use this filter is to include an entire file: + + ```{include="hello.c"} + ``` + +You can still use other attributes, and classes, to control the code blocks: + + ```{.c include="hello.c" numberLines} + ``` + +### Ranges + +If you want to include a specific range of lines, use `startLine` and `endLine`: + + ```{include="hello.c" startLine=35 endLine=80} + ``` + +### Dedent + +Using the `dedent` attribute, you can have whitespaces removed on each line, +where possible (non-whitespace character will not be removed even if they occur +in the dedent area). + + ```{include="hello.c" dedent=4} + ``` + +### Line Numbers + +If you include the `numberLines` class in your code block, and use `include`, +the `startFrom` attribute will be added with respect to the included code's +location in the source file. + + ```{include="hello.c" startLine=35 endLine=80 .numberLines} + ``` + +## Example + +An HTML can be produced with this command: + + pandoc --lua-filter=include-code-files.lua sample.md --output result.html + diff --git a/include-code-files/expected.native b/include-code-files/expected.native new file mode 100644 index 00000000..18e4aca1 --- /dev/null +++ b/include-code-files/expected.native @@ -0,0 +1,8 @@ +[Header 1 ("inclusion",[],[]) [Str "Inclusion"] +,CodeBlock ("",["lua","numberLines"],[]) "--- include-code-files.lua \8211 filter to include code from source files\n---\n--- Copyright: \169 2020 Bruno BEAUFILS\n--- License: MIT \8211 see LICENSE file for details\n\n--- Dedent a line\nlocal function dedent (line, n)\n return line:sub(1,n):gsub(\" \",\"\") .. line:sub(n+1)\nend\n\n--- Filter function for code blocks\nlocal function transclude (cb)\n if cb.attributes.include then\n local content = \"\"\n local fh = io.open(cb.attributes.include)\n if not fh then\n io.stderr:write(\"Cannot open file \" .. cb.attributes.include .. \" | Skipping includes\\n\")\n else\n local number = 1\n local start = 1\n if cb.attributes.startLine then\n cb.attributes.startFrom = cb.attributes.startLine\n start = tonumber(cb.attributes.startLine)\n end\n for line in fh:lines (\"L\")\n do\n if cb.attributes.dedent then\n line = dedent(line, cb.attributes.dedent)\n end\n if number >= start then\n if not cb.attributes.endLine or number <= tonumber(cb.attributes.endLine) then\n content = content .. line\n end\n end\n number = number + 1\n end \n fh:close()\n end \n -- remove key-value pair for used keys\n cb.attributes.include = nil\n cb.attributes.startLine = nil\n cb.attributes.endLine = nil\n cb.attributes.dedent = nil\n -- return final code block\n return pandoc.CodeBlock(content, cb.attr)\n end\nend\n\nreturn {\n { CodeBlock = transclude }\n}\n" +,Header 1 ("ranges",[],[]) [Str "Ranges"] +,CodeBlock ("",["lua","numberLines"],[("startFrom","7")]) "local function dedent (line, n)\n return line:sub(1,n):gsub(\" \",\"\") .. line:sub(n+1)\nend\n" +,Header 1 ("detent",[],[]) [Str "Detent"] +,Para [Code ("",[],[]) "detent",Space,Str "removes",Space,Str "specified",Space,Str "number",Space,Str "of",Space,Str "whitespaces",Space,Str "(and",Space,Str "only",SoftBreak,Str "whitespaces)",Space,Str "from",Space,Str "beginning",Space,Str "of",Space,Str "each",Space,Str "line"] +,CodeBlock ("",["lua","bash","numberLines"],[("startFrom","8")]) "return line:sub(1,n):gsub(\" \",\"\") .. line:sub(n+1)\n" +,CodeBlock ("",["lua","numberLines"],[("startFrom","50")]) "{CodeBlock = transclude }\n"] diff --git a/include-code-files/include-code-files.lua b/include-code-files/include-code-files.lua new file mode 100644 index 00000000..df744bf7 --- /dev/null +++ b/include-code-files/include-code-files.lua @@ -0,0 +1,51 @@ +--- include-code-files.lua – filter to include code from source files +--- +--- Copyright: © 2020 Bruno BEAUFILS +--- License: MIT – see LICENSE file for details + +--- Dedent a line +local function dedent (line, n) + return line:sub(1,n):gsub(" ","") .. line:sub(n+1) +end + +--- Filter function for code blocks +local function transclude (cb) + if cb.attributes.include then + local content = "" + local fh = io.open(cb.attributes.include) + if not fh then + io.stderr:write("Cannot open file " .. cb.attributes.include .. " | Skipping includes\n") + else + local number = 1 + local start = 1 + if cb.attributes.startLine then + cb.attributes.startFrom = cb.attributes.startLine + start = tonumber(cb.attributes.startLine) + end + for line in fh:lines ("L") + do + if cb.attributes.dedent then + line = dedent(line, cb.attributes.dedent) + end + if number >= start then + if not cb.attributes.endLine or number <= tonumber(cb.attributes.endLine) then + content = content .. line + end + end + number = number + 1 + end + fh:close() + end + -- remove key-value pair for used keys + cb.attributes.include = nil + cb.attributes.startLine = nil + cb.attributes.endLine = nil + cb.attributes.dedent = nil + -- return final code block + return pandoc.CodeBlock(content, cb.attr) + end +end + +return { + { CodeBlock = transclude } +} diff --git a/include-code-files/sample.md b/include-code-files/sample.md new file mode 100644 index 00000000..a929adde --- /dev/null +++ b/include-code-files/sample.md @@ -0,0 +1,26 @@ +--- +author: me +title: Including Hello World +--- + +# Inclusion + +``` {include="include-code-files.lua" .lua .numberLines} +``` + +# Ranges + +``` {include="include-code-files.lua" .lua startLine=7 endLine=9 .numberLines} +``` + +# Detent + +`detent` removes specified number of whitespaces (and only +whitespaces) from beginning of each line + +``` {include="include-code-files.lua" .lua startLine=8 endLine=8 dedent=4 .bash .numberLines} +``` + +``` {include="include-code-files.lua" .lua startLine=50 endLine=50 dedent=5 .numberLines} +``` + diff --git a/include-files/Makefile b/include-files/Makefile index c5f5279e..d667c933 100644 --- a/include-files/Makefile +++ b/include-files/Makefile @@ -1,15 +1,15 @@ DIFF ?= diff --strip-trailing-cr -u -test: sample.md file-a.md file-b.md file-c.md include-files.lua +test: sample.md file-a.md file-b.md file-c.md shell1 shell2 include-files.lua @pandoc --lua-filter=include-files.lua --to=native $< \ | $(DIFF) expected.native - @pandoc --lua-filter=include-files.lua -M include-auto --to=native $< \ | $(DIFF) expected-auto.native - -expected.native: sample.md file-a.md file-b.md file-c.md include-files.lua +expected.native: sample.md file-a.md file-b.md file-c.md shell1 shell2 include-files.lua pandoc --lua-filter=include-files.lua --output $@ $< -expected-auto.native: sample.md file-a.md file-b.md file-c.md include-files.lua - pandoc --lua-filter=include-files.lua --output $@ $< +expected-auto.native: sample.md file-a.md file-b.md file-c.md shell1 shell2 include-files.lua + pandoc --lua-filter=include-files.lua -M include-auto --output $@ $< .PHONY: test diff --git a/include-files/README.md b/include-files/README.md index a99402a2..f1596016 100644 --- a/include-files/README.md +++ b/include-files/README.md @@ -11,6 +11,9 @@ document. Metadata from included files is discarded. +Add class `source` to include files as normal code blocks taken from +files instead of text in same format as the input. + ### Shifting Headings The default is to include the subdocuments unchanged, but it can @@ -59,6 +62,9 @@ will want to include files written in a different format. An alternative format can be specified via the `format` attribute. Only plain-text formats are accepted. +In order to include source code block from files use additional class +`source` instead of trying the language as `format`. + ### Recursive transclusion Included files can in turn include other files. Note that all @@ -101,6 +107,13 @@ some additional information in the main file `main.md`: appendix/questionaire.md ``` + ## Source code + + ``` {.include .source .lua} + // code of this nice filter + include-files.lua + ``` + An HTML can be produced with this command: pandoc --lua-filter=include-files.lua main.md --output result.html diff --git a/include-files/expected-auto.native b/include-files/expected-auto.native index 22be9279..dd398cb0 100644 --- a/include-files/expected-auto.native +++ b/include-files/expected-auto.native @@ -16,6 +16,8 @@ ,Para [Str "This",Space,Str "is",Space,Code ("",[],[]) "file-a.md",Str "."] ,Header 3 ("title-of-file-a",[],[]) [Str "Title",Space,Str "of",Space,Str "file-a"] ,Para [Str "This",Space,Str "is",Space,Code ("",[],[]) "file-a.md",Str "."] +,Header 1 ("source-code",[],[]) [Str "Source",Space,Str "code"] +,CodeBlock ("",["include","source","bash"],[]) "#!/bin/bash\n\necho \"Hello World !\"\n\n#!/bin/bash\nfor i in \"Hello \" \"World \" \"!\\n\" \ndo\n\tprintf \"$i\"\ndone\n\n" ,Header 1 ("appendix",[],[]) [Str "Appendix"] ,Para [Str "More",Space,Str "info",Space,Str "goes",Space,Str "here."] ,Header 2 ("questionaire",[],[]) [Str "Questionaire"] diff --git a/include-files/expected.native b/include-files/expected.native index d50caa48..f8c3fcd5 100644 --- a/include-files/expected.native +++ b/include-files/expected.native @@ -16,6 +16,8 @@ ,Para [Str "This",Space,Str "is",Space,Code ("",[],[]) "file-a.md",Str "."] ,Header 2 ("title-of-file-a",[],[]) [Str "Title",Space,Str "of",Space,Str "file-a"] ,Para [Str "This",Space,Str "is",Space,Code ("",[],[]) "file-a.md",Str "."] +,Header 1 ("source-code",[],[]) [Str "Source",Space,Str "code"] +,CodeBlock ("",["include","source","bash"],[]) "#!/bin/bash\n\necho \"Hello World !\"\n\n#!/bin/bash\nfor i in \"Hello \" \"World \" \"!\\n\" \ndo\n\tprintf \"$i\"\ndone\n\n" ,Header 1 ("appendix",[],[]) [Str "Appendix"] ,Para [Str "More",Space,Str "info",Space,Str "goes",Space,Str "here."] ,Header 2 ("questionaire",[],[]) [Str "Questionaire"] diff --git a/include-files/include-files.lua b/include-files/include-files.lua index f685ec00..e060843d 100644 --- a/include-files/include-files.lua +++ b/include-files/include-files.lua @@ -1,4 +1,4 @@ ---- include-files.lua – filter to include Markdown files +--- include-files.lua – filter to include files --- --- Copyright: © 2019–2020 Albert Krewinkel --- License: MIT – see LICENSE file for details @@ -43,6 +43,22 @@ function transclude (cb) if not cb.classes:includes 'include' then return end + -- process files as source code blocks + if cb.classes:includes 'source' then + local contents = "" + for line in cb.text:gmatch('[^\n]+') do + if line:sub(1,2) ~= '//' then + local fh = io.open(line) + if not fh then + io.stderr:write("Cannot open file " .. line .. " | Skipping includes\n") + else + contents = contents .. fh:read('*a') + fh:close() + end + end + end + return pandoc.CodeBlock(contents, cb.attr) + end -- Markdown is used if this is nil. local format = cb.attributes['format'] diff --git a/include-files/sample.md b/include-files/sample.md index b0352fb8..191d1936 100644 --- a/include-files/sample.md +++ b/include-files/sample.md @@ -28,6 +28,14 @@ file-d.org file-f.md ``` +# Source code + +``` {.include .source .bash} +// this will include simple bash files +shell1 +shell2 +``` + # Appendix More info goes here. diff --git a/include-files/shell1 b/include-files/shell1 new file mode 100644 index 00000000..4d0a6dc1 --- /dev/null +++ b/include-files/shell1 @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "Hello World !" + diff --git a/include-files/shell2 b/include-files/shell2 new file mode 100644 index 00000000..a635b20f --- /dev/null +++ b/include-files/shell2 @@ -0,0 +1,6 @@ +#!/bin/bash +for i in "Hello " "World " "!\n" +do + printf "$i" +done +