• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 11573668360

29 Oct 2024 12:17PM UTC coverage: 58.059% (-9.6%) from 67.697%
11573668360

push

github

web-flow
Merge pull request #2139 from Omikhleia/fix-math-tex-limits

TeX-math limits and other commands behaving as big ops

6 of 11 new or added lines in 1 file covered. (54.55%)

1797 existing lines in 50 files now uncovered.

10360 of 17844 relevant lines covered (58.06%)

3713.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

43.53
/packages/linespacing/init.lua
1
local base = require("packages.base")
1✔
2

3
local package = pl.class(base)
1✔
4
package._name = "linespacing"
1✔
5

6
local metrics = require("fontmetrics")
1✔
7

8
local metricscache = {}
1✔
9

10
local getLineMetrics = function (l)
UNCOV
11
   local linemetrics = { ascender = 0, descender = 0, lineheight = SILE.types.length() }
×
UNCOV
12
   if not l or not l.nodes then
×
13
      return linemetrics
×
14
   end
UNCOV
15
   for i = 1, #l.nodes do
×
UNCOV
16
      local node = l.nodes[i]
×
UNCOV
17
      if node.is_nnode then
×
UNCOV
18
         local m = metricscache[SILE.font._key(node.options)]
×
UNCOV
19
         if not m then
×
UNCOV
20
            local face = SILE.font.cache(node.options, SILE.shaper.getFace)
×
UNCOV
21
            m = metrics.get_typographic_extents(face)
×
UNCOV
22
            m.ascender = m.ascender * node.options.size
×
UNCOV
23
            m.descender = m.descender * node.options.size
×
UNCOV
24
            metricscache[SILE.font._key(node.options)] = m
×
25
         end
UNCOV
26
         SILE.settings:temporarily(function ()
×
UNCOV
27
            SILE.call("font", node.options, {})
×
UNCOV
28
            m.lineheight = SU.cast("length", SILE.settings:get("linespacing.css.line-height")):absolute()
×
29
         end)
UNCOV
30
         if m.ascender > linemetrics.ascender then
×
UNCOV
31
            linemetrics.ascender = m.ascender
×
32
         end
UNCOV
33
         if m.descender > linemetrics.descender then
×
UNCOV
34
            linemetrics.descender = m.descender
×
35
         end
UNCOV
36
         if m.lineheight > linemetrics.lineheight then
×
UNCOV
37
            linemetrics.lineheight = m.lineheight
×
38
         end
39
      end
40
   end
UNCOV
41
   return linemetrics
×
42
end
43

44
local linespacingLeading = function (_, vbox, previous)
45
   local method = SILE.settings:get("linespacing.method")
9✔
46

47
   local firstline = SILE.settings:get("linespacing.minimumfirstlineposition"):absolute()
18✔
48
   if not previous then
9✔
49
      if firstline.length:tonumber() > 0 then
4✔
UNCOV
50
         local toAdd = SILE.types.length(firstline.length - vbox.height)
×
UNCOV
51
         return SILE.types.node.vkern(toAdd)
×
52
      else
53
         return nil
2✔
54
      end
55
   end
56

57
   if method == "tex" then
7✔
UNCOV
58
      return SILE.typesetters.base:leadingFor(vbox, previous)
×
59
   end
60

61
   if method == "fit-glyph" then
7✔
UNCOV
62
      local extra = SILE.settings:get("linespacing.fit-glyph.extra-space"):absolute()
×
UNCOV
63
      local toAdd = SILE.types.length(extra)
×
UNCOV
64
      return SILE.types.node.vglue(toAdd)
×
65
   end
66

67
   if method == "fixed" then
7✔
68
      local btob = SILE.settings:get("linespacing.fixed.baselinedistance"):absolute()
14✔
69
      local toAdd = SILE.types.length(btob.length - (vbox.height + previous.depth), btob.stretch, btob.shrink)
21✔
70
      return SILE.types.node.vglue(toAdd)
7✔
71
   end
72

73
   -- For these methods, we need to read the font metrics
UNCOV
74
   if not metrics then
×
75
      SU.error("'" .. method .. "' line spacing method requires font metrics module, which is not available")
×
76
   end
77

UNCOV
78
   local thismetrics = getLineMetrics(vbox)
×
UNCOV
79
   local prevmetrics = getLineMetrics(previous)
×
UNCOV
80
   if method == "fit-font" then
×
81
      -- Distance to next baseline is max(descender) of fonts on previous +
82
      -- max(ascender) of fonts on next
UNCOV
83
      local extra = SILE.settings:get("linespacing.fit-font.extra-space"):absolute()
×
UNCOV
84
      local btob = prevmetrics.descender + thismetrics.ascender + extra
×
UNCOV
85
      local toAdd = btob - (vbox.height + (previous and previous.depth or 0))
×
UNCOV
86
      return SILE.types.node.vglue(toAdd)
×
87
   end
88

UNCOV
89
   if method == "css" then
×
UNCOV
90
      local lh = prevmetrics.lineheight
×
UNCOV
91
      local leading = (lh - (prevmetrics.ascender + prevmetrics.descender))
×
UNCOV
92
      if previous then
×
UNCOV
93
         previous.height = previous.height + leading / 2
×
UNCOV
94
         previous.depth = previous.depth + leading / 2
×
95
      end
UNCOV
96
      return SILE.types.node.vglue()
