Differences From
Artifact [3b9ae546e1]:
121 121 ctx.line = 0
122 122 ctx.doc = doc
123 123 ctx.doc.src = src
124 124 ctx.sec = doc:mksec() -- toplevel section
125 125 ctx.sec.origin = ctx:clone()
126 126 end;
127 127 ref = function(self,id)
128 + if self.invocation then
129 + -- allow IDs to contain template substitutions by mimicking the [#n] syntax
130 + id = id:gsub('%b[]', function(sp)
131 + -- should indirection be allowed here? TODO
132 + if sp:sub(2,2) == '#' then
133 + local n = tonumber(sp:sub(3,-2))
134 + if n == nil then
135 + self:fail('invalid template substitution “%s” in ID “%s”', sp, id)
136 + end
137 + local arg = self.invocation.args[n]
138 + if arg == nil then
139 + self:fail('template instantiation requires at least %u arguments (in ID “%s”)',n,id)
140 + end
141 + return arg
142 + else return sp end
143 + end)
144 +
145 + end
128 146 if not id:find'%.' then
129 147 local rid = self.sec.refs[id]
130 - if self.sec.refs[id] then
131 - return self.sec.refs[id], id, self.sec
132 - else self:fail("no such ref %s in current section", id or '') end
148 + if rid then
149 + return rid, id, self.sec
150 + end
151 +
152 + --nothing in the current section, but this ID could be looked up in the context of a macro expansion. if so, check section of the site of invocation as well
153 + if self.invocation then
154 + rid = self.invocation.origin:ref(id)
155 + if rid then
156 + return rid, id, self.invocation.origin.sec
157 + end
158 + end
159 +
160 + self:fail("no such ref %s in current section", id or '')
133 161 else
134 162 local sec, ref = string.match(id, "(.-)%.(.+)")
135 - local s = self.doc.sections[sec]
163 + local s
164 + if sec == '' then
165 + if self.invocation == nil then
166 + self:fail('site-of-invocation IDs can only be dereferenced in a macro expansion (offending ID: “%s”)', id)
167 + end
168 + s = self.invocation.origin.sec
169 + end
170 + s = s or self.doc.sections[sec]
136 171 if not s then -- fall back on inheritance tree
137 172 for i, p in ipairs(self.doc.parents) do
138 173 if p.sections[sec] then
139 174 s = p.sections[sec]
140 175 break
141 176 end
142 177 end
................................................................................
1295 1330 return {
1296 1331 kind = 'macro';
1297 1332 macro = id;
1298 1333 args = argv;
1299 1334 }
1300 1335 end)};
1301 1336 {seq='&', fn=blockwrap(function(s,c)
1302 - local id, cap = s:match('^&([^%s]+)%s*(.-)%s*$')
1337 + local mode, id, cap = s:match('^&([-+]?)([^%s]+)%s*(.-)%s*$')
1303 1338 if id == nil or id == '' then
1304 1339 c:fail 'malformed embed block'
1305 1340 end
1306 - if cap == '' then cap = nil end
1341 + if cap == '' then cap = nil end
1342 + if mode == '-' then mode = 'closed'
1343 + elseif mode == '+' then mode = 'open'
1344 + else mode = 'inline' end
1307 1345 return {
1308 1346 kind = 'embed';
1309 1347 ref = id;
1310 1348 cap = cap;
1349 + mode = mode;
1311 1350 }
1312 1351 end)};
1313 1352 {fn = insert_paragraph};
1314 1353 }
1315 1354
1316 1355 function ct.parse_line(rawline, ctx, dest)
1317 1356 local newspan