@@ -9,15 +9,99 @@ PANDOC_VERSION:must_be_at_least '2.12'
99local List = require ' pandoc.List'
1010local path = require ' pandoc.path'
1111local system = require ' pandoc.system'
12+ local cs = PANDOC_STATE
1213
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
1484local include_auto = false
85+ local default_format = nil
86+ local include_fail_if_read_error = false
87+
1588function get_vars (meta )
1689 if meta [' include-auto' ] then
1790 include_auto = true
1891 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
19102end
20103
104+
21105--- Keep last heading level found
22106local last_heading_level = 0
23107function update_last_level (header )
@@ -62,8 +146,23 @@ function transclude (cb)
62146 return
63147 end
64148
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+
66157 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"
67166
68167 -- Attributes shift headings
69168 local shift_heading_level_by = 0
@@ -77,35 +176,63 @@ function transclude (cb)
77176 end
78177 end
79178
80- --- keep track of level before recusion
179+ --- Keep track of level before recursion
81180 local buffer_last_heading_level = last_heading_level
82181
83182 local blocks = List :new ()
84183 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" )
89201 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
106204 end
107205 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::
108234 end
235+
109236 return blocks
110237end
111238
0 commit comments