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

sile-typesetter / sile / 6934957716

20 Nov 2023 07:35PM UTC coverage: 57.468% (-3.2%) from 60.703%
6934957716

push

github

web-flow
Merge c91d9a7d4 into 34e2e5335

60 of 79 new or added lines in 1 file covered. (75.95%)

717 existing lines in 27 files now uncovered.

8957 of 15586 relevant lines covered (57.47%)

5715.38 hits per line

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

76.58
/classes/plain.lua
1
local base = require("classes.base")
173✔
2

3
local class = pl.class(base)
173✔
4
class._name = "plain"
173✔
5

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

28
local skips = {
173✔
29
  small = "3pt plus 1pt minus 1pt",
30
  med = "6pt plus 2pt minus 2pt",
31
  big = "12pt plus 4pt minus 4pt"
×
32
}
33

34
function class:_init (options)
173✔
35
  base._init(self, options)
173✔
36
  self:loadPackage("bidi")
173✔
37
  self:loadPackage("folio")
173✔
38
end
39

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

56
function class:setOptions (options)
173✔
57
  -- TODO: set a default direction here?
58
  base.setOptions(self, options)
173✔
59
end
60

61
function class:declareSettings ()
173✔
62
  base.declareSettings(self)
173✔
63
  for k, v in pairs(skips) do
692✔
64
    SILE.settings:declare({
1,038✔
65
        parameter = "plain." .. k .. "skipamount",
519✔
66
        type = "vglue",
67
        default = SILE.nodefactory.vglue(v),
1,038✔
68
        help = "The amount of a \\" .. k .. "skip"
519✔
69
      })
70
  end
71
end
72

73
function class:registerCommands ()
173✔
74

75
  SILE.classes.base.registerCommands(self)
173✔
76

77
  self:registerCommand("noindent", function (_, content)
346✔
78
    if #SILE.typesetter.state.nodes ~= 0 then
105✔
79
      SU.warn("\\noindent called after nodes already received in a paragraph, the setting will have no effect because the parindent (if any) has already been output")
1✔
80
    end
81
    SILE.settings:set("current.parindent", SILE.nodefactory.glue())
210✔
82
    SILE.process(content)
105✔
83
  end, "Do not add an indent to the start of this paragraph")
278✔
84

85
  self:registerCommand("neverindent", function (_, content)
346✔
86
    SILE.settings:set("current.parindent", SILE.nodefactory.glue())
106✔
87
    SILE.settings:set("document.parindent", SILE.nodefactory.glue())
106✔
88
    SILE.process(content)
53✔
89
  end, "Turn off all indentation")
226✔
90

91
  self:registerCommand("indent", function (_, content)
346✔
92
    SILE.settings:set("current.parindent", SILE.settings:get("document.parindent"))
8✔
93
    SILE.process(content)
4✔
94
  end, "Do add an indent to the start of this paragraph, even if previously told otherwise")
177✔
95

96
  for k, _ in pairs(skips) do
692✔
97
    self:registerCommand(k .. "skip", function (_, _)
1,038✔
98
      SILE.typesetter:leaveHmode()
41✔
99
      SILE.typesetter:pushExplicitVglue(SILE.settings:get("plain." .. k .. "skipamount"))
82✔
100
    end, "Skip vertically by a " .. k .. " amount")
1,079✔
101
  end
102

103
  self:registerCommand("hfill", function (_, _)
346✔
104
    SILE.typesetter:pushExplicitGlue(SILE.nodefactory.hfillglue())
50✔
105
  end, "Add a huge horizontal glue")
198✔
106

107
  self:registerCommand("vfill", function (_, _)
346✔
108
    SILE.typesetter:leaveHmode()
361✔
109
    SILE.typesetter:pushExplicitVglue(SILE.nodefactory.vfillglue())
722✔
110
  end, "Add huge vertical glue")
534✔
111

112
  self:registerCommand("hss", function (_, _)
346✔
113
    SILE.typesetter:initline()
×
114
    SILE.typesetter:pushGlue(SILE.nodefactory.hssglue())
×
115
    table.insert(SILE.typesetter.state.nodes, SILE.nodefactory.zerohbox())
×
116
  end, "Add glue which stretches and shrinks horizontally (good for centering)")
