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

sile-typesetter / sile / 9304060604

30 May 2024 02:07PM UTC coverage: 74.124% (-0.6%) from 74.707%
9304060604

push

github

alerque
style: Reformat Lua with stylua

8104 of 11995 new or added lines in 184 files covered. (67.56%)

15 existing lines in 11 files now uncovered.

12444 of 16788 relevant lines covered (74.12%)

7175.1 hits per line

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

67.38
/packages/counters/init.lua
1
local base = require("packages.base")
181✔
2

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

6
SILE.formatCounter = function (counter)
181✔
NEW
7
   SU.deprecated("SILE.formatCounter", "class:formatCounter", "0.13.0", "0.15.0")
×
NEW
8
   return package.formatCounter(nil, counter)
×
9
end
10

11
SILE.formatMultilevelCounter = function (counter, options)
181✔
NEW
12
   SU.deprecated("SILE.formatMultilevelCounter", "class:formatMultilevelCounter", "0.13.0", "0.15.0")
×
NEW
13
   return package.formatMultilevelCounter(nil, counter, options)
×
14
end
15

16
local function getCounter (_, id)
17
   local counter = SILE.scratch.counters[id]
16✔
18
   if not counter then
16✔
19
      counter = {
1✔
20
         value = 0,
21
         display = "arabic",
22
         format = package.formatCounter,
1✔
23
      }
1✔
24
      SILE.scratch.counters[id] = counter
1✔
25
   elseif type(counter.value) ~= "number" then
15✔
NEW
26
      SU.error("Counter " .. id .. " is not a single-level counter")
×
27
   end
28
   return counter
16✔
29
end
30

31
local function getMultilevelCounter (_, id)
32
   local counter = SILE.scratch.counters[id]
34✔
33
   if not counter then
34✔
34
      counter = {
4✔
35
         value = { 0 },
4✔
36
         display = { "arabic" },
4✔
37
         format = package.formatMultilevelCounter,
4✔
38
      }
4✔
39
      SILE.scratch.counters[id] = counter
4✔
40
   elseif type(counter.value) ~= "table" then
30✔
NEW
41
      SU.error("Counter " .. id .. " is not a multi-level counter")
×
42
   end
43
   return counter
34✔
44
end
45

46
function package.formatCounter (_, counter)
181✔
47
   return SU.formatNumber(counter.value, { system = counter.display })
387✔
48
end
49

50
function package:formatMultilevelCounter (counter, options)
181✔
51
   options = options or {}