×
97
   end
98

99
   SU.error("Unknown line spacing method " .. method)
×
100
end
101

102
function package:_init ()
1✔
103
   base._init(self)
1✔
104
   self.class:registerPostinit(function (_)
2✔
105
      SILE.typesetter.leadingFor = linespacingLeading
1✔
106
   end)
107
end
108

109
function package.declareSettings (_)
1✔
110
   SILE.settings:declare({
1✔
111
      parameter = "linespacing.method",
112
      default = "tex",
113
      type = "string",
114
      help = "How to set the line spacing (tex, fixed, fit-font, fit-glyph, css)",
115
   })
116

117
   SILE.settings:declare({
2✔
118
      parameter = "linespacing.fixed.baselinedistance",
119
      default = SILE.types.length("1.2em"),
2✔
120
      type = "length",
121
      help = "Distance from baseline to baseline in the case of fixed line spacing",
122
   })
123

124
   SILE.settings:declare({
2✔
125
      parameter = "linespacing.minimumfirstlineposition",
126
      default = SILE.types.length(0),
2✔
127
      type = "length",
128
   })
129

130
   SILE.settings:declare({
2✔
131
      parameter = "linespacing.fit-glyph.extra-space",
132
      default = SILE.types.length(0),
2✔
133
      type = "length",
134
   })
135

136
   SILE.settings:declare({
2✔
137
      parameter = "linespacing.fit-font.extra-space",
138
      default = SILE.types.length(0),
2✔
139
      type = "length",
140
   })
141

142
   SILE.settings:declare({
2✔
143
      parameter = "linespacing.css.line-height",
144
      default = SILE.types.length("1.2em"),
2✔
145
      type = "length",
146
   })
147
end
148

149
function package:registerCommands ()
1✔
150
   self:registerCommand("linespacing-on", function ()
2✔
151
      SILE.typesetter.leadingFor = linespacingLeading
×
152
   end)
153

154
   self:registerCommand("linespacing-off", function ()
2✔
155
      SILE.typesetter.leadingFor = SILE.typesetters.base.leadingFor
×
156
   end)
157
end
158

159
package.documentation = [[
160
\begin{document}
161
\linespacing-on
162
SILE’s default method of inserting leading between lines should be familiar to users of TeX, but it is not the most friendly system for book designers.
163
The \autodoc:package{linespacing} package provides a better choice of leading systems.
164

165
After loading the package, you are able to choose the linespacing mode by setting the \autodoc:setting{linespacing.method} parameter.
166
The following examples have funny sized words in them so that you can see how the different methods interact.
167

168
By default, this is set to \code{tex}. The other options available are:
169

170
\medskip
171
\set[parameter=linespacing.method,value=fixed]
172
\set[parameter=linespacing.fixed.baselinedistance,value=1.5em]
173
\begin{itemize}
174
\item{\code{fixed}. This set the lines at a fixed baseline-to-baseline distance, determined by the \autodoc:setting{linespacing.fixed.baselinedistance} parameter.
175
You can specify this parameter either relative to the type size (\code{1.2em}) or as a absolute distance (\code{15pt}).
176
This paragraph is set with a fixed 1.5em baseline-to-baseline distance.}
177
\end{itemize}
178

179
\medskip
180
\set[parameter=linespacing.method,value=fit-glyph]
181
\begin{itemize}
182
\item{\code{fit-glyph}. This sets the lines solid; that is, the lowest point on line 1 (either a descender like \font[size=20pt]{q} or, if there are no descenders, the baseline) will touch the \font[size=20pt]{highest} point of line 2, as in this paragraph.
183
You generally don’t want to use this as-is.}
184
\end{itemize}
185

186
\set[parameter=linespacing.fit-glyph.extra-space,value=5pt]
187

188
What you probably want to do is insert a constant (relative or absolute) s\font[size=20pt]{p}ace between the lines by setting the \autodoc:setting{linespacing.fit-glyph.extra-space} parameter.
189
\font[size=20pt]{T}his paragraph is set with 5 points of space between the descenders and the ascenders.
190

191
\medskip
192
\set[parameter=linespacing.method,value=fit-font]
193
\begin{itemize}
194
\item{\code{fit-font}. This inspects each \code{hbox} on the line, and asks the fonts it finds for their bounding boxes—the highest ascender and the lower descender.
195
It then sets the lines solid.
196
Essentially each character is treated as if it is the same height, rather like composing a slug of metal type.
197
If there are things other than text on your line, or the text is buried inside other boxes, this may not work well.}
198
\end{itemize}
199

200
\set[parameter=linespacing.fit-font.extra-space,value=5pt]
201

202
As with \code{fit-glyph}, you can insert extra space between the lines with the \autodoc:setting{linespacing.fit-font.extra-space} parameter.
203

204
\medskip
205
\set[parameter=linespacing.method,value=css]
206
\set[parameter=linespacing.css.line-height,value=2em]
207
\begin{itemize}
208
\item{\code{css}. This is similar to the method used in browsers; the baseline distance is set with the \autodoc:setting{linespacing.css.line-height} parameter, and the excess \font[size=20pt]{space} between this parameter and the actual height of the line is distributed between the top and bottom of the line.}
209
\end{itemize}
210
\medskip
211

212
\linespacing-off
213
\end{document}
214
]]
1✔
215

216
return package
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc