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

sile-typesetter / sile / 13921080357

18 Mar 2025 10:32AM UTC coverage: 32.02% (-26.4%) from 58.465%
13921080357

push

github

alerque
style: Restyle and normalize Lua files with stylua

0 of 9 new or added lines in 1 file covered. (0.0%)

4776 existing lines in 29 files now uncovered.

6381 of 19928 relevant lines covered (32.02%)

4191.61 hits per line

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

78.47
/classes/plain.lua
1
--- plain document class.
2
-- @use classes.plain
3

4
local base = require("classes.base")
194✔
5

6
local class = pl.class(base)
194✔
7
class._name = "plain"
194✔
8

9
class.defaultFrameset = {
194✔
10
   content = {
194✔
11
      left = "5%pw",
12
      right = "95%pw",
13
      top = "5%ph",
14
      bottom = "top(footnotes)",
15
   },
194✔
16
   folio = {
194✔
17
      left = "left(content)",
18
      right = "right(content)",
19
      top = "bottom(footnotes)+2%ph",
20
      bottom = "97%ph",
21
   },
194✔
22
   footnotes = {
194✔
23
      left = "left(content)",
24
      right = "right(content)",
25
      height = "0",
26
      bottom = "90%ph",
27
   },
194✔
28
}
194✔
29
class.firstContentFrame = "content"
194✔
30

31
local skips = {
194✔
32
   small = "3pt plus 1pt minus 1pt",
33
   med = "6pt plus 2pt minus 2pt",
34
   big = "12pt plus 4pt minus 4pt",
35
}
36

37
function class:_init (options)
194✔
38
   base._init(self, options)
194✔
39
   self:loadPackage("bidi")
194✔
40
   self:loadPackage("folio")
194✔
41
end
42

43
function class:declareOptions ()
194✔
44
   base.declareOptions(self)
194✔
45
   self:declareOption("direction", function (_, value)
388✔
46
      if value then
6✔
47
         SILE.documentState.direction = value
6✔
48
         SILE.settings:set("font.direction", value, true)
6✔
49
         for _, frame in pairs(self.defaultFrameset) do
24✔
50
            if not frame.direction then
18✔
51
               frame.direction = value
18✔
52
            end
53
         end
54
      end
55
      return SILE.documentState.direction
6✔
56
   end)
57
end
58

59
function class:setOptions (options)
194✔
60
   -- TODO: set a default direction here?
61
   base.setOptions(self, options)
194✔
62
end
63

64
function class:declareSettings ()
194✔
65
   base.declareSettings(self)
194✔
66
   for k, v in pairs(skips) do
776✔
67
      SILE.settings:declare({
1,164✔
68
         parameter = "plain." .. k .. "skipamount",
582✔
69
         type = "vglue",
70
         default = SILE.types.node.vglue(v),
1,164✔
71
         help = "The amount of a \\" .. k .. "skip",
582✔
72
      })
73
   end
74
end
75

76
function class:registerCommands ()
194✔
77
   SILE.classes.base.registerCommands(self)
194✔
78

79
   self:registerCommand("noindent", function (_, content)
388✔
80
      if #SILE.typesetter.state.nodes ~= 0 then
109✔
81
         SU.warn([[
2✔
82
            \noindent was called after paragraph content has already been processed
83

84
            This will not result in avoiding the current paragraph being indented. This
85
            function must be called before any content belonging to the paragraph is
86
            processed. If the intent was to suppress indentation of a following paragraph,
87
            first explicitly close the current paragraph. From an input document this is
88
            typically done with an empty line between paragraphs, but calling the \par
89
            command explicitly or from Lua code running SILE.call("par") will end
90
            the current paragraph.
91
         ]])
1✔
92
      end
93
      SILE.settings:set("current.parindent", SILE.types.node.glue())
218✔
94
      SILE.process(content)
109✔
95
   end, "Do not add an indent to the start of this paragraph")
303✔
96

