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

sile-typesetter / sile / 9304049654

30 May 2024 02:12PM UTC coverage: 60.021% (-14.7%) from 74.707%
9304049654

push

github

web-flow
Merge 1a26b4f22 into a1fd105f8

6743 of 12900 new or added lines in 186 files covered. (52.27%)

347 existing lines in 49 files now uncovered.

10311 of 17179 relevant lines covered (60.02%)

3307.34 hits per line

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

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

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

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

17
local function getStrikethroughParameters ()
NEW
18
   local ot = require("core.opentype-parser")
×
NEW
19
   local fontoptions = SILE.font.loadDefaults({})
×
NEW
20
   local face = SILE.font.cache(fontoptions, SILE.shaper.getFace)
×
NEW
21
   local font = ot.parseFont(face)
×
NEW
22
   local upem = font.head.unitsPerEm
×
NEW
23
   local yStrikeoutPosition = font.os2.yStrikeoutPosition / upem * fontoptions.size
×
NEW
24
   local yStrikeoutSize = font.os2.yStrikeoutSize / upem * fontoptions.size
×
NEW
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.
NEW
30
local hrulefillglue = pl.class(SILE.types.node.hfillglue)
×
NEW
31
hrulefillglue.raise = SILE.types.measurement()
×
NEW
32
hrulefillglue.thickness = SILE.types.measurement("0.2pt")
×
33

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

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

UNCOV
51
function package:registerCommands ()
×
NEW
52
   self:registerCommand("hrule", function (options, _)
×
NEW
53
      local width = SU.cast("length", options.width)
×
NEW
54
      local height = SU.cast("length", options.height)
×
NEW
55
      local depth = SU.cast("length", options.depth)
×
NEW
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)
NEW
62
            local outputWidth = SU.rationWidth(node.width, node.width, line.ratio)
×
NEW
63
            typesetter.frame:advancePageDirection(-node.height)
×
NEW
64
            local oldx = typesetter.frame.state.cursorX
×
NEW
65
            local oldy = typesetter.frame.state.cursorY
×
NEW
66
            typesetter.frame:advanceWritingDirection(outputWidth)
×
NEW
67
            typesetter.frame:advancePageDirection(node.height + node.depth)
×
NEW
68
            local newx = typesetter.frame.state.cursorX
×
NEW
69
            local newy = typesetter.frame.state.cursorY
×
NEW
70
            SILE.outputter:drawRule(oldx, oldy, newx - oldx, newy - oldy)
×
NEW
71
            typesetter.frame:advancePageDirection(-node.depth)
×
72
         end,
73
      })
NEW
74
   end, "Draws a blob of ink of width <width>, height <height> and depth <depth>")
×
75

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

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

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

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

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

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

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

132
         -- Build the content.
133
         -- Cursor will be moved by the actual definitive size.
NEW
134
         box:outputContent(typesetter, line)
×
NEW
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
NEW
141
         SILE.outputter:drawRule(oldX, Y - underlinePosition, newX - oldX, underlineThickness)
×
142
      end)
NEW
143
   end, "Underlines some content")
×
144

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

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

152
         -- Build the content.
153
         -- Cursor will be moved by the actual definitive size.
NEW
154
         box:outputContent(typesetter, line)
×
NEW
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
NEW
160
         SILE.outputter:drawRule(oldX, Y - yStrikeoutPosition - yStrikeoutSize / 2, newX - oldX, yStrikeoutSize)
×
161
      end)
NEW
162
   end, "Strikes out some content")
×
163

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

NEW
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.
NEW
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)
NEW
179
            local oldX = typesetter.frame.state.cursorX
×
NEW
180
            local Y = typesetter.frame.state.cursorY
×
181

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

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

NEW
194
            SILE.outputter:drawRule(oldX, Y + d - thickness, w, thickness)
×
NEW
195
            SILE.outputter:drawRule(oldX, Y - h, w, thickness)
×
NEW
196
            SILE.outputter:drawRule(oldX, Y - h, thickness, h + d)
×
NEW
197
            SILE.outputter:drawRule(oldX + w - thickness, Y - h, thickness, h + d)
×
198
         end,
199
      })
NEW
200
      SILE.typesetter:pushHlist(hlist)
×
NEW
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}
UNCOV
236
]]
×
237

UNCOV
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