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

sile-typesetter / sile / 3679882487

pending completion
3679882487

push

github

GitHub
Merge 93b1c7814 into 49780d512

335 of 335 new or added lines in 16 files covered. (100.0%)

65384 of 67338 relevant lines covered (97.1%)

1597.14 hits per line

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

94.38
/packages/parallel/init.lua
1
local base = require("packages.base")
3✔
2

3
local package = pl.class(base)
3✔
4
package._name = "parallel"
3✔
5

6
local typesetterPool = {}
3✔
7
local calculations = {}
3✔
8
local folioOrder = {}
3✔
9

10
local allTypesetters = function (callback)
11
  local oldtypesetter = SILE.typesetter
24✔
12
  for frame, typesetter in pairs(typesetterPool) do
88✔
13
    SILE.typesetter = typesetter
64✔
14
    callback(frame, typesetter)
64✔
15
  end
16
  SILE.typesetter = oldtypesetter
24✔
17
end
18

19
local nulTypesetter = pl.class(SILE.typesetters.base) -- we ignore this
3✔
20
nulTypesetter.outputLinesToPage = function () end
3✔
21

22
local parallelPagebreak = function ()
23
  for i = 1, #folioOrder do
6✔
24
    local thisPageFrames = folioOrder[i]
3✔
25
    for j = 1, #thisPageFrames do
11✔
26
      local frame = thisPageFrames[j]
8✔
27
      local typesetter = typesetterPool[frame]
8✔
28
      local thispage = {}
8✔
29
      SU.debug("parallel", "Dumping lines for page on typesetter", typesetter.id)
8✔
30
      if #typesetter.state.outputQueue > 0 and calculations[frame].mark == 0 then
8✔
31
        -- More than one page worth of stuff here.
32
        -- Just ship out one page and hope for the best.
33
        SILE.typesetters.base.buildPage(typesetter)
×
34
      else
35
        for l = 1, calculations[frame].mark do
17✔
36
          thispage[l] = table.remove(typesetter.state.outputQueue, 1)
18✔
37
          SU.debug("parallel", thispage[l])
9✔
38
        end
39
        typesetter:outputLinesToPage(thispage)
8✔
40
      end
41
    end
42
    SILE.documentState.documentClass:endPage()
3✔
43
    for l = 1, #thisPageFrames do
11✔
44
      local frame = thisPageFrames[l]
8✔
45
      local typesetter = typesetterPool[frame]
8✔
46
      typesetter:initFrame(typesetter.frame)
8✔
47
    end
48
    SILE.documentState.documentClass:newPage()
3✔
49
  end
50
end
51

52
local addBalancingGlue = function (height)
53
  allTypesetters(function (frame, typesetter)
12✔
54
    local glue = height - calculations[frame].heightOfNewMaterial
16✔
55
    if glue.length:tonumber() > 0 then
32✔
56
      SU.debug("parallel", "Adding", glue, "to", frame)
1✔
57
      typesetter:pushVglue({ height = glue })
1✔
58
    end
59
    calculations[frame].mark = #typesetter.state.outputQueue
16✔
60
  end)
61
end
62

63
function package:_init (options)
3✔
64
  base._init(self, options)
3✔
65
  SILE.typesetter = nulTypesetter(SILE.getFrame("page"))
9✔
66
  for frame, typesetter in pairs(options.frames) do
11✔
67
    typesetterPool[frame] = SILE.typesetters.base(SILE.getFrame(typesetter))
24✔
68
    typesetterPool[frame].id = typesetter
8✔
69
    typesetterPool[frame].buildPage = function ()
8✔
70
      -- No thank you, I will do that.
71
    end
72
    -- Fixed leading here is obviously a bug, but n-way leading calculations
73
    -- get very complicated...
74
    -- typesetterPool[frame].leadingFor = function() return SILE.nodefactory.vglue(SILE.settings:get("document.lineskip")) end
75
    local fontcommand = frame .. ":font"
