Skip to content

Commit 100feae

Browse files
authored
Updated to support string tags and added startAfter & endBefore
You can now specify the start and end of code blocks via string labels. This greatly improves the experience because you can edit the source file and rely on the string labels to grab the correct code blocks. No more adjusting line numbers after making edits
1 parent f196b89 commit 100feae

File tree

1 file changed

+112
-38
lines changed

1 file changed

+112
-38
lines changed

_extensions/include-code-files/include-code-files.lua

Lines changed: 112 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,54 +10,128 @@ end
1010

1111
--- Filter function for code blocks
1212
local function transclude (cb)
13+
local content = ""
14+
1315
if cb.attributes.include then
14-
local content = ""
1516
local fh = io.open(cb.attributes.include)
1617
if not fh then
1718
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
1860
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
40101
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
45111
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()
57122
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)
58133
end
59134

60135
return {
61136
{ CodeBlock = transclude }
62137
}
63-

0 commit comments

Comments
 (0)