@@ -9,15 +9,99 @@ PANDOC_VERSION:must_be_at_least '2.12'
9
9
local List = require ' pandoc.List'
10
10
local path = require ' pandoc.path'
11
11
local system = require ' pandoc.system'
12
+ local cs = PANDOC_STATE
12
13
13
- --- Get include auto mode
14
+ -- This is the codeblock-var-replace
15
+ -- filter directly copied, since we
16
+ -- cannot run Lua filters inside this filter
17
+ -- https://github.com/jgm/pandoc/issues/6830
18
+ -- We replace variables in include blocks.
19
+
20
+ local sys = require ' pandoc.system'
21
+ local utils = require ' pandoc.utils'
22
+ -- local ut = require "module-lua.utils"
23
+
24
+ -- Save env. variables
25
+ local env = sys .environment ()
26
+
27
+ -- Save meta table and metadata
28
+ local meta
29
+ function save_meta (m )
30
+ meta = m
31
+ end
32
+
33
+ --- Replace variables in code blocks
34
+ local metaMap
35
+ local function var_replace_codeblocks (cb )
36
+ --- Replace variable with values from environment
37
+ --- and meta data (stringifing).
38
+ local function replace (what , var )
39
+ local repl = nil
40
+ if what == " env" then
41
+ repl = env [var ]
42
+ elseif what == " meta" then
43
+ local v = metaMap [var ]
44
+ if v then
45
+ repl = utils .stringify (v )
46
+ end
47
+ end
48
+
49
+ if repl == nil then
50
+ io.stderr :write (" Could not replace variable in codeblock: '" .. var .. " '\n " )
51
+ end
52
+
53
+ return repl
54
+ end
55
+
56
+ -- ignore code blocks which are not of class "var-replace".
57
+ if not cb .classes :includes ' var-replace' then
58
+ return
59
+ end
60
+
61
+ cb .text = cb .text :gsub (" %${(%l+):([^}]+)}" , replace )
62
+ end
63
+
64
+ --- Include/exclude by attribute
65
+ --- `exclude-if-format='formatA;formatB;...'
66
+ --- `include-if-format='formatA;formatB;...`
67
+ --- Default: true
68
+ local function is_included (cb )
69
+ local include = true
70
+ local exclude = false
71
+
72
+ if cb .attributes [' include-if-format' ] then
73
+ include = cb .attributes [' include-if-format' ]:match (FORMAT ) ~= nil
74
+ end
75
+
76
+ if cb .attributes [' exclude-if-format' ] then
77
+ exclude = cb .attributes [' exclude-if-format' ]:match (FORMAT ) ~= nil
78
+ end
79
+
80
+ return include == true and exclude == false
81
+ end
82
+
83
+ --- Get default settings
14
84
local include_auto = false
85
+ local default_format = nil
86
+ local include_fail_if_read_error = false
87
+
15
88
function get_vars (meta )
16
89
if meta [' include-auto' ] then
17
90
include_auto = true
18
91
end
92
+
93
+ if meta [' include-fail-if-read-error' ] then
94
+ include_fail_if_read_error = true
95
+ end
96
+
97
+ -- If this is nil, markdown is used as a default format.
98
+ default_format = meta [' include-format' ]
99
+
100
+ -- Save meta table for var_replace
101
+ metaMap = meta
19
102
end
20
103
104
+
21
105
--- Keep last heading level found
22
106
local last_heading_level = 0
23
107
function update_last_level (header )
@@ -62,8 +146,23 @@ function transclude (cb)
62
146
return
63
147
end
64
148
65
- -- Markdown is used if this is nil.
149
+ -- Filter by includes and excludes
150
+ if not is_included (cb ) then
151
+ return List {} -- remove block
152
+ end
153
+
154
+ -- Variable substitution
155
+ var_replace_codeblocks (cb )
156
+
66
157
local format = cb .attributes [' format' ]
158
+ if not format then
159
+ -- Markdown is used if this is nil.
160
+ format = default_format
161
+ end
162
+
163
+ -- Check if we include the file as raw inline
164
+ local raw = cb .attributes [' raw' ]
165
+ raw = raw == " true"
67
166
68
167
-- Attributes shift headings
69
168
local shift_heading_level_by = 0
@@ -77,35 +176,63 @@ function transclude (cb)
77
176
end
78
177
end
79
178
80
- --- keep track of level before recusion
179
+ --- Keep track of level before recursion
81
180
local buffer_last_heading_level = last_heading_level
82
181
83
182
local blocks = List :new ()
84
183
for line in cb .text :gmatch (' [^\n ]+' ) do
85
- if line :sub (1 ,2 ) ~= ' //' then
86
- local fh = io.open (line )
87
- if not fh then
88
- io.stderr :write (" Cannot open file " .. line .. " | Skipping includes\n " )
184
+ if line :sub (1 ,2 ) == ' //' then
185
+ goto skip_to_next
186
+ end
187
+
188
+ if cs .verbosity == " INFO" then
189
+ io.stderr :write (string.format (" Including: [format: %s, raw: %s]\n - '%s'\n " ,
190
+ format ,
191
+ tostring (raw ), line ))
192
+ end
193
+
194
+ local fh = io.open (line )
195
+ if not fh then
196
+ local cwd = system .get_working_directory ()
197
+ local msg = " Cannot find include file: '" .. line .. " ' in working dir: '" .. cwd .. " '"
198
+ if include_fail_if_read_error then
199
+ io.stderr :write (msg .. " | error\n " )
200
+ error (" Abort due to include failure" )
89
201
else
90
- local contents = pandoc .read (fh :read ' *a' , format ).blocks
91
- last_heading_level = 0
92
- -- recursive transclusion
93
- contents = system .with_working_directory (
94
- path .directory (line ),
95
- function ()
96
- return pandoc .walk_block (
97
- pandoc .Div (contents ),
98
- { Header = update_last_level , CodeBlock = transclude }
99
- )
100
- end ).content
101
- --- reset to level before recursion
102
- last_heading_level = buffer_last_heading_level
103
- blocks :extend (update_contents (contents , shift_heading_level_by ,
104
- path .directory (line )))
105
- fh :close ()
202
+ io.stderr :write (msg .. " | skipping include\n " )
203
+ goto skip_to_next
106
204
end
107
205
end
206
+
207
+ -- Read the file
208
+ local text = fh :read (' *a' )
209
+ fh :close ()
210
+
211
+ if raw then
212
+ -- Include as raw inline element
213
+ blocks :extend ({pandoc .RawBlock (format , text )})
214
+ else
215
+ -- Inlcude as parsed AST
216
+ local contents = pandoc .read (text , format ).blocks
217
+ last_heading_level = 0
218
+ -- Recursive transclusion
219
+ contents = system .with_working_directory (
220
+ path .directory (line ),
221
+ function ()
222
+ return pandoc .walk_block (
223
+ pandoc .Div (contents ),
224
+ { Header = update_last_level , CodeBlock = transclude }
225
+ )
226
+ end ).content
227
+ --- Reset to level before recursion
228
+ last_heading_level = buffer_last_heading_level
229
+ blocks :extend (update_contents (contents , shift_heading_level_by ,
230
+ path .directory (line )))
231
+ end
232
+
233
+ :: skip_to_next::
108
234
end
235
+
109
236
return blocks
110
237
end
111
238
0 commit comments