Skip to content

Commit c08fcaa

Browse files
OmikhleiaDidier Willis
authored andcommitted
feat(packages): Honor bibliography style indentation rules
1 parent ded9a16 commit c08fcaa

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

packages/bibtex/csl/engine.lua

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,9 @@ function CslEngine:_layout (options, content, entries)
449449
-- quite logically as we force a paragraph break between entries.
450450
for _, entry in ipairs(entries) do
451451
self:_prerender()
452-
local elem = self:_render_children(content, entry)
452+
local elem = self:_render_children(content, entry, {
453+
secondFieldAlign = self.inheritable.bibliography["second-field-align"] and true or false,
454+
})
453455
elem = self:_render_affixes(elem, options)
454456
elem = self:_render_formatting(elem, options)
455457
elem = self:_postrender(elem)
@@ -1459,6 +1461,16 @@ function CslEngine:_render_children (ast, entry, context)
14591461
SU.error("CSL unexpected content") -- Should not happen
14601462
end
14611463
end
1464+
if context.secondFieldAlign then
1465+
-- CSL 1.0.2 says that "subsequent lines of bibliographic entries are aligned
1466+
-- along the second field" with the first field either flushed "with the margin"
1467+
-- or "put in the margin".
1468+
-- This is a dubious wording, probably bad typography, with no amount of spacing
1469+
-- even described.
1470+
-- We choose to "box" the first field, and the default implementation will take
1471+
-- care of doing sound typography.
1472+
ret[1] = "<bibBoxForIndent>" .. ret[1] .. "</bibBoxForIndent>"
1473+
end
14621474
return #ret > 0 and self:_render_delimiter(ret, context.delimiter) or nil
14631475
end
14641476

packages/bibtex/init.lua

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ function package.declareSettings (_)
9898
default = "chicago",
9999
help = "BibTeX style",
100100
})
101+
102+
-- For CSL hanging-indent or second-field-align
103+
SILE.settings:declare({
104+
parameter = "bibliography.indent",
105+
type = "measurement",
106+
default = SILE.types.measurement("3em"),
107+
help = "Left indentation for bibliography entries when the citation style requires it.",
108+
})
101109
end
102110

103111
--- Retrieve the CSL engine, creating it if necessary.
@@ -279,6 +287,18 @@ function package:registerCommands ()
279287
end)
280288
end)
281289

290+
self:registerCommand("bibBoxForIndent", function (_, content)
291+
local hbox = SILE.typesetter:makeHbox(content)
292+
local margin = SILE.types.length(SILE.settings:get("bibliography.indent"):absolute())
293+
if hbox.width > margin then
294+
SILE.typesetter:pushHbox(hbox)
295+
SILE.typesetter:typeset(" ")
296+
else
297+
hbox.width = margin
298+
SILE.typesetter:pushHbox(hbox)
299+
end
300+
end)
301+
282302
-- Style and locale loading
283303

284304
self:registerCommand("bibliographystyle", function (options, _)
@@ -390,9 +410,31 @@ function package:registerCommands ()
390410
end
391411

392412
print("<bibliography: " .. #entries .. " entries>")
413+
if not SILE.typesetter:vmode() then
414+
SILE.call("par")
415+
end
393416
local engine = self:getCslEngine()
394417
local cite = engine:reference(entries)
395-
SILE.processString(("<sile>%s</sile>"):format(cite), "xml")
418+
SILE.settings:temporarily(function ()
419+
local hanging_indent = SU.boolean(engine.bibliography.options["hanging-indent"], false)
420+
local must_align = engine.bibliography.options["second-field-align"]
421+
local lskip = (SILE.settings:get("document.lskip") or SILE.types.node.glue()):absolute()
422+
if hanging_indent or must_align then
423+
-- Respective to the fixed part of the current lskip, all lines are indented
424+
-- but the first one.
425+
local indent = SILE.settings:get("bibliography.indent"):absolute()
426+
SILE.settings:set("document.lskip", lskip.width + indent)
427+
SILE.settings:set("document.parindent", - indent)
428+
SILE.settings:set("current.parindent", - indent)
429+
else
430+
-- Fixed part of the current lskip, and no paragraph indentation
431+
SILE.settings:set("document.lskip", lskip.width)
432+
SILE.settings:set("document.parindent", SILE.types.length())
433+
SILE.settings:set("current.parindent", SILE.types.length())
434+
end
435+
SILE.processString(("<sile>%s</sile>"):format(cite), "xml")
436+
SILE.call("par")
437+
end)
396438

397439
SILE.scratch.bibtex.cited = { keys = {}, citnums = {} }
398440
end, "Produce a bibliography of references.")

0 commit comments

Comments
 (0)