173✔
117

118
  self:registerCommand("vss", function (_, _)
346✔
119
    SILE.typesetter:pushExplicitVglue(SILE.nodefactory.vssglue())
×
120
  end, "Add glue which stretches and shrinks vertically")
173✔
121

122
  local _thinspacewidth = SILE.measurement(0.16667, "em")
173✔
123

124
  self:registerCommand("thinspace", function (_, _)
346✔
125
    SILE.call("glue", { width = _thinspacewidth })
×
126
  end)
127

128
  self:registerCommand("negthinspace", function (_, _)
346✔
129
    SILE.call("glue", { width = -_thinspacewidth })
×
130
  end)
131

132
  self:registerCommand("enspace", function (_, _)
346✔
133
    SILE.call("glue", { width = SILE.measurement(1, "en") })
×
134
  end)
135

136
  self:registerCommand("relax", function (_, _)
346✔
137
  end)
138

139
  self:registerCommand("enskip", function (_, _)
346✔
140
    SILE.call("enspace")
×
141
  end)
142

143
  local _quadwidth = SILE.measurement(1, "em")
173✔
144

145
  self:registerCommand("quad", function (_, _)
346✔
146
    SILE.call("glue", { width = _quadwidth })
1✔
147
  end)
148

149
  self:registerCommand("qquad", function (_, _)
346✔
150
    SILE.call("glue", { width = _quadwidth * 2 })
90✔
151
  end)
152

153
  self:registerCommand("slash", function (_, _)
346✔
154
    SILE.typesetter:typeset("/")
×
155
    SILE.call("penalty", { penalty = 50 })
×
156
  end)
157

158
  self:registerCommand("break", function (_, _)
346✔
159
    SILE.call("penalty", { penalty = -10000 })
41✔
160
  end, "Requests a frame break (if in vertical mode) or a line break (if in horizontal mode)")
214✔
161

162
  self:registerCommand("cr", function (_, _)
346✔
163
    SILE.call("hfill")
3✔
164
    SILE.call("break")
3✔
165
  end, "Fills a line with a stretchable glue and then requests a line break")
176✔
166

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

173
  self:registerCommand("framebreak", function (_, _)
346✔
174
    if not SILE.typesetter:vmode() then
22✔
175
      SU.warn("framebreak was not intended to work in horizontal mode. Behaviour may change in future versions")
×
176
    end
177
    SILE.call("penalty", { penalty = -10000, vertical = true })
11✔
178
  end, "Requests a frame break (switching to vertical mode if needed)")
184✔
179

180
  self:registerCommand("pagebreak", function (_, _)
346✔
181
    if not SILE.typesetter:vmode() then
14✔
182
      SU.warn("pagebreak was not intended to work in horizontal mode. Behaviour may change in future versions")
×
183
    end
184
    SILE.call("penalty", { penalty = -20000, vertical = true })
7✔
185
  end, "Requests a non-negotiable page break (switching to vertical mode if needed)")
180✔
186

187
  self:registerCommand("nobreak", function (_, _)
346✔
188
    SILE.call("penalty", { penalty = 10000 })
×
189
  end, "Inhibits a frame break (if in vertical mode) or a line break (if in horizontal mode)")
173✔
190

191
  self:registerCommand("novbreak", function (_, _)
346✔
192
    SILE.call("penalty", { penalty = 10000, vertical = true })
7✔
193
  end, "Inhibits a frame break (switching to vertical mode if needed)")
180✔
194

195
  self:registerCommand("allowbreak", function (_, _)
346✔
196
    SILE.call("penalty", { penalty = 0 })
×
197
  end, "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")
173✔
198

199
  -- THIS SEEMS BROKEN BUT THE COMMAND NOT MENTIONED IN THE SILE MANUAL
200
  -- In TeX, "\filbreak" compensates the vertical fill if no break actually occurs
