|
10 | 10 |
|
11 | 11 | --- Filter function for code blocks |
12 | 12 | local function transclude (cb) |
| 13 | + local content = "" |
| 14 | + |
13 | 15 | if cb.attributes.include then |
14 | | - local content = "" |
15 | 16 | local fh = io.open(cb.attributes.include) |
16 | 17 | if not fh then |
17 | 18 | io.stderr:write("Cannot open file " .. cb.attributes.include .. " | Skipping includes\n") |
| 19 | + goto cleanup |
| 20 | + end |
| 21 | + |
| 22 | + -- change hyphenated attributes to PascalCase |
| 23 | + for i,pascal in pairs({"startLine", "endLine", "startAfter", "endBefore"}) |
| 24 | + do |
| 25 | + local hyphen = pascal:gsub("%u", "-%0"):lower() |
| 26 | + if cb.attributes[hyphen] then |
| 27 | + cb.attributes[pascal] = cb.attributes[hyphen] |
| 28 | + cb.attributes[hyphen] = nil |
| 29 | + end |
| 30 | + end |
| 31 | + |
| 32 | + if cb.attributes.startLine and cb.attributes.startAfter then |
| 33 | + io.stderr:write("Cannot specify both startLine and startAfter | Skipping includes\n") |
| 34 | + goto cleanup |
| 35 | + end |
| 36 | + |
| 37 | + if cb.attributes.endLine and cb.attributes.endBefore then |
| 38 | + io.stderr:write("Cannot specify both endLine and endBefore | Skipping includes\n") |
| 39 | + goto cleanup |
| 40 | + end |
| 41 | + |
| 42 | + local number = 0 |
| 43 | + local start = nil |
| 44 | + local finish = nil |
| 45 | + local skipFirst = false |
| 46 | + local skipLast = false |
| 47 | + |
| 48 | + -- set start and skipFirst based on start params |
| 49 | + if cb.attributes.startLine then |
| 50 | + start = tonumber(cb.attributes.startLine) |
| 51 | + if not start then |
| 52 | + start = cb.attributes.startLine |
| 53 | + end |
| 54 | + elseif cb.attributes.startAfter then |
| 55 | + start = tonumber(cb.attributes.startAfter) |
| 56 | + if not start then |
| 57 | + start = cb.attributes.startAfter |
| 58 | + end |
| 59 | + skipFirst = true |
18 | 60 | else |
19 | | - local number = 1 |
20 | | - local start = 1 |
21 | | - |
22 | | - -- change hyphenated attributes to PascalCase |
23 | | - for i,pascal in pairs({"startLine", "endLine"}) |
24 | | - do |
25 | | - local hyphen = pascal:gsub("%u", "-%0"):lower() |
26 | | - if cb.attributes[hyphen] then |
27 | | - cb.attributes[pascal] = cb.attributes[hyphen] |
28 | | - cb.attributes[hyphen] = nil |
29 | | - end |
30 | | - end |
31 | | - |
32 | | - if cb.attributes.startLine then |
33 | | - cb.attributes.startFrom = cb.attributes.startLine |
34 | | - start = tonumber(cb.attributes.startLine) |
35 | | - end |
36 | | - for line in fh:lines ("L") |
37 | | - do |
38 | | - if cb.attributes.dedent then |
39 | | - line = dedent(line, cb.attributes.dedent) |
| 61 | + -- if no start specified, start at the first line |
| 62 | + start = 1 |
| 63 | + end |
| 64 | + |
| 65 | + quarto.log.output("start: " .. start) |
| 66 | + |
| 67 | + -- set finish and skipLast based on end params |
| 68 | + if cb.attributes.endLine then |
| 69 | + finish = tonumber(cb.attributes.endLine) |
| 70 | + if not finish then |
| 71 | + finish = cb.attributes.endLine |
| 72 | + end |
| 73 | + elseif cb.attributes.endBefore then |
| 74 | + finish = tonumber(cb.attributes.endBefore) |
| 75 | + if not finish then |
| 76 | + finish = cb.attributes.endBefore |
| 77 | + end |
| 78 | + skipLast = true |
| 79 | + else |
| 80 | + -- if no end specified, end at the last line |
| 81 | + end |
| 82 | + |
| 83 | + quarto.log.output("finish: " .. finish) |
| 84 | + |
| 85 | + for line in fh:lines ("L") |
| 86 | + do |
| 87 | + number = number + 1 |
| 88 | + -- if start or finish is a string, check if it exists on the current line |
| 89 | + if type(start) == "string" and string.find(line, start, 1, true) then |
| 90 | + start = number |
| 91 | + quarto.log.output("convererted start to : " .. start) |
| 92 | + elseif type(finish) == "string" and string.find(line, finish, 1 , true) then |
| 93 | + finish = number |
| 94 | + quarto.log.output("convererted finish to : " .. finish) |
| 95 | + end |
| 96 | + |
| 97 | + -- if haven't found start yet, then continue |
| 98 | + if start and type(start) == "number" then |
| 99 | + if number < start or (number == start and skipFirst) then |
| 100 | + goto continue |
40 | 101 | end |
41 | | - if number >= start then |
42 | | - if not cb.attributes.endLine or number <= tonumber(cb.attributes.endLine) then |
43 | | - content = content .. line |
44 | | - end |
| 102 | + elseif start then |
| 103 | + -- else if start is still a string, then continue |
| 104 | + goto continue |
| 105 | + end |
| 106 | + |
| 107 | + -- if found finish, then end |
| 108 | + if finish and type(finish) == "number" then |
| 109 | + if number > finish or (number == finish and skipLast) then |
| 110 | + break |
45 | 111 | end |
46 | | - number = number + 1 |
47 | | - end |
48 | | - fh:close() |
49 | | - end |
50 | | - -- remove key-value pair for used keys |
51 | | - cb.attributes.include = nil |
52 | | - cb.attributes.startLine = nil |
53 | | - cb.attributes.endLine = nil |
54 | | - cb.attributes.dedent = nil |
55 | | - -- return final code block |
56 | | - return pandoc.CodeBlock(content, cb.attr) |
| 112 | + end |
| 113 | + |
| 114 | + if cb.attributes.dedent then |
| 115 | + line = dedent(line, cb.attributes.dedent) |
| 116 | + end |
| 117 | + |
| 118 | + content = content .. line |
| 119 | + ::continue:: |
| 120 | + end |
| 121 | + fh:close() |
57 | 122 | end |
| 123 | + ::cleanup:: |
| 124 | + -- remove key-value pair for used keys |
| 125 | + cb.attributes.include = nil |
| 126 | + cb.attributes.startLine = nil |
| 127 | + cb.attributes.startAfter = nil |
| 128 | + cb.attributes.endLine = nil |
| 129 | + cb.attributes.endBefore = nil |
| 130 | + cb.attributes.dedent = nil |
| 131 | + -- return final code block |
| 132 | + return pandoc.CodeBlock(content, cb.attr) |
58 | 133 | end |
59 | 134 |
|
60 | 135 | return { |
61 | 136 | { CodeBlock = transclude } |
62 | 137 | } |
63 | | - |
|
0 commit comments