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

sile-typesetter / sile / 9432254829

08 Jun 2024 11:20PM UTC coverage: 60.675% (+3.5%) from 57.223%
9432254829

push

github

alerque
fix(build): Bundle all assets in source distribution

...even when configured for doing a static binary build with embedded
assets. They don't get installed, but they should be in the dist file in
case the good folks building want to configure it a different way.

10441 of 17208 relevant lines covered (60.68%)

1913.98 hits per line

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

83.59
/core/tracestack.lua
1
-- Represents a stack of stack frame objects,
2
-- which describe the call-stack stack of the currently processed document.
3
-- Stack frames are stored contiguously, treating this object as an array.
4
-- Most recent and relevant stack frames are in higher indices, up to #traceStack.
5
-- Do not manipulate the stack directly, use provided push<Type> and pop methods.
6
-- There are different types of stack frames, see pushFrame for more details.
7
local traceStack = pl.class({
180✔
8
   -- Stores the frame which was last popped. Reset after a push.
9
   -- Helps to further specify current location in the processed document.
10
   afterFrame = nil,
11
})
12

13
traceStack.defaultFrame = pl.class({
180✔
14

15
   location = function (self, relative)
16
      local str = ""
18✔
17
      if self.file and not relative then
18✔
18
         str = str .. self.file .. ":"
13✔
19
      end
20
      if self.lno then
18✔
21
         str = str .. self.lno .. ":"
9✔
22
         if self.col then
9✔
23
            str = str .. self.col .. ":"
9✔
24
         end
25
      end
26
      str = str .. (str:len() > 0 and " " or "") .. "in "
36✔
27
      str = str .. tostring(self)
36✔
28
      return str
18✔
29
   end,
30

31
   __tostring = function (self)
32
      self.file = nil
×
33
      self.lno = nil
×
34
      self.col = nil
×
35
      return #self > 0 and tostring(self) or ""
×
36
   end,
37
})
90✔
38

39
traceStack.documentFrame = pl.class(traceStack.defaultFrame)
180✔
40

41
local function oneline (str)
42
   return str:gsub("\n", "␤")
5✔
43
      :gsub("\r", "␍")
5✔
44
      :gsub("\f", "␊")
5✔
45
      :gsub("\a", "␇")
5✔
46
      :gsub("\b", "␈")
5✔
47
      :gsub("\t", "␉")
5✔
48
      :gsub("\v", "␋")
5✔
49
end
50

51
function traceStack.documentFrame:_init (file, snippet)
180✔
52
   self.command = "document"
108✔
53
   self.file = file
108✔
54
   self.snippet = snippet
108✔
55
end
56

57
function traceStack.documentFrame:__tostring ()
180✔
58
   return "<snippet>:\n\t\t[[" .. oneline(self.snippet) .. "]]"
8✔
59
end
60

61
traceStack.commandFrame = pl.class(traceStack.defaultFrame)
180✔
62

63
function traceStack.commandFrame:_init (command, content, options)
180✔
64
   self.command = command
1,314✔
65
   self.file = content.file or SILE.currentlyProcessingFile
1,314✔
66
   self.lno = content.lno
1,314✔
67
   self.col = content.col
1,314✔
68
   self.options = options or {}
1,314✔
69
end
70

71
function traceStack.commandFrame:__tostring ()
180✔
72
   local opts = pl.tablex.size(self.options) == 0 and ""
26✔
73
      or pl.pretty.write(self.options, ""):gsub("^{", "["):gsub("}$", "]")
19✔
74
   return "\\" .. tostring(self.command) .. opts
13✔
75
end
76

77
traceStack.contentFrame = pl.class(traceStack.commandFrame)
180✔
78

79
function traceStack.contentFrame:_init (command, content)
180✔
80
   self:super(command, content, content.options)
38✔
81
end
82

83
traceStack.textFrame = pl.class(traceStack.defaultFrame)
180✔
84

85
function traceStack.textFrame:_init (text)
180✔
86
   self.text = text
344✔
87
end
88

89
function traceStack.textFrame:__tostring ()
180✔
90
   if self.text:len() > 20 then
2✔
91
      self.text = luautf8.sub(self.text, 1, 18) .. "…"
1✔
92
   end
93
   self.text = oneline(self.text)
2✔
94
   return '"' .. self.text .. '"'
1✔
95
end
96

97
local function formatTraceLine (string)
98
   local prefix = "\t"
6✔
99
   return prefix .. string .. "\n"
6✔
100
end
101

102
-- Push a document processing run (input method) onto the stack
103
function traceStack:pushDocument (file, doc)
90✔
104
   if type(doc) == "table" then
108✔
105
      doc = tostring(doc)
×
106
   end
107
   local snippet = doc:sub(1, 100)
108✔
108
   local frame = traceStack.documentFrame(file, snippet)
108✔
109
   return self:pushFrame(frame)
108✔
110
end
111

112
-- Push a command frame on to the stack to record the execution trace for debugging.
113
-- Carries information about the command call, not the command itself.
114
-- Must be popped with `pop(returnOfPush)`.
115
function traceStack:pushCommand (command, content, options)
90✔
116
   if not command then
1,276✔
117
      SU.warn("Command should be specified for SILE.traceStack:pushCommand", true)
×
118
   end