8✔
76
    self:registerCommand(frame, function (_, _) -- \left ...
16✔
77
      SILE.typesetter = typesetterPool[frame]
4✔
78
      SILE.call(fontcommand)
4✔
79
    end)
80
    if not SILE.Commands[fontcommand] then
8✔
81
      self:registerCommand(fontcommand, function (_, _) end) -- to be overridden
12✔
82
    end
83
  end
84
  if not options.folios then
3✔
85
    folioOrder = { {} }
3✔
86
    -- Note output order doesn't matter for PDF, but for our test suite it is
87
    -- essential that the output order is deterministic, hence this sort()
88
    for frame, _ in pl.tablex.sort(options.frames) do table.insert(folioOrder[1], frame) end
25✔
89
  else
90
    folioOrder = options.folios -- As usual we trust the user knows what they're doing
×
91
  end
92
  self.class.newPage = function(self_)
3✔
93
    allTypesetters(function (frame, _)
6✔
94
      calculations[frame] = { mark = 0 }
8✔
95
    end)
96
    self.class._base.newPage(self_)
3✔
97
    SILE.call("sync")
3✔
98
  end
99
  allTypesetters(function (frame, _) calculations[frame] = { mark = 0 } end)
11✔
100
  local oldfinish = self.class.finish
3✔
101
  self.class.finish = function (self_)
3✔
102
    parallelPagebreak()
3✔
103
    oldfinish(self_)
3✔
104
  end
105
end
106

107
function package:registerCommands ()
3✔
108

109
  self:registerCommand("sync", function (_, _)
6✔
110
    local anybreak = false
6✔
111
    local maxheight = SILE.length()
6✔
112
    SU.debug("parallel", "Trying a sync")
6✔
113
    allTypesetters(function (_, typesetter)
12✔
114
      SU.debug("parallel", "Leaving hmode on", typesetter.id)
16✔
115
      typesetter:leaveHmode(true)
16✔
116
      -- Now we have each typesetter's content boxed up onto the output stream
117
      -- but page breaking has not been run. See if page breaking would cause a
118
      -- break
119
      local lines = pl.tablex.copy(typesetter.state.outputQueue)
16✔
120
      if SILE.pagebuilder:findBestBreak({ vboxlist = lines, target = typesetter:getTargetLength() }) then
48✔
121
        anybreak = true
×
122
      end
123
    end)
124

125
    if anybreak then
6✔
126
      parallelPagebreak()
×
127
      return
×
128
    end
129

130
    allTypesetters(function (frame, typesetter)
12✔
131
      calculations[frame].heightOfNewMaterial = SILE.length()
32✔
132
      for i = calculations[frame].mark + 1, #typesetter.state.outputQueue do
24✔
133
        local thisHeight = typesetter.state.outputQueue[i].height + typesetter.state.outputQueue[i].depth
8✔
134
        calculations[frame].heightOfNewMaterial = calculations[frame].heightOfNewMaterial + thisHeight
16✔
135
      end
136
      if maxheight < calculations[frame].heightOfNewMaterial then maxheight = calculations[frame].heightOfNewMaterial end
17✔
137
      SU.debug("parallel", frame, ": pre-sync content=", calculations[frame].mark, ", now", #typesetter.state.outputQueue, ", height of material:", calculations[frame].heightOfNewMaterial)
16✔
138
    end)
139
    addBalancingGlue(maxheight)
6✔
140
  end)
141

142
end
143

144
package.documentation = [[
145
\begin{document}
146
The \autodoc:package{parallel} package provides the mechanism for typesetting diglot or other parallel documents.
147
When used by a class such as \code{classes/diglot.lua}, it registers a command for each parallel frame, to allow you to select which frame you’re typesetting into.
148
It also defines the \autodoc:command{\sync} command, which adds vertical spacing to each frame such that the \em{next} set of text is vertically aligned.
149
See \url{https://sile-typesetter.org/examples/parallel.sil} and the source of \code{classes/diglot.lua} for examples which makes the operation clear.
150
\end{document}
151
]]
3✔
152

153
return package
3✔
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