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

sile-typesetter / sile / 9441244789

10 Jun 2024 01:45AM UTC coverage: 49.048% (-11.6%) from 60.675%
9441244789

push

github

web-flow
Merge 8a4989eae into 519864108

8320 of 16963 relevant lines covered (49.05%)

1813.12 hits per line

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

0.0
/packages/rules/init.lua
1
local base = require("packages.base")
×
2

3
local package = pl.class(base)
×
4
package._name = "rules"
×
5

6
local function getUnderlineParameters ()
7
   local ot = require("core.opentype-parser")
×
8
   local fontoptions = SILE.font.loadDefaults({})
×
9
   local face = SILE.font.cache(fontoptions, SILE.shaper.getFace)
×
10
   local font = ot.parseFont(face)
×
11
   local upem = font.head.unitsPerEm
×
12
   local underlinePosition = font.post.underlinePosition / upem * fontoptions.size
×
13
   local underlineThickness = font.post.underlineThickness / upem * fontoptions.size
×
14
   return underlinePosition, underlineThickness
×
15
end
16

17
local function getStrikethroughParameters ()
18
   local ot = require("core.opentype-parser")
×
19
   local fontoptions = SILE.font.loadDefaults({})
×
20
   local face = SILE.font.cache(fontoptions, SILE.shaper.getFace)
×
21
   local font = ot.parseFont(face)
×
22
   local upem = font.head.unitsPerEm
×
23
   local yStrikeoutPosition = font.os2.yStrikeoutPosition / upem * fontoptions.size
×
24
   local yStrikeoutSize = font.os2.yStrikeoutSize / upem * fontoptions.size
×
25
   return yStrikeoutPosition, yStrikeoutSize
×
26
end
27

28
-- \hfill (from the "plain" class) and \leaders (from the "leaders" package) use glues,
29
-- so we behave the same for hrulefill.
30
local hrulefillglue = pl.class(SILE.types.node.hfillglue)
×
31
hrulefillglue.raise = SILE.types.measurement()
×
32
hrulefillglue.thickness = SILE.types.measurement("0.2pt")
×
33

34
function hrulefillglue:outputYourself (typesetter, line)
×
35
   local outputWidth = SU.rationWidth(self.width, self.width, line.ratio):tonumber()
×
36
   local oldx = typesetter.frame.state.cursorX
×
37
   typesetter.frame:advancePageDirection(-self.raise)
×
38
   typesetter.frame:advanceWritingDirection(outputWidth)
×
39
   local newx = typesetter.frame.state.cursorX
×
40
   local newy = typesetter.frame.state.cursorY
×
41
   SILE.outputter:drawRule(oldx, newy, newx - oldx, self.thickness)
×
42
   typesetter.frame:advancePageDirection(self.raise)
×
43
end
44

45
function package:_init ()
×
46
   base._init(self)
×
47
   self:loadPackage("raiselower")
×
48
   self:loadPackage("rebox")
×
49
end
50

51
function package:registerCommands ()
×
52
   self:registerCommand("hrule", function (options, _)
×
53
      local width = SU.cast("length", options.width)
×
54
      local height = SU.cast("length", options.height)
×
55
      local depth = SU.cast("length", options.depth)
×
56
      SILE.typesetter:pushHbox({
×
57
         width = width:absolute(),
58
         height = height:absolute(),
59
         depth = depth:absolute(),
60
         value = options.src,
61
         outputYourself = function (node, typesetter, line)
62
            local outputWidth = SU.rationWidth(node.width, node.width, line.ratio)
×
63
            typesetter.frame:advancePageDirection(-node.height)
×
64
            local oldx = typesetter.frame.state.cursorX
×
65
            local oldy = typesetter.frame.state.cursorY
×
66
            typesetter.frame:advanceWritingDirection(outputWidth)
×
67
            typesetter.frame:advancePageDirection(node.height + node.depth)
×
68
            local newx = typesetter.frame.state.cursorX
×
69
            local newy = typesetter.frame.state.cursorY
×
70
            SILE.outputter:drawRule(oldx, oldy, newx - oldx, newy - oldy)
×
71
            typesetter.frame:advancePageDirection(-node.depth)
×
72
         end,
73
      })
74
   end, "Draws a blob of ink of width <width>, height <height> and depth <depth>")