119
   if type(content) == "function" then
1,276✔
120
      content = {}
25✔
121
   end
122
   local frame = traceStack.commandFrame(command, content, options)
1,276✔
123
   return self:pushFrame(frame)
1,276✔
124
end
125

126
-- Push a command frame on to the stack to record the execution trace for debugging.
127
-- Command arguments are inferred from AST content, any item may be overridden.
128
-- Must be popped with `pop(returnOfPush)`.
129
function traceStack:pushContent (content, command)
90✔
130
   if type(content) ~= "table" then
38✔
131
      SU.warn("Content parameter of SILE.traceStack:pushContent must be a table", true)
×
132
   end
133
   command = command or content.command
38✔
134
   if not command then
38✔
135
      SU.warn("Command should be specified or inferable for SILE.traceStack:pushContent", true)
×
136
   end
137
   local frame = traceStack.contentFrame(command, content)
38✔
138
   return self:pushFrame(frame)
38✔
139
end
140

141
-- Push a text that is going to get typeset on to the stack to record the execution trace for debugging.
142
-- Must be popped with `pop(returnOfPush)`.
143
function traceStack:pushText (text)
90✔
144
   local frame = traceStack.textFrame(text)
344✔
145
   return self:pushFrame(frame)
344✔
146
end
147

148
-- Internal: Push-pop balance checking ID
149
local lastPushId = 0
90✔
150

151
-- Push complete frame onto the stack.
152
-- Frame is a table with following optional fields:
153
-- .file = string - name of the file from which this originates
154
-- .lno = number - line in the file
155
-- .col = number - column on the line
156
-- .toStringHelper = function() that serializes extended information about the frame BESIDES location
157
function traceStack:pushFrame (frame)
90✔
158
   SU.debug("traceStack", function ()
3,532✔
159
      return string.rep(".", #self) .. "PUSH(" .. frame:location() .. ")"
×
160
   end)
161
   self[#self + 1] = frame
1,766✔
162
   self.afterFrame = nil
1,766✔
163
   lastPushId = lastPushId + 1
1,766✔
164
   frame._pushId = lastPushId
1,766✔
165
   return lastPushId
1,766✔
166
end
167

168
-- Pop previously pushed command from the stack.
169
-- Return value of `push` function must be provided as argument to check for balanced usage.
170
function traceStack:pop (pushId)
90✔
171
   if type(pushId) ~= "number" then
1,766✔
172
      SU.error("SILE.traceStack:pop's argument must be the result value of the corresponding push", true)
×
173
   end
174
   -- First verify that push/pop is balanced
175
   local popped = self[#self]
1,766✔
176
   if popped._pushId ~= pushId then
1,766✔
177
      local message = "Unbalanced content push/pop"
×
178
      if SILE.traceback or SU.debugging("traceStack") then
×
179
         message = message .. ". Expected " .. popped.pushId .. " - (" .. popped:location() .. "), got " .. pushId
×
180
      end
181
      SU.warn(message, true)
×
182
   else
183
      -- Correctly balanced: pop the frame
184
      self.afterFrame = popped
1,766✔
185
      self[#self] = nil
1,766✔
186
      SU.debug("traceStack", function ()
3,532✔
187
         return string.rep(".", #self) .. "POP(" .. popped:location() .. ")"
×
188
      end)
189
   end
190
end
191

192
-- Returns single line string with location of top most trace frame
193
function traceStack:locationHead ()
90✔
194
   local afterFrame = self.afterFrame
18✔
195
   local top = self[#self]
18✔
196
   if not top then
18✔
197
      -- Stack is empty, there is not much we can do
198
      return formatTraceLine(
5✔
199
         afterFrame and "after " .. afterFrame:location() or SILE.currentlyProcessingFile or "<nowhere>"
10✔
200
      )
5✔
201
   end
202
   local trace = top:location()
13✔
203
   local locationFrame = top
13✔
204
   -- Not all stack traces have to carry location information.
205
   -- If the first stack trace does not carry it, find a frame which does.
206
   -- Then append it, because its information may be useful.
207
   if not locationFrame.lno then
13✔
208
      for i = #self - 1, 1, -1 do
10✔
209
         if self[i].lno then
6✔
210
            locationFrame = self[i]
×
211
            trace = trace .. " near " .. locationFrame:location(locationFrame.file == top.file)
×
212
            break
213
         end
214
      end
215
   end
216
   -- Print after, if it is in a relevant file
217
   if afterFrame and (not locationFrame or afterFrame.file == locationFrame.file) then
13✔
218
      trace = trace .. " after " .. afterFrame:location(true)
×
219
   end
220
   return trace
13✔
221
end
222

223
-- Returns multiline trace string with locations of each frame up to maxdepth
224
function traceStack:locationTrace (maxdepth)
90✔
225
   local depth = maxdepth or #self
1✔
226
   local trace = formatTraceLine(self:locationHead())
2✔
227
   depth = depth - 1
1✔
228
   if depth > 1 then
1✔
229
      repeat
230
         trace = trace .. formatTraceLine(self[depth]:location())
×
231
         depth = depth - 1
×
232
      until depth == 1 -- stop at 1 (document) as not useful in trace
×
233
   end
234
   return trace
1✔
235
end
236

237
return traceStack
90✔
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