201
  -- (\def\filbreak{\par\vfil\penalty-200\vfilneg)
202
  self:registerCommand("filbreak", function (_, _)
346✔
203
    SILE.call("vfill")
×
204
    SILE.call("penalty", { penalty = -200 })
×
205
  end, "I HAVE THE SAME NAME AS A TEX COMMAND BUT DON'T SEEM TO BE THE SAME")
173✔
206

207
  -- NOTE: TeX's "\goodbreak" does a \par first, so always switches to vertical mode.
208
  -- SILE differs here, allowing it both within a paragraph (line breaking) and between
209
  -- paragraphs (page breaking).
210
  self:registerCommand("goodbreak", function (_, _)
346✔
211
    SILE.call("penalty", { penalty = -500 })
4✔
212
  end, "Indicates a good potential point to break a frame (if in vertical mode) or a line (if in horizontal mode")
177✔
213

214
  self:registerCommand("eject", function (_, _)
346✔
215
    SILE.call("vfill")
3✔
216
    SILE.call("break")
3✔
217
  end, "Fills the page with stretchable vglue and then request a page break")
176✔
218

219
  self:registerCommand("supereject", function (_, _)
346✔
220
    SILE.call("vfill")
183✔
221
    SILE.call("penalty", { penalty = -20000 })
183✔
222
  end, "Fills the page with stretchable vglue and then requests a non-negotiable page break")
356✔
223

224
  self:registerCommand("em", function (_, content)
346✔
225
    local style = SILE.settings:get("font.style")
90✔
226
    local toggle = (style and style:lower() == "italic") and "Regular" or "Italic"
180✔
227
    SILE.call("font", { style = toggle }, content)
90✔
228
  end, "Emphasizes its contents by switching the font style to italic (or back to regular if already italic)")
263✔
229

230
  self:registerCommand("strong", function (_, content)
346✔
231
    SILE.call("font", { weight = 700 }, content)
×
232
  end, "Sets the font weight to bold (700)")
173✔
233

234
  self:registerCommand("code", function (options, content)
346✔
235
    -- IMPLEMENTATION NOTE:
236
    -- The \code command came from the url package, though used in plenty of
237
    -- places. It was referring to the verbatim:font from the verbatim
238
    -- package, which _should_ be sort of unrelated.
239
    -- Trying to untangle the things here, by introducing the
240
    -- definition from the former, but it's of sub-quality...
241
    -- The ugly -3 size is a HACK of sorts.
242
    options.family = options.family or "Hack"
1✔
243
    options.size = options.size or SILE.settings:get("font.size") - 3
2✔
244
    SILE.call("font", options, content)
1✔
245
  end)
246

247
  self:registerCommand("nohyphenation", function (_, content)
346✔
248
    SILE.call("font", { language = "und" }, content)
×
249
  end)
250

251
  self:registerCommand("center", function (_, content)
346✔
252
    if #SILE.typesetter.state.nodes ~= 0 then
124✔
NEW
253
      SU.warn("\\center environment started after other nodes in a paragraph, may not center as expected")
×
254
    end
255
    SILE.settings:temporarily(function ()
248✔
256
      local lskip = SILE.settings:get("document.lskip") or SILE.nodefactory.glue()
248✔
257
      local rskip = SILE.settings:get("document.rskip") or SILE.nodefactory.glue()
248✔
258
      SILE.settings:set("document.parindent", SILE.nodefactory.glue())
248✔
259
      SILE.settings:set("current.parindent", SILE.nodefactory.glue())
248✔
260
      SILE.settings:set("document.lskip", SILE.nodefactory.hfillglue(lskip.width.length))
248✔
261
      SILE.settings:set("document.rskip", SILE.nodefactory.hfillglue(rskip.width.length))
248✔
262
      SILE.settings:set("typesetter.parfillskip", SILE.nodefactory.glue())
248✔
263
      SILE.settings:set("document.spaceskip", SILE.length("1spc", 0, 0))
248✔
264
      SILE.process(content)
124✔
265
      SILE.call("par")
124✔
266
    end)
267
  end, "Typeset its contents in a centered block (keeping margins).")
297✔
268

269
  self:registerCommand("raggedright", function (_, content)
346✔
270
    SILE.settings:temporarily(function ()
14✔
271
      local lskip = SILE.settings:get("document.lskip") or SILE.nodefactory.glue()
14✔
272
      local rskip = SILE.settings:get("document.rskip") or SILE.nodefactory.glue()
14✔
273
      SILE.settings:set("document.lskip", SILE.nodefactory.glue(lskip.width.length))
14✔
274
      SILE.settings:set("document.rskip", SILE.nodefactory.hfillglue(rskip.width.length))
14✔
275
      SILE.settings:set("typesetter.parfillskip", SILE.nodefactory.glue())
14✔
276
      SILE.settings:set("document.spaceskip", SILE.length("1spc", 0, 0))
14✔
277
      SILE.process(content)
7✔
278
      SILE.call("par")
7✔
279
    end)
280
  end, "Typeset its contents in a left aligned block (keeping margins).")
180✔
281

282
  self:registerCommand("raggedleft", function (_, content)
346✔
283
    SILE.settings:temporarily(function ()
12✔
284
      local lskip = SILE.settings:get("document.lskip") or SILE.nodefactory.glue()
12✔
285
      local rskip = SILE.settings:get("document.rskip") or SILE.nodefactory.glue()
12✔
286
      SILE.settings:set("document.lskip", SILE.nodefactory.hfillglue(lskip.width.length))
12✔
287
      SILE.settings:set("document.rskip", SILE.nodefactory.glue(rskip.width.length))
12✔
288
      SILE.settings:set("typesetter.parfillskip", SILE.nodefactory.glue())
12✔
289
      SILE.settings:set("document.spaceskip", SILE.length("1spc", 0, 0))
12✔
290
      SILE.process(content)
6✔
291
      SILE.call("par")
6✔
292
    end)
293
  end, "Typeset its contents in a right aligned block (keeping margins).")
179✔
294

295
  self:registerCommand("justified", function (_, content)
346✔
296
    SILE.settings:temporarily(function ()
2✔
297
      local lskip = SILE.settings:get("document.lskip") or SILE.nodefactory.glue()
2✔
298
      local rskip = SILE.settings:get("document.rskip") or SILE.nodefactory.glue()
2✔
299
      SILE.settings:set("document.lskip", SILE.nodefactory.glue(lskip.width.length))
2✔
300
      SILE.settings:set("document.rskip", SILE.nodefactory.glue(rskip.width.length))
2✔
301
      SILE.settings:set("document.spaceskip", nil)
1✔
302
      -- HACK. This knows too much about parfillskip defaults...
303
      -- (Which must be big, but smaller than infinity. Doh!)
304
      SILE.settings:set("typesetter.parfillskip", SILE.nodefactory.glue("0pt plus 10000pt"))
2✔
305
      SILE.process(content)
1✔
306
      SILE.call("par")
1✔
307
    end)
308
    end, "Typeset its contents in a justified block (keeping margins).")
174✔
309

310
  self:registerCommand("ragged", function (options, content)
346✔
311
    -- Fairly dubious command for compatibility
312
    local l = SU.boolean(options.left, false)
1✔
313
    local r = SU.boolean(options.right, false)
1✔
314
    if l and r then
1✔
315
      SILE.call("center", {}, content)
2✔
NEW
316
    elseif r then
×
NEW
317
      SILE.call("raggedleft", {}, content)
×
NEW
318
    elseif l then
×
NEW
319
      SILE.call("raggedright", {}, content)
×
320
    else
NEW
321
      SILE.call("justified", {}, content)
×
322
    end
323
  end)
324

325
  self:registerCommand("rightalign", function (_, content)
346✔
326
    SU.deprecated("\\rightalign", "\\raggedleft", "0.15.0", "0.17.0")
4✔
327
    SILE.call("raggedleft", {}, content)
4✔
328
  end)
329

330
  self:registerCommand("blockquote", function (_, content)
346✔
NEW
331
    SILE.call("smallskip")
×
NEW
332
    SILE.typesetter:leaveHmode()
×
NEW
333
    SILE.settings:temporarily(function ()
×
NEW
334
      local indent = SILE.measurement("2em"):absolute()
×
NEW
335
      local lskip = SILE.settings:get("document.lskip") or SILE.nodefactory.glue()
×
NEW
336
      local rskip = SILE.settings:get("document.rskip") or SILE.nodefactory.glue()
×
337
      -- We keep the stretcheability of the lskip and rskip: honoring text alignment
338
      -- from the parent context.
NEW
339
      SILE.settings:set("document.lskip", SILE.nodefactory.glue(lskip.width + indent))
×
NEW
340
      SILE.settings:set("document.rskip", SILE.nodefactory.glue(rskip.width + indent))
×
NEW
341
      SILE.settings:set("font.size", SILE.settings:get("font.size") * 0.95)
×
NEW
342
      SILE.process(content)
×
NEW
343
      SILE.typesetter:leaveHmode()
×
344
    end)
NEW
345
    SILE.call("smallskip")
×
346
  end, "A blockquote environment")
173✔
347

348
  self:registerCommand("quote", function (_, content)
346✔
NEW
349
    SU.deprecated("\\quote", "\\pullquote or \\blockquote", "0.14.5", "0.16.0", [[
×
350
  The \quote command has *such* bad output it is being completely
351
  deprecated as unsuitable for general purpose use.
352
  The pullquote package (\use[module=packages.pullquote]) provides one
353
  alternative, and the blockquote environment provides another.
354
  But you can also copy and adapt the original source from the plain
355
  class if you need to maintain exact output past SILE v0.16.0.]])
×
356
    SILE.call("smallskip")
×
357
    SILE.call("par")
×
358
    local margin = SILE.measurement(2.5, "em")
×
359
    SILE.settings:set("document.lskip", margin)
×
360
    SILE.settings:set("document.lskip", margin)
×
361
    SILE.call("font", { size = SILE.measurement(0.8, "em") }, function ()
×
362
      SILE.call("noindent")
×
363
      SILE.process(content)
×
364
    end)
365
    SILE.call("par")
×
366
    SILE.settings:set("document.lskip", nil)
×
367
    SILE.settings:set("document.rskip", nil)
×
368
    SILE.call("smallskip")
×
369
  end)
370

371
  self:registerCommand("listitem", function (_, content)
346✔
372
    SU.deprecated("\\listitem", "\\item", "0.14.6", "0.16.0", [[
×
373
  The new list package (\use[module=packages.lists) has much better
374
  typography for lists. If you want to maintain the exact output of listitem
375
  past SILE v0.16.0 copy the source of \listitem from the plain class into
376
  your project.]])
×
377
    SILE.call("medskip")
×
378
    SILE.typesetter:typeset("• ")
×
379
    SILE.process(content)
×
380
    SILE.call("medskip")
×
381
  end)
382

383
  self:registerCommand("sloppy", function (_, _)
346✔
384
    SILE.settings:set("linebreak.tolerance", 9999)
×
385
  end)
386

387
  self:registerCommand("awful", function (_, _)
346✔
388
    SILE.settings:set("linebreak.tolerance", 10000)
×
389
  end)
390

391
  self:registerCommand("hbox", function (_, content)
346✔
392
    local hbox, hlist = SILE.typesetter:makeHbox(content)
70✔
393
    SILE.typesetter:pushHbox(hbox)
70✔
394
    if #hlist > 0 then
70✔
395
      SU.warn("Hbox has migrating content (ignored for now, but likely to break in future versions)")
×
396
      -- Ugly shim:
397
      -- One day we ought to do SILE.typesetter:pushHlist(hlist) here, so as to push
398
      -- back the migrating contents from within the hbox'ed content.
399
      -- However, old Lua code assumed the hbox to be returned, and sometimes removed it
400
      -- from the typesetter queue (for measuring, etc.), assuming it was the last
401
      -- element in the queue...
402
    end
403
    return hbox
70✔
404
  end, "Compiles all the enclosed horizontal-mode material into a single hbox")
173✔
405

406
  self:registerCommand("vbox", function (options, content)
346✔
407
    local vbox
408
    SILE.settings:temporarily(function ()
90✔
409
      if options.width then SILE.settings:set("typesetter.breakwidth", SILE.length(options.width)) end
45✔
410
      SILE.typesetter:pushState()
45✔
411
      SILE.process(content)
45✔
412
      SILE.typesetter:leaveHmode(1)
45✔
413
      vbox = SILE.pagebuilder:collateVboxes(SILE.typesetter.state.outputQueue)
90✔
414
      SILE.typesetter:popState()
45✔
415
    end)
416
    return vbox
45✔
417
  end, "Compiles all the enclosed material into a single vbox")
173✔
418

419
end
420

421
return class
173✔
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

© 2025 Coveralls, Inc