×
75

76
   self:registerCommand("hrulefill", function (options, _)
×
77
      local raise
78
      local thickness
79
      if options.position and options.raise then
×
80
         SU.error("hrulefill cannot have both position and raise parameters")
×
81
      end
82
      if options.thickness then
×
83
         thickness = SU.cast("measurement", options.thickness)
×
84
      end
85
      if options.position == "underline" then
×
86
         local underlinePosition, underlineThickness = getUnderlineParameters()
×
87
         thickness = thickness or underlineThickness
×
88
         raise = underlinePosition
×
89
      elseif options.position == "strikethrough" then
×
90
         local yStrikeoutPosition, yStrikeoutSize = getStrikethroughParameters()
×
91
         thickness = thickness or yStrikeoutSize
×
92
         raise = yStrikeoutPosition + thickness / 2
×
93
      elseif options.position then
×
94
         SU.error("Unknown hrulefill position '" .. options.position .. "'")
×
95
      else
96
         raise = SU.cast("measurement", options.raise or "0")
×
97
      end
98

99
      SILE.typesetter:pushExplicitGlue(hrulefillglue({
×
100
         raise = raise,
101
         thickness = thickness or SILE.types.measurement("0.2pt"),
102
      }))
103
   end, "Add a huge horizontal hrule glue")
×
104

105
   self:registerCommand("fullrule", function (options, _)
×
106
      local thickness = SU.cast("measurement", options.thickness or "0.2pt")
×
107
      local raise = SU.cast("measurement", options.raise or "0.5em")
×
108

109
      if options.height then
×
110
         SU.deprecated("\\fullrule[…, height=…]", "\\fullrule[…, thickness=…]", "0.13.1", "0.15.0")
×
111
      end
112
      if not SILE.typesetter:vmode() then
×
113
         SU.deprecated("\\fullrule in horizontal mode", "\\hrule or \\hrulefill", "0.13.1", "0.15.0")
×
114
      end
115
      if options.width then
×
116
         SU.deprecated("\\fullrule with width", "\\hrule and \\raise", "0.13.1 ", "0.15.0")
×
117
      end
118

119
      SILE.typesetter:leaveHmode()
×
120
      SILE.call("noindent")
×
121
      SILE.call("hrulefill", { raise = raise, thickness = thickness })
×
122
      SILE.typesetter:leaveHmode()
×
123
   end, "Draw a full width hrule centered on the current line")
×
124

125
   self:registerCommand("underline", function (_, content)
×
126
      local underlinePosition, underlineThickness = getUnderlineParameters()
×
127

128
      SILE.typesetter:liner("underline", content, function (box, typesetter, line)
×
129
         local oldX = typesetter.frame.state.cursorX
×
130
         local Y = typesetter.frame.state.cursorY
×
131

132
         -- Build the content.
133
         -- Cursor will be moved by the actual definitive size.
134
         box:outputContent(typesetter, line)
×
135
         local newX = typesetter.frame.state.cursorX
×
136

137
         -- Output a line.
138
         -- NOTE: According to the OpenType specs, underlinePosition is "the suggested distance of
139
         -- the top of the underline from the baseline" so it seems implied that the thickness
140
         -- should expand downwards
141
         SILE.outputter:drawRule(oldX, Y - underlinePosition, newX - oldX, underlineThickness)
×
142
      end)
143
   end, "Underlines some content")
×
144

145
   self:registerCommand("strikethrough", function (_, content)
×
146
      local yStrikeoutPosition, yStrikeoutSize = getStrikethroughParameters()
×
147

148
      SILE.typesetter:liner("strikethrough", content, function (box, typesetter, line)
×
149
         local oldX = typesetter.frame.state.cursorX
×
150
         local Y = typesetter.frame.state.cursorY
×
151

152
         -- Build the content.
153
         -- Cursor will be moved by the actual definitive size.
154
         box:outputContent(typesetter, line)
×
155
         local newX = typesetter.frame.state.cursorX
×
156

157
         -- Output a line.
158
         -- NOTE: The OpenType spec is not explicit regarding how the size
159
         -- (thickness) affects the position. We opt to distribute evenly
160
         SILE.outputter:drawRule(oldX, Y - yStrikeoutPosition - yStrikeoutSize / 2, newX - oldX, yStrikeoutSize)
×
161
      end)
162
   end, "Strikes out some content")
