@@ -124,16 +124,51 @@ ctx.sec = doc:mksec() -- toplevel section ctx.sec.origin = ctx:clone() end; ref = function(self,id) + if self.invocation then + -- allow IDs to contain template substitutions by mimicking the [#n] syntax + id = id:gsub('%b[]', function(sp) + -- should indirection be allowed here? TODO + if sp:sub(2,2) == '#' then + local n = tonumber(sp:sub(3,-2)) + if n == nil then + self:fail('invalid template substitution “%s” in ID “%s”', sp, id) + end + local arg = self.invocation.args[n] + if arg == nil then + self:fail('template instantiation requires at least %u arguments (in ID “%s”)',n,id) + end + return arg + else return sp end + end) + + end if not id:find'%.' then local rid = self.sec.refs[id] - if self.sec.refs[id] then - return self.sec.refs[id], id, self.sec - else self:fail("no such ref %s in current section", id or '') end + if rid then + return rid, id, self.sec + end + + --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 + if self.invocation then + rid = self.invocation.origin:ref(id) + if rid then + return rid, id, self.invocation.origin.sec + end + end + + self:fail("no such ref %s in current section", id or '') else local sec, ref = string.match(id, "(.-)%.(.+)") - local s = self.doc.sections[sec] + local s + if sec == '' then + if self.invocation == nil then + self:fail('site-of-invocation IDs can only be dereferenced in a macro expansion (offending ID: “%s”)', id) + end + s = self.invocation.origin.sec + end + s = s or self.doc.sections[sec] if not s then -- fall back on inheritance tree for i, p in ipairs(self.doc.parents) do if p.sections[sec] then s = p.sections[sec] @@ -1298,17 +1333,21 @@ args = argv; } end)}; {seq='&', fn=blockwrap(function(s,c) - local id, cap = s:match('^&([^%s]+)%s*(.-)%s*$') + local mode, id, cap = s:match('^&([-+]?)([^%s]+)%s*(.-)%s*$') if id == nil or id == '' then c:fail 'malformed embed block' end - if cap == '' then cap = nil end + if cap == '' then cap = nil end + if mode == '-' then mode = 'closed' + elseif mode == '+' then mode = 'open' + else mode = 'inline' end return { kind = 'embed'; ref = id; cap = cap; + mode = mode; } end)}; {fn = insert_paragraph}; }