diff options
author | Jonas Smedegaard <dr@jones.dk> | 2025-02-24 15:00:10 +0100 |
---|---|---|
committer | Jonas Smedegaard <dr@jones.dk> | 2025-02-24 15:00:10 +0100 |
commit | 58042b5135ddf74bf5945c46eafd3828739e045c (patch) | |
tree | 76bca3d1d18c8979087660e052ddd4facd41ecc8 /_extensions/quarto-ext/include-code-files/include-code-files.lua |
initial draft
Diffstat (limited to '_extensions/quarto-ext/include-code-files/include-code-files.lua')
-rw-r--r-- | _extensions/quarto-ext/include-code-files/include-code-files.lua | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/_extensions/quarto-ext/include-code-files/include-code-files.lua b/_extensions/quarto-ext/include-code-files/include-code-files.lua new file mode 100644 index 0000000..c74aa53 --- /dev/null +++ b/_extensions/quarto-ext/include-code-files/include-code-files.lua @@ -0,0 +1,130 @@ +--- 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 + +--- Find snippet start and end. +-- +-- Use this to populate startline and endline. +-- This should work like pandocs snippet functionality: https://github.com/owickstrom/pandoc-include-code/tree/master +local function snippet(cb, fh) + if not cb.attributes.snippet then + return + end + + -- Cannot capture enum: http://lua-users.org/wiki/PatternsTutorial + local comment + local comment_stop = "" + if + string.match(cb.attributes.include, ".py$") + or string.match(cb.attributes.include, ".jl$") + or string.match(cb.attributes.include, ".r$") + then + comment = "#" + elseif string.match(cb.attributes.include, ".o?js$") or string.match(cb.attributes.include, ".css$") then + comment = "//" + elseif string.match(cb.attributes.include, ".lua$") then + comment = "--" + elseif string.match(cb.attributes.include, ".html$") then + comment = "<!%-%-" + comment_stop = " *%-%->" + else + -- If not known assume that it is something one or two long and not alphanumeric. + comment = "%W%W?" + end + + local p_start = string.format("^ *%s start snippet %s%s", comment, cb.attributes.snippet, comment_stop) + local p_stop = string.format("^ *%s end snippet %s%s", comment, cb.attributes.snippet, comment_stop) + local start, stop = nil, nil + + -- Cannot use pairs. + local line_no = 1 + for line in fh:lines() do + if start == nil then + if string.match(line, p_start) then + start = line_no + 1 + end + elseif stop == nil then + if string.match(line, p_stop) then + stop = line_no - 1 + end + else + break + end + line_no = line_no + 1 + end + + -- Reset so nothing is broken later on. + fh:seek("set") + + -- If start and stop not found, just continue + if start == nil or stop == nil then + return nil + end + + cb.attributes.startLine = tostring(start) + cb.attributes.endLine = tostring(stop) +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 + + -- change hyphenated attributes to PascalCase + for i, pascal in pairs({ "startLine", "endLine" }) do + local hyphen = pascal:gsub("%u", "-%0"):lower() + if cb.attributes[hyphen] then + cb.attributes[pascal] = cb.attributes[hyphen] + cb.attributes[hyphen] = nil + end + end + + -- Overwrite startLine and stopLine with the snippet if any. + snippet(cb, fh) + + 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 }, +} |