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

sile-typesetter / sile / 11135083927

01 Oct 2024 11:26PM UTC coverage: 62.071% (-7.3%) from 69.333%
11135083927

push

github

alerque
style: Reformat Lua with stylua

0 of 9 new or added lines in 2 files covered. (0.0%)

1678 existing lines in 57 files now uncovered.

11071 of 17836 relevant lines covered (62.07%)

5220.48 hits per line

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

86.36
/core/settings.lua
1
--- core settings instance
2
--- @module SILE.settings
3

4
local deprecator = function ()
5
   SU.deprecated("SILE.settings.*", "SILE.settings:*", "0.13.0", "0.15.0")
×
6
end
7

8
--- @type settings
9
local settings = pl.class()
376✔
10

11
function settings:_init ()
376✔
12
   self.state = {}
376✔
13
   self.declarations = {}
376✔
14
   self.stateQueue = {}
376✔
15
   self.defaults = {}
376✔
16
   self.hooks = {}
376✔
17

18
   self:declare({
752✔
19
      parameter = "document.language",
20
      type = "string",
21
      default = "en",
22
      hook = function (language)
23
         if SILE.scratch.loaded_languages and not SILE.scratch.loaded_languages[language] then
1,263✔
24
            SU.warn(([[
42✔
25
               Setting document.language to '%s', but support for '%s' has not been loaded
26

27
               Consider invoking \language[main=%s] which loads language support before
28
               setting it or manually calling SILE.languageSupport.loadLanguage("%s").
29
            ]]):format(language, language, language, language))
21✔
30
         end
31
         fluent:set_locale(language)
1,263✔
32
      end,
33
      help = "Locale for localized language support",
34
   })
35

36
   self:declare({
752✔
37
      parameter = "document.parindent",
38
      type = "glue",
39
      default = SILE.types.node.glue("1bs"),
1,128✔
40
      help = "Glue at start of paragraph",
41
   })
42

43
   self:declare({
752✔
44
      parameter = "document.baselineskip",
45
      type = "vglue",
46
      default = SILE.types.node.vglue("1.2em plus 1pt"),
752✔
47
      help = "Leading",
48
   })
49

50
   self:declare({
752✔
51
      parameter = "document.lineskip",
52
      type = "vglue",
53
      default = SILE.types.node.vglue("1pt"),
752✔
54
      help = "Leading",
55
   })
56

57
   self:declare({
752✔
58
      parameter = "document.parskip",
59
      type = "vglue",
60
      default = SILE.types.node.vglue("0pt plus 1pt"),
752✔
61
      help = "Leading",
62
   })
63

64
   self:declare({
376✔
65
      parameter = "document.spaceskip",
66
      type = "length or nil",
67
      default = nil,
68
      help = "The length of a space (if nil, then measured from the font)",
69
   })
70

71
   self:declare({
376✔
72
      parameter = "document.rskip",
73
      type = "glue or nil",
74
      default = nil,
75
      help = "Skip to be added to right side of line",
76
   })
77

78
   self:declare({
376✔
79
      parameter = "document.lskip",
80
      type = "glue or nil",
81
      default = nil,
82
      help = "Skip to be added to left side of line",
83
   })
84

85
   self:declare({
376✔
86
      parameter = "document.zenkakuchar",
87
      default = "あ",
88
      type = "string",
89
      help = "The character measured to determine the length of a zenkaku width (全角幅)",
90
   })
91

92
   SILE.registerCommand(
752✔
93
      "set",
376✔
94
      function (options, content)
95
         local makedefault = SU.boolean(options.makedefault, false)
115✔
96
         local reset = SU.boolean(options.reset, false)
115✔
97
         local value = options.value
115✔
98
         if content and (type(content) == "function" or content[1]) then
115✔
99
            if makedefault then
10✔
UNCOV
100
               SU.warn(
×
101
                  "Are you sure meant to set default settings *and* pass content to ostensibly apply them to temporarily?"
102
               )
103
            end
104
            self:temporarily(function ()
20✔
105
               if options.parameter then
10✔
106
                  local parameter = SU.required(options, "parameter", "\\set command")
9✔
107
                  self:set(parameter, value, makedefault, reset)
9✔
108
               end
109
               SILE.process(content)
10✔
110
            end)
111
         else
112
            local parameter = SU.required(options, "parameter", "\\set command")
105✔
113
            self:set(parameter, value, makedefault, reset)
105✔
114
         end
115
      end,
116
      "Set a SILE parameter <parameter> to value <value> (restoring the value afterwards if <content> is provided)",
376✔
117
      nil,
376✔
118
      true
119
   )
