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

sile-typesetter / sile / 6995072559

26 Nov 2023 10:46AM UTC coverage: 63.726% (+0.1%) from 63.58%
6995072559

push

github

web-flow
Merge 73d09f6d4 into 1e5773cff

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

4 existing lines in 2 files now uncovered.

9963 of 15634 relevant lines covered (63.73%)

6749.84 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")
176✔
2

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

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

28
local skips = {
176✔
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)
176✔
35
  base._init(self, options)
176✔
36
  self:loadPackage("bidi")
176✔
37
  self:loadPackage("folio")
176✔
38
end
39

40
function class:declareOptions ()
176✔
41
  base.declareOptions(self)
176✔
42
  self:declareOption("direction", function (_, value)
352✔
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)
176✔
57
  -- TODO: set a default direction here?
58
  base.setOptions(self, options)
176✔
59
end
60

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

73
function class:registerCommands ()
176✔
74

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

77
  self:registerCommand("noindent", function (_, content)
352✔
78
    if #SILE.typesetter.state.nodes ~= 0 then
106✔
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())
212✔
82
    SILE.process(content)
106✔
83
  end, "Do not add an indent to the start of this paragraph")
282✔
84

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

91
  self:registerCommand("indent", function (_, content)
352✔
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")
180✔
95

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

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

107
  self:registerCommand("vfill", function (_, _)
352✔
108
    SILE.typesetter:leaveHmode()
369✔
109
    SILE.typesetter:pushExplicitVglue(SILE.nodefactory.vfillglue())
738✔
110
  end, "Add huge vertical glue")
545✔
111

112
  self:registerCommand("hss", function (_, _)
352✔
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)")
176✔
117

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

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

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

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

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

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

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

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

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

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

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

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

162
  self:registerCommand("cr", function (_, _)
352✔
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")
179✔
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 (_, _)
352✔
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)")
187✔
179

180
  self:registerCommand("pagebreak", function (_, _)
352✔
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)")
183✔
186

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

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

195
  self:registerCommand("allowbreak", function (_, _)
352✔
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")
176✔
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 (_, _)
352✔
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")
176✔
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 (_, _)
352✔
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")
180✔
213

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

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

224
  self:registerCommand("em", function (_, content)
352✔
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)")
266✔
229

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

234
  self:registerCommand("code", function (options, content)
352✔
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)
352✔
248
    SILE.call("font", { language = "und" }, content)
×
249
  end)
250

251
  self:registerCommand("center", function (_, content)
352✔
252
    if #SILE.typesetter.state.nodes ~= 0 then
126✔
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 ()
252✔
256
      local lskip = SILE.settings:get("document.lskip") or SILE.nodefactory.glue()
252✔
257
      local rskip = SILE.settings:get("document.rskip") or SILE.nodefactory.glue()
252✔
258
      SILE.settings:set("document.parindent", SILE.nodefactory.glue())
252✔
259
      SILE.settings:set("current.parindent", SILE.nodefactory.glue())
252✔
260
      SILE.settings:set("document.lskip", SILE.nodefactory.hfillglue(lskip.width.length))
252✔
261
      SILE.settings:set("document.rskip", SILE.nodefactory.hfillglue(rskip.width.length))
252✔
262
      SILE.settings:set("typesetter.parfillskip", SILE.nodefactory.glue())
252✔
263
      SILE.settings:set("document.spaceskip", SILE.length("1spc", 0, 0))
252✔
264
      SILE.process(content)
126✔
265
      SILE.call("par")
126✔
266
    end)
267
  end, "Typeset its contents in a centered block (keeping margins).")
302✔
268

269
  self:registerCommand("raggedright", function (_, content)
352✔
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).")
183✔
281

282
  self:registerCommand("raggedleft", function (_, content)
352✔
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).")
182✔
294

295
  self:registerCommand("justified", function (_, content)
352✔
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
      -- Keep the fixed part of the margins for nesting but remove the stretchability.
300
      SILE.settings:set("document.lskip", SILE.nodefactory.glue(lskip.width.length))
2✔
301
      SILE.settings:set("document.rskip", SILE.nodefactory.glue(rskip.width.length))
2✔
302
      -- Reset parfillskip to its default value, in case the surrounding context
303
      -- is ragged and cancelled it.
304
      SILE.settings:set("typesetter.parfillskip", nil, false, true)
1✔
305
      SILE.settings:set("document.spaceskip", nil)
1✔
306
      SILE.process(content)
1✔
307
      SILE.call("par")
1✔
308
    end)
309
    end, "Typeset its contents in a justified block (keeping margins).")
177✔
310

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

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

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

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

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

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

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

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

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

420
end
421

422
return class
176✔
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