97
   self:registerCommand("neverindent", function (_, content)
388✔
98
      SILE.settings:set("current.parindent", SILE.types.node.glue())
140✔
99
      SILE.settings:set("document.parindent", SILE.types.node.glue())
140✔
100
      SILE.process(content)
70✔
101
   end, "Turn off all indentation")
264✔
102

103
   self:registerCommand("indent", function (_, content)
388✔
104
      SILE.settings:set("current.parindent", SILE.settings:get("document.parindent"))
8✔
105
      SILE.process(content)
4✔
106
   end, "Do add an indent to the start of this paragraph, even if previously told otherwise")
198✔
107

108
   for k, _ in pairs(skips) do
776✔
109
      self:registerCommand(k .. "skip", function (_, _)
1,164✔
110
         SILE.typesetter:leaveHmode()
55✔
111
         SILE.typesetter:pushExplicitVglue(SILE.settings:get("plain." .. k .. "skipamount"))
110✔
112
      end, "Skip vertically by a " .. k .. " amount")
1,219✔
113
   end
114

115
   self:registerCommand("hfill", function (_, _)
388✔
116
      SILE.typesetter:pushExplicitGlue(SILE.types.node.hfillglue())
50✔
117
   end, "Add a huge horizontal glue")
219✔
118

119
   self:registerCommand("vfill", function (_, _)
388✔
120
      SILE.typesetter:leaveHmode()
406✔
121
      SILE.typesetter:pushExplicitVglue(SILE.types.node.vfillglue())
812✔
122
   end, "Add huge vertical glue")
600✔
123

124
   self:registerCommand("hss", function (_, _)
388✔
125
      SILE.typesetter:pushGlue(SILE.types.node.hssglue())
×
126
      table.insert(SILE.typesetter.state.nodes, SILE.types.node.zerohbox())
×
127
   end, "Add glue which stretches and shrinks horizontally (good for centering)")
194✔
128

129
   self:registerCommand("vss", function (_, _)
388✔
130
      SILE.typesetter:pushExplicitVglue(SILE.types.node.vssglue())
×
131
   end, "Add glue which stretches and shrinks vertically")
194✔
132

133
   local _thinspacewidth = SILE.types.measurement(0.16667, "em")
194✔
134

135
   self:registerCommand("thinspace", function (_, _)
388✔
136
      SILE.call("glue", { width = _thinspacewidth })
×
137
   end)
138

139
   self:registerCommand("negthinspace", function (_, _)
388✔
140
      SILE.call("glue", { width = -_thinspacewidth })
×
141
   end)
142

143
   self:registerCommand("enspace", function (_, _)
388✔
144
      SILE.call("glue", { width = SILE.types.measurement(1, "en") })
×
145
   end)
146

147
   self:registerCommand("relax", function (_, _) end)
194✔
148

149
   self:registerCommand("enskip", function (_, _)
388✔
150
      SILE.call("enspace")
×
151
   end)
152

153
   local _quadwidth = SILE.types.measurement(1, "em")
194✔
154

155
   self:registerCommand("quad", function (_, _)
388✔
156
      SILE.call("glue", { width = _quadwidth })
1✔
157
   end)
158

159
   self:registerCommand("qquad", function (_, _)
388✔
160
      SILE.call("glue", { width = _quadwidth * 2 })
90✔
161
   end)
162

163
   self:registerCommand("slash", function (_, _)
388✔
164
      SILE.typesetter:typeset("/")
×
165
      SILE.call("penalty", { penalty = 50 })
×
166
   end)
167

168
   self:registerCommand("break", function (_, _)
388✔
169
      SILE.call("penalty", { penalty = -10000 })
45✔
170
   end, "Requests a frame break (if in vertical mode) or a line break (if in horizontal mode)")
239✔
171

172
   self:registerCommand("cr", function (_, _)
388✔
173
      SILE.call("hfill")
3✔
174
      SILE.call("break")
3✔
175
   end, "Fills a line with a stretchable glue and then requests a line break")