×
163

164
   self:registerCommand("boxaround", function (_, content)
×
165
      -- This command was not documented and lacks feature.
166
      -- Plan replacement with a better suited package.
167
      SU.deprecated("\\boxaround (undocumented)", "\\framebox (package)", "0.12.0")
×
168

169
      local hbox, hlist = SILE.typesetter:makeHbox(content)
×
170
      -- Re-wrap the hbox in another hbox responsible for boxing it at output
171
      -- time, when we will know the line contribution and can compute the scaled width
172
      -- of the box, taking into account possible stretching and shrinking.
173
      SILE.typesetter:pushHbox({
×
174
         inner = hbox,
175
         width = hbox.width,
176
         height = hbox.height,
177
         depth = hbox.depth,
178
         outputYourself = function (node, typesetter, line)
179
            local oldX = typesetter.frame.state.cursorX
×
180
            local Y = typesetter.frame.state.cursorY
×
181

182
            -- Build the original hbox.
183
            -- Cursor will be moved by the actual definitive size.
184
            node.inner:outputYourself(SILE.typesetter, line)
×
185
            local newX = typesetter.frame.state.cursorX
×
186

187
            -- Output a border
188
            -- NOTE: Drawn inside the hbox, so borders overlap with inner content.
189
            local w = newX - oldX
×
190
            local h = node.height:tonumber()
×
191
            local d = node.depth:tonumber()
×
192
            local thickness = 0.5
×
193

194
            SILE.outputter:drawRule(oldX, Y + d - thickness, w, thickness)
×
195
            SILE.outputter:drawRule(oldX, Y - h, w, thickness)
×
196
            SILE.outputter:drawRule(oldX, Y - h, thickness, h + d)
×
197
            SILE.outputter:drawRule(oldX + w - thickness, Y - h, thickness, h + d)
×
198
         end,
199
      })
200
      SILE.typesetter:pushHlist(hlist)
×
201
   end, "Draws a box around some content")
×
202
end
203

204
package.documentation = [[
205
\begin{document}
206
The \autodoc:package{rules} package provides several line-drawing commands.
207

208
The \autodoc:command{\hrule} command draws a blob of ink of a given \autodoc:parameter{width} (length), \autodoc:parameter{height} (above the current baseline), and \autodoc:parameter{depth} (below the current baseline).
209
Such rules are horizontal boxes, placed along the baseline of a line of text and treated just like other text to be output.
210
So, they can appear in the middle of a paragraph, like this:
211
\hrule[width=20pt, height=0.5pt]
212
(That one was generated with \autodoc:command{\hrule[width=20pt, height=0.5pt]}.)
213

214
The \autodoc:command{\underline} command \underline{underlines} its content.
215

216
The \autodoc:command{\strikethrough} command \strikethrough{strikes} its content.
217

218
Both commands support paragraph content spanning multiple lines.
219

220
\autodoc:note{The position and thickness of the underlines and strikethroughs are based on the metrics of the current font, honoring the values defined by the type designer.}
221

222
The \autodoc:command{\hrulefill} inserts an infinite horizontal rubber, similar to an \autodoc:command{\hfill}, but—as its name implies—filled with a rule (that is, a solid line).
223
By default, it stands on the baseline and has a thickness of 0.2pt, below the baseline.
224
It supports optional parameters \autodoc:parameter{raise=<dimension>} and \autodoc:parameter{thickness=<dimension>} to adjust the position and thickness of the line, respectively.
225
The former accepts a negative measurement, to lower the line.
226
Alternatively, use the \autodoc:parameter{position} option, which can be set to \code{underline} or \code{strikethrough}.
227
In that case, it honors the current font metrics and the line is drawn at the appropriate position and, by default, with the relevant thickness.
228
You can still set a custom thickness with the \autodoc:parameter{thickness} parameter.
229

230
For instance, \autodoc:command{\hrulefill[position=underline]} gives:
231
\hrulefill[position=underline]
232

233
Finally, \autodoc:command{\fullrule} draws a thin standalone rule across the width of a full text line.
234
Accepted parameters are \autodoc:parameter{raise} and \autodoc:parameter{thickness}, with the same meanings as above.
235
\end{document}
236
]]
×
237

238
return package
×
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