376✔
120
end
121

122
--- Stash the current values of all settings in a stack to be returned to later
123
function settings:pushState ()
376✔
124
   if not self then
1,588✔
UNCOV
125
      return deprecator()
×
126
   end
127
   table.insert(self.stateQueue, self.state)
1,588✔
128
   self.state = pl.tablex.copy(self.state)
3,176✔
129
end
130

131
--- Return the most recently pushed set of values in the setting stack
132
function settings:popState ()
376✔
133
   if not self then
1,592✔
UNCOV
134
      return deprecator()
×
135
   end
136
   local previous = self.state
1,592✔
137
   self.state = table.remove(self.stateQueue)
3,184✔
138
   for parameter, oldvalue in pairs(previous) do
86,756✔
139
      if self.hooks[parameter] then
85,164✔
140
         local newvalue = self.state[parameter]
85,164✔
141
         if oldvalue ~= newvalue then
85,164✔
142
            self:runHooks(parameter, newvalue)
1,912✔
143
         end
144
      end
145
   end
146
end
147

148
--- Declare a new setting
149
--- @tparam table specs { parameter, type, default, help, hook, ... } declaration specification
150
function settings:declare (spec)
376✔
151
   if not spec then
19,813✔
UNCOV
152
      return deprecator()
×
153
   end
154
   if spec.name then
19,813✔
UNCOV
155
      SU.deprecated(
×
156
         "'name' argument of SILE.settings:declare",
157
         "'parameter' argument of SILE.settings:declare",
158
         "0.10.10",
159
         "0.11.0"
160
      )
161
   end
162
   if self.declarations[spec.parameter] then
19,813✔
163
      SU.debug("settings", "Attempt to re-declare setting:", spec.parameter)
1,716✔
164
      return
1,716✔
165
   end
166
   self.declarations[spec.parameter] = spec
18,097✔
167
   self.hooks[spec.parameter] = {}
18,097✔
168
   if spec.hook then
18,097✔
169
      self:registerHook(spec.parameter, spec.hook)
376✔
170
   end
171
   self:set(spec.parameter, spec.default, true)
18,097✔
172
end
173

174
--- Reset all settings to their registered default values.
175
function settings:reset ()
376✔
176
   if not self then
×
UNCOV
177
      return deprecator()
×
178
   end
179
   for k, _ in pairs(self.state) do
×
UNCOV
180
      self:set(k, self.defaults[k])
×
181
   end
182
end
183

184
--- Restore all settings to the value they had in the top-level state,
185
-- that is at the tap of the settings stack (normally the document level).
186
function settings:toplevelState ()
376✔
187
   if not self then
130✔
UNCOV
188
      return deprecator()
×
189
   end
190
   if #self.stateQueue ~= 0 then
130✔
191
      for parameter, _ in pairs(self.state) do
6,697✔
192
         -- Bypass self:set() as the latter performs some tests and a cast,
193
         -- but the setting might not have been defined in the top level state
194
         -- (in which case, assume the default value).
195
         self.state[parameter] = self.stateQueue[1][parameter] or self.defaults[parameter]
6,567✔
196
      end
197
   end
198
end
199

200
--- Get the value of a setting
201
-- @tparam string parameter The full name of the setting to fetch.
202
-- @return Value of setting
203
function settings:get (parameter)
376✔
204
   -- HACK FIXME https://github.com/sile-typesetter/sile/issues/1699
205
   -- See comment on set() below.
206
   if parameter == "current.parindent" then
253,664✔
207
      return SILE.typesetter and SILE.typesetter.state.parindent
1,651✔
208
   end
209
   if not parameter then
252,013✔
UNCOV
210
      return deprecator()
×
211
   end
212
   if not self.declarations[parameter] then
252,013✔
UNCOV
213
      SU.error("Undefined setting '" .. parameter .. "'")
×
214
   end
215
   if type(self.state[parameter]) ~= "nil" then
252,013✔
216
      return self.state[parameter]
164,542✔
217
   else
218
      return self.defaults[parameter]
87,471✔
219
   end
220
end
221

222
--- Set the value of a setting
223
-- @tparam string parameter The full name of the setting to change.
224
-- @param value The new value to change it to.
225
-- @tparam[opt=false] boolean makedefault Whether to make this the new default value.
226
-- @tparam[opt=false] boolean reset Whether to reset the value to the current default value.
227
function settings:set (parameter, value, makedefault, reset)
376✔
228
   -- HACK FIXME https://github.com/sile-typesetter/sile/issues/1699
