-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
init.lua
105 lines (89 loc) · 5.65 KB
/
init.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
local base = require("packages.base")
local package = pl.class(base)
package._name = "dropcaps"
function package:_init ()
base._init(self)
self:loadPackage("rebox")
self:loadPackage("raiselower")
end
local shapeHbox = function (options, content)
-- Clear irrelevant values before passing to font
options.lines, options.join, options.raise, options.shift, options.color, options.scale = nil, nil, nil, nil, nil, nil
SILE.call("noindent")
local hbox = SILE.typesetter:makeHbox(function ()
SILE.call("font", options, content)
end)
return hbox
end
function package:registerCommands ()
-- This implementation relies on the hangafter and hangindent features of Knuth's line-breaking algorithm.
-- These features in core line breaking algorithm supply the blank space in the paragraph shape but don't fill it with anything.
self:registerCommand("dropcap", function (options, content)
local lines = SU.cast("integer", options.lines or 3)
local join = SU.boolean(options.join, false)
local standoff = SU.cast("measurement", options.standoff or "1spc")
local raise = SU.cast("measurement", options.raise or 0)
local shift = SU.cast("measurement", options.shift or 0)
local size = SU.cast("measurement or nil", options.size or nil)
local scale = SU.cast("number", options.scale or 1.0)
local color = options.color
options.size = nil -- we need to measure the "would have been" size before using this
if color then self:loadPackage("color") end
-- We want the drop cap to span over N lines, that is N - 1 baselineskip + the height of the first line.
-- Note this only works for the default linespace mechanism.
-- We determine the height of the first line by measuring the size the initial content *would have* been.
-- This gives the font some control over its relative size, sometimes desired sometimes undesired.
local tmpHbox = shapeHbox(options, content)
local extraHeight = SILE.measurement((lines - 1).."bs"):tonumber()
local targetHeight = tmpHbox.height:tonumber() * scale + extraHeight
SU.debug("dropcaps", "Target height", targetHeight)
-- Now we need to figure out how to scale the dropcap font to get an initial of targetHeight.
-- From that we can also figure out the width it will be at that height.
local curSize = SILE.measurement(SILE.settings:get("font.size")):tonumber()
local curHeight, curWidth = tmpHbox.height:tonumber(), tmpHbox.width:tonumber()
options.size = size and size:tonumber() or (targetHeight / curHeight * curSize)
local targetWidth = curWidth / curSize * options.size
SU.debug("dropcaps", "Target font size", options.size)
SU.debug("dropcaps", "Target width", targetWidth)
-- Typeset the dropcap with its final shape, but don't output it yet
local hbox = shapeHbox(options, content)
-- Setup up the necessary indents for the final paragraph content
local joinOffset = join and standoff:tonumber() or 0
SILE.settings:set("current.hangAfter", -lines)
SILE.settings:set("current.hangIndent", targetWidth + joinOffset)
SU.debug("dropcaps", "joinOffset", joinOffset)
-- The paragraph is indented so as to leave enough space for the drop cap.
-- We "trick" the typesetter with a zero-dimension box wrapping our original box.
SILE.call("rebox", { height = 0, width = -joinOffset }, function ()
SILE.call("glue", { width = shift - targetWidth - joinOffset })
SILE.call("lower", { height = extraHeight - raise }, function ()
SILE.call(color and "color" or "noop", { color = color }, function ()
SILE.typesetter:pushHbox(hbox)
end)
end)
end)
end, "Show an 'initial capital' (also known as a 'drop cap') at the start of the content paragraph.")
end
package.documentation = [[
\begin{document}
The \autodoc:package{dropcaps} package allows you to format paragraphs with an “initial capital” (also commonly referred as a “drop cap”), typically one large capital letter used as a decorative element at the beginning of a paragraph.
It provides the \autodoc:command{\dropcap} command.
The content passed will be the initial character(s).
The primary option is \autodoc:parameter{lines}, an integer specifying the number of lines to span (defaults to \code{3}).
The scale of the characters can be adjusted relative to the first line using the \autodoc:parameter{scale} option (defaults to \code{1.0}).
The \autodoc:parameter{join} parameter is a boolean for whether to join the dropcap to the first line (defaults to \code{false}).
If \autodoc:parameter{join} is \code{true}, the value of the \autodoc:parameter{standoff} option (defaults to \code{1spc}) is applied to all but the first line.
Optionally \autodoc:parameter{color} can be passed to change the typeface color, which is sometimes useful to offset the apparent weight of a large glyph.
To tweak the position of the dropcap, measurements may be passed to the \autodoc:parameter{raise} and \autodoc:parameter{shift} options.
Other options passed to \autodoc:command{\dropcap} will be passed through to \autodoc:command{\font} when drawing the initial letter(s).
This may be useful for passing OpenType options or other font preferences.
\begin{note}
One caveat is that the size of the initials is calculated using the default linespacing mechanism.
If you are using an alternative method from the \autodoc:package{linespacing} package, you might see strange results.
Set the \autodoc:setting{document.baselineskip} to approximate your effective leading value for best results.
If that doesn't work set the size manually.
Using \code{SILE.setCommandDefaults()} can be helpful for so you don't have to set the size every time.
\end{note}
\end{document}
]]
return package