197✔
176

177
   -- Despite their name, in older versions, \framebreak and \pagebreak worked badly in horizontal
178
   -- mode. The former was a linebreak, and the latter did nothing. That was surely not intended.
179
   -- There are many ways, though to assume what's wrong or what the user's intent ought to be.
180
   -- We now warn, and terminate the paragraph, but to all extents this might be a wrong approach to
181
   -- reconsider at some point.
182

183
   self:registerCommand("framebreak", function (_, _)
388✔
184
      if not SILE.typesetter:vmode() then
22✔
185
         SU.warn([[
×
186
            \\framebreak was not intended to work in horizontal mode
187

188
            Behavior may change in future versions.
189
         ]])
×
190
      end
191
      SILE.call("penalty", { penalty = -10000, vertical = true })
11✔
192
   end, "Requests a frame break (switching to vertical mode if needed)")
205✔
193

194
   self:registerCommand("pagebreak", function (_, _)
388✔
195
      if not SILE.typesetter:vmode() then
10✔
196
         SU.warn([[
×
197
            \\pagebreak was not intended to work in horizontal mode
198

199
            Behavior may change in future versions.
200
         ]])
×
201
      end
202
      SILE.call("penalty", { penalty = -20000, vertical = true })
5✔
203
   end, "Requests a non-negotiable page break (switching to vertical mode if needed)")
199✔
204

205
   self:registerCommand("nobreak", function (_, _)
388✔
206
      SILE.call("penalty", { penalty = 10000 })
×
207
   end, "Inhibits a frame break (if in vertical mode) or a line break (if in horizontal mode)")
194✔
208

209
   self:registerCommand("novbreak", function (_, _)
388✔
210
      SILE.call("penalty", { penalty = 10000, vertical = true })
21✔
211
   end, "Inhibits a frame break (switching to vertical mode if needed)")
215✔
212

213
   self:registerCommand(
388✔
214
      "allowbreak",
194✔
215
      function (_, _)
216
         SILE.call("penalty", { penalty = 0 })
×
217
      end,
218
      "Allows a page break (if in vertical mode) or a line break (if in horizontal mode) at a point would not be considered as suitable for breaking"
219
   )
194✔
220

221
   -- THIS SEEMS BROKEN BUT THE COMMAND NOT MENTIONED IN THE SILE MANUAL
222
   -- In TeX, "\filbreak" compensates the vertical fill if no break actually occurs