229
   -- Anything dubbed current.xxx should likely NOT be a "setting" (subject
230
   -- to being pushed/popped via temporary stacking) and actually has its
231
   -- own lifecycle (e.g. reset for the next paragraph).
232
   -- These should be rather typesetter states, or something to that extent
233
   -- yet to clarify. Notably, current.parindent falls in that category,
234
   -- BUT probably current.hangAfter and current.hangIndent too.
235
   -- To avoid breaking too much code yet without being sure of the solution,
236
   -- we implement a hack of sorts for current.parindent only.
237
   -- Note moreover that current.parindent is currently probably a bad concept
238
   -- anyway:
239
   --   - It can be nil (= document.parindent applies)
240
   --   - It can be a zero-glue (\noindent, ragged environments, etc.)
241
   --   - It can be a valued glue set to document.parindent
242
   --     (e.g. from \indent, and document.parindent thus applies)
243
   --   - It could be another valued glue (uh, use case to ascertain)
244
   -- What we would _likely_ only need to track is whether document.parindent
245
   -- applies or not on the paragraph just composed afterwards...
246
   if parameter == "current.parindent" then
31,401✔
247
      if SILE.typesetter and not SILE.typesetter.state.hmodeOnly then
2,706✔
248
         SILE.typesetter.state.parindent = SU.cast("glue or nil", value)
5,004✔
249
      end
250
      return
2,706✔
251
   end
252
   if type(self) ~= "table" then
28,695✔
UNCOV
253
      return deprecator()
×
254
   end
255
   if not self.declarations[parameter] then
28,695✔
UNCOV
256
      SU.error("Undefined setting '" .. parameter .. "'")
×
257
   end
258
   if reset then
28,695✔
259
      if makedefault then
5✔
UNCOV
260
         SU.error("Can't set a new default and revert to and old default setting at the same time")
×
261
      end
262
      value = self.defaults[parameter]
5✔
263
   else
264
      value = SU.cast(self.declarations[parameter].type, value)
57,380✔
265
   end
266
   self.state[parameter] = value
28,695✔
267
   if makedefault then
28,695✔
268
      self.defaults[parameter] = value
18,177✔
269
   end
270
   self:runHooks(parameter, value)
28,695✔
271
end
272

273
--- Register a callback hook to be run when a setting changes.
274
-- @tparam string parameter Name of the setting to add a hook to.
275
-- @tparam function func Callback function accepting one argument (the new value).
276
function settings:registerHook (parameter, func)
376✔
277
   table.insert(self.hooks[parameter], func)
376✔
278
end
279

280
--- Trigger execution of callback hooks for a given setting.
281
-- @tparam string parameter The name of the parameter changes.
282
-- @param value The new value of the setting, passed as the first argument to the hook function.
283
function settings:runHooks (parameter, value)
376✔
284
   if self.hooks[parameter] then
30,607✔
285
      for _, func in ipairs(self.hooks[parameter]) do
31,870✔
286
         SU.debug("classhooks", "Running setting hook for", parameter)
1,263✔
287
         func(value)
1,263✔
288
      end
289
   end
290
end
291

292
--- Isolate a block of processing so that setting changes made during the block don't last past the block.
293
-- (Under the hood this just uses `:pushState()`, the processes the function, then runs `:popState()`)
294
-- @tparam function func A function wrapping the actions to take without affecting settings for future use.
295
function settings:temporarily (func)
376✔
296
   if not func then
1,191✔
UNCOV
297
      return deprecator()
×
298
   end
299
   self:pushState()
1,191✔
300
   func()
1,191✔
301
   self:popState()
1,191✔
302
end
303

304
--- Create a settings wrapper function that applies current settings to later content processing.
305
--- @treturn function a closure function accepting one argument (content) to process using
306
--- typesetter settings as they are at the time of closure creation.
307
function settings:wrap ()
376✔
308
   if not self then
13✔
UNCOV
309
      return deprecator()
×
310
   end
311
   local clSettings = pl.tablex.copy(self.state)
13✔
312
   return function (content)
313
      table.insert(self.stateQueue, self.state)
4✔
314
      self.state = clSettings
4✔
315
      SILE.process(content)
4✔
316
      self:popState()
4✔
317
   end
318
end
319

320
return settings
376✔
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