19✔
52
   local maxlevel = options.level and SU.min(SU.cast("integer", options.level), #counter.value) or #counter.value
25✔
53
   -- Option minlevel is undocumented and should perhaps be deprecated: is there a real use case for it?
54
   local minlevel = options.minlevel and SU.min(SU.cast("integer", options.minlevel, #counter.value)) or 1
19✔
55
   local out = {}
19✔
56
   if SU.boolean(options.noleadingzeros, false) then
38✔
NEW
57
      while counter.value[minlevel] == 0 do
×
NEW
58
         minlevel = minlevel + 1
×
59
      end -- skip leading zeros
60
   end
61
   for x = minlevel, maxlevel do
62✔
62
      out[x - minlevel + 1] = self:formatCounter({ display = counter.display[x], value = counter.value[x] })
86✔
63
   end
64
   return table.concat(out, ".")
19✔
65
end
66

67
function package:_init ()
181✔
68
   base._init(self)
260✔
69
   if not SILE.scratch.counters then
260✔
70
      SILE.scratch.counters = {}
181✔
71
   end
72
   self:export("getCounter", getCounter)
260✔
73
   self:export("getMultilevelCounter", getMultilevelCounter)
260✔
74
   self:deprecatedExport("formatCounter", self.formatCounter)
260✔
75
   self:deprecatedExport("formatMultilevelCounter", self.formatMultilevelCounter)
260✔
76
end
77

78
function package:registerCommands ()
181✔
79
   self:registerCommand("increment-counter", function (options, _)
520✔
NEW
80
      local id = SU.required(options, "id", "increment-counter")
×
81

NEW
82
      local counter = self.class:getCounter(id)
×
NEW
83
      if options["set-to"] then
×
NEW
84
         SU.deprecated("\\increment-counter[set-to=...]", "\\set-counter[value=...]", "0.14.4", "0.16.0")
×
85
         -- An increment command that does a set is plain weird...
NEW
86
         counter.value = SU.cast("integer", options["set-to"])
×
87
      else
NEW
88
         counter.value = counter.value + 1
×
89
      end
NEW
90
      if options.display then
×
NEW
91
         counter.display = options.display
×
92
      end
93
   end, "Increments the counter named by the <id> option")
260✔
94

95
   self:registerCommand(
520✔
96
      "set-counter",
260✔
97
      function (options, _)
98
         local id = SU.required(options, "id", "set-counter")
10✔
99

100
         local counter = self.class:getCounter(id)
10✔
101
         if options.value then
10✔
102
            counter.value = SU.cast("integer", options.value)
10✔
103
         end
104
         if options.display then
10✔
105
            counter.display = options.display
5✔
106
         end
107
      end,
108
      "Sets the counter named by the <id> option to <value>; sets its display type (roman/Roman/arabic) to type <display>."
109
   )
260✔
110

111
   self:registerCommand("show-counter", function (options, _)
520✔
112
      local id = SU.required(options, "id", "show-counter")
6✔
113

114
      local counter = self.class:getCounter(id)
6✔
115
      if options.display then
6✔
NEW
116
         SU.deprecated("\\show-counter[display=...]", "\\set-counter[display=...]", "0.14.4", "0.16.0")
×
NEW
117
         counter.display = options.display
×
118
      end
119
      SILE.typesetter:typeset(self:formatCounter(counter))
12✔
120
   end, "Outputs the value of counter <id>, optionally displaying it with the <display> format.")
266✔
121

122
   self:registerCommand("increment-multilevel-counter", function (options, _)
520✔
123
      local id = SU.required(options, "id", "increment-multilevel-counter")
15✔
124

125
      local counter = self.class:getMultilevelCounter(id)
15✔
126
      local currentLevel = #counter.value
15✔
127
      local level = SU.cast("integer", options.level or currentLevel)
15✔
128
      local reset = SU.boolean(options.reset, true)
15✔
129
      -- Option reset=false is undocumented and was previously somewhat broken.
130
      -- It should perhaps be deprecated: is there a real use case for it?
131
      if level == currentLevel then
15✔
132
         counter.value[level] = counter.value[level] + 1
9✔
133
      elseif level > currentLevel then
6✔
134
         while level - 1 > currentLevel do
9✔
135
            currentLevel = currentLevel + 1
5✔
136
            counter.value[currentLevel] = 0
5✔
137
            counter.display[currentLevel] = counter.display[currentLevel - 1]
5✔
138
         end
139
         currentLevel = currentLevel + 1
4✔
140
         counter.value[level] = 1
4✔
141
         counter.display[level] = counter.display[currentLevel - 1]
4✔
142
      else -- level < currentLevel
143
         counter.value[level] = counter.value[level] + 1
2✔
144
         while currentLevel > level do
5✔
145
            if reset then
3✔
146
               counter.value[currentLevel] = nil
3✔
147
               counter.display[currentLevel] = nil
3✔
148
            end
149
            currentLevel = currentLevel - 1
3✔
150
         end
151
      end
152
      if options.display then
15✔
NEW
153
         counter.display[currentLevel] = options.display
×
154
      end
155
   end, "Increments the value of the multilevel counter <id> at the given <level> or the current level.")
275✔
156

157
   self:registerCommand(
520✔
158
      "set-multilevel-counter",
260✔
159
      function (options, _)
NEW
160
         local level = SU.cast("integer", SU.required(options, "level", "set-multilevel-counter"))
×
NEW
161
         local id = SU.required(options, "id", "set-multilevel-counter")
×
162

NEW
163
         local counter = self.class:getMultilevelCounter(id)
×
NEW
164
         local currentLevel = #counter.value
×
NEW
165
         if options.value then
×
NEW
166
            local value = SU.cast("integer", options.value)
×
NEW
167
            if level == currentLevel then
×
168
               -- e.g. set to x the level 3 of 1.2.3 => 1.2.x
NEW
169
               counter.value[level] = value
×
NEW
170
            elseif level > currentLevel then
×
171
               -- Fill all missing levels in-between, assuming same display format.
172
               -- e.g. set to x the level 3 of 1 => 1.0.x
NEW
173
               while level - 1 > currentLevel do
×
NEW
174
                  currentLevel = currentLevel + 1
×
NEW
175
                  counter.value[currentLevel] = 0
×
NEW
176
                  counter.display[currentLevel] = counter.display[currentLevel - 1]
×
177
               end
NEW
178
               currentLevel = currentLevel + 1
×
NEW
179
               counter.value[level] = value
×
NEW
180
               counter.display[level] = counter.display[currentLevel - 1]
×
181
            else -- level < currentLevel
182
               -- Reset all upper levels
183
               -- e.g. set to x the level 2 of 1.2.3 => 1.x
NEW
184
               counter.value[level] = value
×
NEW
185
               while currentLevel > level do
×
NEW
186
                  counter.value[currentLevel] = nil
×
NEW
187
                  counter.display[currentLevel] = nil
×
NEW
188
                  currentLevel = currentLevel - 1
×
189
               end
190
            end
191
         end
NEW
192
         if options.display then
×
NEW
193
            if level <= #counter.value then
×
NEW
194
               counter.display[level] = options.display
×
195
            else
NEW
196
               SU.warn("Ignoring attempt to set the display of a multilevel counter beyond its level")
×
197
            end
198
         end
199
      end,
200
      "Sets the multilevel counter named by the <id> option to <value> at level <level>; optionally sets its display type at that level to <display>."
201
   )
260✔
202

203
   self:registerCommand("show-multilevel-counter", function (options, _)
520✔
204
      local id = SU.required(options, "id", "show-multilevel-counter")
13✔
205

206
      local counter = self.class:getMultilevelCounter(id)
13✔
207
      if options.display then
13✔
NEW
208
         SU.deprecated(
×
209
            "\\show-multilevel-counter[display=...]",
210
            "\\set-multilevel-counter[display=...]",
211
            "0.14.4",
212
            "0.16.0"
213
         )
NEW
214
         counter.display[#counter.value] = options.display
×
215
      end
216

217
      SILE.typesetter:typeset(self:formatMultilevelCounter(counter, options))
26✔
218
   end, "Outputs the value of the multilevel counter <id>.")
273✔
219
end
220

221
package.documentation = [[
222
\begin{document}
223

224
Various parts of SILE such as the \autodoc:package{footnotes} package and the sectioning commands keep a counter of things going on: the current footnote number, the chapter number, and so on.
225
The counters package allows you to set up, increment, and typeset named counters.
226
It provides the following commands:
227

228
\begin{itemize}
229
\item{\autodoc:command{\set-counter[id=<counter-name>, value=<value>]}: Sets the counter with the specified name to the given value. The command takes an optional \autodoc:parameter{display=<display-type>} parameter to set the display type of the counter (see below).}
230
\item{\autodoc:command{\increment-counter[id=<counter-name>]}: Increments the counter by one. The command creates the counter if it does not exist and also accepts setting the display type.}
231
\item{\autodoc:command{\show-counter[id=<counter-name>]}: Typesets the value of the counter according to the counter’s declared display type.}
232
\end{itemize}
233

234

235
The available built-in display types are:
236

237
\begin{itemize}
238
\item{\code{arabic}, the default}
239
\item{\code{alpha}, for lower-case alphabetic counting}
240
\item{\code{Alpha}, for upper-case alphabetic counting}
241
\item{\code{roman}, for lower-case Roman numerals}
242
\item{\code{ROMAN} for upper-case Roman numerals}
243
\end{itemize}
244

245
The ICU library also provides ways of formatting numbers in global (non-Latin) scripts.
246
You can use any of the display types in this list: \url{http://www.unicode.org/repos/cldr/tags/latest/common/bcp47/number.xml}.
247
For example, \autodoc:parameter{display=beng} will format your numbers in Bengali digits.
248

249
So, for example, the following SILE code:
250

251
\begin[type=autodoc:codeblock]{raw}
252
\set-counter[id=mycounter, value=2]
253
\show-counter[id=mycounter]
254

255
\increment-counter[id=mycounter, display=roman]
256
\show-counter[id=mycounter]
257
\end{raw}
258

259
produces:
260

261
\fullrule
262
\autodoc:example{
263
\noindent{}2
264

265
\noindent{}iii}
266
\par
267
\fullrule
268

269
The package also provides multi-level (hierarchical) counters, of the kind used in sectioning
270
commands:
271

272
\begin{itemize}
273
\item{\autodoc:command{\set-multilevel-counter[id=<counter-name>, level=<level>, value=<value>]}:
274
Sets the multi-level counter with the specified name to the given value at the given level.
275
The command also takes an optional \autodoc:parameter{display=<display-type>}, also acting at the given level.}
276
\item{\autodoc:command{\increment-multilevel-counter[id=<counter-name>]}:
277
Increments the counter by one at its current (deepest) level.
278
The command creates the counter if it does not exist.
279
If given the \autodoc:parameter{level=<level>} parameter, the command increments that level,
280
clearing any lower level (and filling previous levels with zeros, if they weren’t properly set).
281
It also accepts setting the display type at the target level.}
282
\item{\autodoc:command{\show-multilevel-counter[id=<counter-name>]}:
283
Typesets the value of the multi-level counter according to the counter’s declared display types
284
at each level. By default, all levels are output; option \autodoc:parameter{level=<level>} may be
285
used to display the counter up to a given level. Option \autodoc:parameter{noleadingzeros=true}
286
skips any leading zero (which may happen if a counter is at some level, without previous levels
287
having been set).}
288
\end{itemize}
289
\end{document}
290
]]
181✔
291

292
return package
181✔
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