223
   -- (\def\filbreak{\par\vfil\penalty-200\vfilneg)
224
   self:registerCommand("filbreak", function (_, _)
388✔
225
      SILE.call("vfill")
×
226
      SILE.call("penalty", { penalty = -200 })
×
227
   end, "I HAVE THE SAME NAME AS A TEX COMMAND BUT DON'T SEEM TO BE THE SAME")
194✔
228

229
   -- NOTE: TeX's "\goodbreak" does a \par first, so always switches to vertical mode.
230
   -- SILE differs here, allowing it both within a paragraph (line breaking) and between
231
   -- paragraphs (page breaking).
232
   self:registerCommand("goodbreak", function (_, _)
388✔
233
      SILE.call("penalty", { penalty = -500 })
4✔
234
   end, "Indicates a good potential point to break a frame (if in vertical mode) or a line (if in horizontal mode")
198✔
235

236
   self:registerCommand("eject", function (_, _)
388✔
237
      SILE.call("vfill")
3✔
238
      SILE.call("break")
3✔
239
   end, "Fills the page with stretchable vglue and then request a page break")
197✔
240

241
   self:registerCommand("supereject", function (_, _)
388✔
242
      SILE.call("vfill")
204✔
243
      SILE.call("penalty", { penalty = -20000 })
204✔
244
   end, "Fills the page with stretchable vglue and then requests a non-negotiable page break")
398✔
245

246
   self:registerCommand("em", function (_, content)
388✔
247
      local style = SILE.settings:get("font.style")
92✔
248
      local toggle = (style and style:lower() == "italic") and "Regular" or "Italic"
184✔
249
      SILE.call("font", { style = toggle }, content)
92✔
250
   end, "Emphasizes its contents by switching the font style to italic (or back to regular if already italic)")
286✔
251

252
   self:registerCommand("strong", function (_, content)
388✔
253
      SILE.call("font", { weight = 700 }, content)
×
254
   end, "Sets the font weight to bold (700)")
194✔
255

256
   self:registerCommand("code", function (options, content)
388✔
257
      -- IMPLEMENTATION NOTE:
258
      -- The \code command came from the url package, though used in plenty of
259
      -- places. It was referring to the verbatim:font from the verbatim
260
      -- package, which _should_ be sort of unrelated.
261
      -- Trying to untangle the things here, by introducing the
262
      -- definition from the former, but it's of sub-quality...
263
      -- The ugly -3 size is a HACK of sorts.
UNCOV
264
      options.family = options.family or "Hack"
×
UNCOV
265
      if not options.size and not options.adjust then
×
UNCOV
266
         options.adjust = "ex-height"
×
267
      end
UNCOV
268
      SILE.call("font", options, content)
×
269
   end)
270

271
   self:registerCommand("nohyphenation", function (_, content)
388✔
272
      SILE.call("font", { language = "und" }, content)
×
273
   end)
274

275
   self:registerCommand("center", function (_, content)
388✔
276
      if #SILE.typesetter.state.nodes ~= 0 then
33✔
277
         SU.warn([[
×
278
            \\center environment started after other nodes in a paragraph
279

280
            Content may not be centered as expected.
281
         ]])
×
282
      end
283
      SILE.settings:temporarily(function ()
66✔
284
         local lskip = SILE.settings:get("document.lskip") or SILE.types.node.glue()
66✔
285
         local rskip = SILE.settings:get("document.rskip") or SILE.types.node.glue()
66✔
286
         SILE.settings:set("document.parindent", SILE.types.node.glue())
66✔
287
         SILE.settings:set("current.parindent", SILE.types.node.glue())
66✔
288
         SILE.settings:set("document.lskip", SILE.types.node.hfillglue(lskip.width.length))
66✔
289
         SILE.settings:set("document.rskip", SILE.types.node.hfillglue(rskip.width.length))
66✔
290
         SILE.settings:set("typesetter.parfillskip", SILE.types.node.glue())
66✔
291
         SILE.settings:set("document.spaceskip", SILE.types.length("1spc", 0, 0))
66✔
292
         SILE.process(content)
33✔
293
         SILE.call("par")
33✔
294
      end)
295
   end, "Typeset its contents in a centered block (keeping margins).")
227✔
296

297
   self:registerCommand("raggedright", function (_, content)
388✔
298
      SILE.settings:temporarily(function ()
14✔
299
         local lskip = SILE.settings:get("document.lskip") or SILE.types.node.glue()
14✔
300
         local rskip = SILE.settings:get("document.rskip") or SILE.types.node.glue()
14✔
301
         SILE.settings:set("document.lskip", SILE.types.node.glue(lskip.width.length))
14✔
302
         SILE.settings:set("document.rskip", SILE.types.node.hfillglue(rskip.width.length))
14✔
303
         SILE.settings:set("typesetter.parfillskip", SILE.types.node.glue())
14✔
304
         SILE.settings:set("document.spaceskip", SILE.types.length("1spc", 0, 0))
14✔
305
         SILE.process(content)
7✔
306
         SILE.call("par")
7✔
307
      end)
308
   end, "Typeset its contents in a left aligned block (keeping margins).")
201✔
309

310
   self:registerCommand("raggedleft", function (_, content)
388✔
311
      SILE.settings:temporarily(function ()
10✔
312
         local lskip = SILE.settings:get("document.lskip") or SILE.types.node.glue()
10✔
313
         local rskip = SILE.settings:get("document.rskip") or SILE.types.node.glue()
10✔
314
         SILE.settings:set("document.lskip", SILE.types.node.hfillglue(lskip.width.length))
10✔
315
         SILE.settings:set("document.rskip", SILE.types.node.glue(rskip.width.length))
10✔
316
         SILE.settings:set("typesetter.parfillskip", SILE.types.node.glue())
10✔
317
         SILE.settings:set("document.spaceskip", SILE.types.length("1spc", 0, 0))
10✔
318
         SILE.process(content)
5✔
319
         SILE.call("par")
5✔
320
      end)
321
   end, "Typeset its contents in a right aligned block (keeping margins).")
199✔
322

323
   self:registerCommand("justified", function (_, content)
388✔
324
      SILE.settings:temporarily(function ()
2✔
325
         local lskip = SILE.settings:get("document.lskip") or SILE.types.node.glue()
2✔
326
         local rskip = SILE.settings:get("document.rskip") or SILE.types.node.glue()
2✔
327
         -- Keep the fixed part of the margins for nesting but remove the stretchability.
328
         SILE.settings:set("document.lskip", SILE.types.node.glue(lskip.width.length))
2✔
329
         SILE.settings:set("document.rskip", SILE.types.node.glue(rskip.width.length))
2✔
330
         -- Reset parfillskip to its default value, in case the surrounding context
331
         -- is ragged and cancelled it.
332
         SILE.settings:set("typesetter.parfillskip", nil, false, true)
1✔
333
         SILE.settings:set("document.spaceskip", nil)
1✔
334
         SILE.process(content)
1✔
335
         SILE.call("par")
1✔
336
      end)
337
   end, "Typeset its contents in a justified block (keeping margins).")
195✔
338

339
   self:registerCommand("ragged", function (options, content)
388✔
340
      -- Fairly dubious command for compatibility
341
      local l = SU.boolean(options.left, false)
1✔
342
      local r = SU.boolean(options.right, false)
1✔
343
      if l and r then
1✔
344
         SILE.call("center", {}, content)
2✔
345
      elseif r then
×
346
         SILE.call("raggedleft", {}, content)
×
347
      elseif l then
×
348
         SILE.call("raggedright", {}, content)
×
349
      else
350
         SILE.call("justified", {}, content)
×
351
      end
352
   end)
353

354
   self:registerCommand("rightalign", function (_, content)
388✔
355
      SU.deprecated("\\rightalign", "\\raggedleft", "0.15.0", "0.17.0")
×
356
      SILE.call("raggedleft", {}, content)
×
357
   end)
358

359
   self:registerCommand("blockquote", function (_, content)
388✔
360
      SILE.call("smallskip")
1✔
361
      SILE.typesetter:leaveHmode()
1✔
362
      SILE.settings:temporarily(function ()
2✔
363
         local indent = SILE.types.measurement("2em"):absolute()
2✔
364
         local lskip = SILE.settings:get("document.lskip") or SILE.types.node.glue()
2✔
365
         local rskip = SILE.settings:get("document.rskip") or SILE.types.node.glue()
2✔
366
         -- We keep the stretcheability of the lskip and rskip: honoring text alignment
367
         -- from the parent context.
368
         SILE.settings:set("document.lskip", SILE.types.node.glue(lskip.width + indent))
3✔
369
         SILE.settings:set("document.rskip", SILE.types.node.glue(rskip.width + indent))
3✔
370
         SILE.settings:set("font.size", SILE.settings:get("font.size") * 0.95)
2✔
371
         SILE.process(content)
1✔
372
         SILE.typesetter:leaveHmode()
1✔
373
      end)
374
      SILE.call("smallskip")
1✔
375
   end, "A blockquote environment")
195✔
376

377
   self:registerCommand("quote", function (_, content)
388✔
378
      SU.deprecated(
×
379
         "\\quote",
380
         "\\pullquote or \\blockquote",
381
         "0.14.5",
382
         "0.16.0",
383
         [[
×
384
            The \quote command has *such* bad output it is being completely deprecated as
385
            unsuitable for general purpose use. The pullquote package
386
            (\use[module=packages.pullquote]) provides one alternative, and the blockquote
387
            environment provides another. But you can also copy and adapt the original
388
            source from the plain class if you need to maintain exact output past
389
            SILE v0.16.0.
390
         ]]
×
391
      )
392
      SILE.call("smallskip")
×
393
      SILE.call("par")
×
394
      local margin = SILE.types.measurement(2.5, "em")
×
395
      SILE.settings:set("document.lskip", margin)
×
396
      SILE.settings:set("document.lskip", margin)
×
397
      SILE.call("font", { size = SILE.types.measurement(0.8, "em") }, function ()
×
398
         SILE.call("noindent")
×
399
         SILE.process(content)
×
400
      end)
401
      SILE.call("par")
×
402
      SILE.settings:set("document.lskip", nil)
×
403
      SILE.settings:set("document.rskip", nil)
×
404
      SILE.call("smallskip")
×
405
   end)
406

407
   self:registerCommand("listitem", function (_, content)
388✔
408
      SU.deprecated(
×
409
         "\\listitem",
410
         "\\item",
411
         "0.14.6",
412
         "0.16.0",
413
         [[
×
414
            The new list package (\use[module=packages.lists) has much better typography
415
            for lists. If you want to maintain the exact output of listitem past
416
            SILE v0.16.0 copy the source of \listitem from the plain class into your
417
            project.
418
         ]]
×
419
      )
420
      SILE.call("medskip")
×
421
      SILE.typesetter:typeset("• ")
×
422
      SILE.process(content)
×
423
      SILE.call("medskip")
×
424
   end)
425

426
   self:registerCommand("sloppy", function (_, _)
388✔
427
      SILE.settings:set("linebreak.tolerance", 9999)
×
428
   end)
429

430
   self:registerCommand("awful", function (_, _)
388✔
431
      SILE.settings:set("linebreak.tolerance", 10000)
×
432
   end)
433

434
   self:registerCommand("hbox", function (_, content)
388✔
435
      local hbox, hlist = SILE.typesetter:makeHbox(content)
72✔
436
      SILE.typesetter:pushHbox(hbox)
72✔
437
      if #hlist > 0 then
72✔
438
         SU.warn([[
×
439
            \\hbox has migrating content
440

441
            Ignored for now, but likely to break in future versions.
442
         ]])
×
443
         -- Ugly shim:
444
         -- One day we ought to do SILE.typesetter:pushHlist(hlist) here, so as to push
445
         -- back the migrating contents from within the hbox'ed content.
446
         -- However, old Lua code assumed the hbox to be returned, and sometimes removed it
447
         -- from the typesetter queue (for measuring, etc.), assuming it was the last
448
         -- element in the queue...
449
      end
450
      return hbox
72✔
451
   end, "Compiles all the enclosed horizontal-mode material into a single hbox")
194✔
452

453
   self:registerCommand("vbox", function (options, content)
388✔
454
      local vbox
455
      SILE.settings:temporarily(function ()
90✔
456
         if options.width then
45✔
457
            SILE.settings:set("typesetter.breakwidth", SILE.types.length(options.width))
×
458
         end
459
         SILE.typesetter:pushState()
45✔
460
         SILE.process(content)
45✔
461
         SILE.typesetter:leaveHmode(1)
45✔
462
         vbox = SILE.pagebuilder:collateVboxes(SILE.typesetter.state.outputQueue)
90✔
463
         SILE.typesetter:popState()
45✔
464
      end)
465
      return vbox
45✔
466
   end, "Compiles all the enclosed material into a single vbox")
194✔
467
end
468

469
return class
194✔
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