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

sile-typesetter / sile / 6915746301

18 Nov 2023 07:02PM UTC coverage: 56.433% (-12.3%) from 68.751%
6915746301

push

github

web-flow
Merge 8b3fdc301 into f64e235fa

8729 of 15468 relevant lines covered (56.43%)

932.75 hits per line

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

77.14
/core/settings.lua
1
local deprecator = function ()
2
  SU.deprecated("SILE.settings.*", "SILE.settings:*", "0.13.0", "0.15.0")
×
3
end
4

5
local settings = pl.class()
34✔
6

7
function settings:_init()
34✔
8

9
  self.state = {}
34✔
10
  self.declarations = {}
34✔
11
  self.stateQueue = {}
34✔
12
  self.defaults = {}
34✔
13

14
  self:declare({
34✔
15
    parameter = "document.language",
16
    type = "string",
17
    default = "en",
18
    help = "Locale for localized language support"
×
19
  })
20

21
  self:declare({
68✔
22
    parameter = "document.parindent",
23
    type = "glue",
24
    default = SILE.nodefactory.glue("20pt"),
68✔
25
    help = "Glue at start of paragraph"
×
26
  })
27

28
  self:declare({
68✔
29
    parameter = "document.baselineskip",
30
    type = "vglue",
31
    default = SILE.nodefactory.vglue("1.2em plus 1pt"),
68✔
32
    help = "Leading"
×
33
  })
34

35
  self:declare({
68✔
36
    parameter = "document.lineskip",
37
    type = "vglue",
38
    default = SILE.nodefactory.vglue("1pt"),
68✔
39
    help = "Leading"
×
40
  })
41

42
  self:declare({
68✔
43
    parameter = "document.parskip",
44
    type = "vglue",
45
    default = SILE.nodefactory.vglue("0pt plus 1pt"),
68✔
46
    help = "Leading"
×
47
  })
48

49
  self:declare({
34✔
50
    parameter = "document.spaceskip",
51
    type = "length or nil",
52
    default = nil,
53
    help = "The length of a space (if nil, then measured from the font)"
×
54
  })
55

56
  self:declare({
34✔
57
    parameter = "document.rskip",
58
    type = "glue or nil",
59
    default = nil,
60
    help = "Skip to be added to right side of line"
×
61
  })
62

63
  self:declare({
34✔
64
    parameter = "document.lskip",
65
    type = "glue or nil",
66
    default = nil,
67
    help = "Skip to be added to left side of line"
×
68
  })
69

70
  self:declare({
34✔
71
    parameter = "document.zenkakuchar",
72
    default = "あ",
73
    type = "string",
74
    help = "The character measured to determine the length of a zenkaku width (全角幅)"
×
75
  })
76

77
  SILE.registerCommand("set", function(options, content)
68✔
78
    local parameter = SU.required(options, "parameter", "\\set command")
18✔
79
    local makedefault = SU.boolean(options.makedefault, false)
18✔
80
    local reset = SU.boolean(options.reset, false)
18✔
81
    local value = options.value
18✔
82
    if content and (type(content) == "function" or content[1]) then
18✔
83
      if makedefault then
6✔
84
        SU.warn("Are you sure meant to set default settings *and* pass content to ostensibly apply them to temporarily?")
×
85
      end
86
      self:temporarily(function()
12✔
87
        self:set(parameter, value, makedefault, reset)
6✔
88
        SILE.process(content)
6✔
89
      end)
90
    else
91
      self:set(parameter, value, makedefault, reset)
12✔
92
    end
93
  end, "Set a SILE parameter <parameter> to value <value> (restoring the value afterwards if <content> is provided)", nil, true)
52✔
94

95
end
96

97
function settings:pushState ()
34✔
98
  if not self then return deprecator() end
158✔
99
  table.insert(self.stateQueue, self.state)
158✔
100
  self.state = pl.tablex.copy(self.state)
316✔
101
end
102

103
function settings:popState ()
34✔
104
  if not self then return deprecator() end
158✔
105
  self.state = table.remove(self.stateQueue)
316✔
106
end
107

108
function settings:declare (spec)
34✔
109
  if not spec then return deprecator() end
1,809✔
110
  if spec.name then
1,809✔
111
    SU.deprecated("'name' argument of SILE.settings:declare", "'parameter' argument of SILE.settings:declare", "0.10.10", "0.11.0")
×
112
  end
113
  if self.declarations[spec.parameter] then
1,809✔
114
    SU.debug("settings", "Attempt to re-declare setting: " .. spec.parameter)
225✔
115
    return
225✔
116
  end
117
  self.declarations[spec.parameter] = spec
1,584✔
118
  self:set(spec.parameter, spec.default, true)
1,584✔
119
end
120

121
--- Reset all settings to their default value.
122
function settings:reset ()
34✔
123
  if not self then return deprecator() end
×
124
  for k,_ in pairs(self.state) do
×
125
    self:set(k, self.defaults[k])
×
126
  end
127
end
128

129
--- Restore all settings to the value they had in the top-level state,
130
-- that is at the head of the settings stack (normally the document
131
-- level).
132
function settings:toplevelState ()
34✔
133
  if not self then return deprecator() end
24✔
134
  if #self.stateQueue ~= 0 then
24✔
135
    for parameter, _ in pairs(self.state) do
1,135✔
136
      -- Bypass self:set() as the latter performs some tests and a cast,
137
      -- but the setting might not have been defined in the top level state
138
      -- (in which case, assume the default value).
139
      self.state[parameter] = self.stateQueue[1][parameter] or self.defaults[parameter]
1,111✔
140
    end
141
  end
142
end
143

144
function settings:get (parameter)
34✔
145
  -- HACK FIXME https://github.com/sile-typesetter/sile/issues/1699
146
  -- See comment on set() below.
147
  if parameter == "current.parindent" then
41,679✔
148
    return SILE.typesetter and SILE.typesetter.state.parindent
123✔
149
  end
150
  if not parameter then return deprecator() end
41,556✔
151
  if not self.declarations[parameter] then
41,556✔
152
    SU.error("Undefined setting '"..parameter.."'")
×
153
  end
154
  if type(self.state[parameter]) ~= "nil" then
41,556✔
155
    return self.state[parameter]
33,405✔
156
  else
157
    return self.defaults[parameter]
8,151✔
158
  end
159
end
160

161
function settings:set (parameter, value, makedefault, reset)
34✔
162
  -- HACK FIXME https://github.com/sile-typesetter/sile/issues/1699
163
  -- Anything dubbed current.xxx should likely NOT be a "setting" (subject
164
  -- to being pushed/popped via temporary stacking) and actually has its
165
  -- own lifecycle (e.g. reset for the next paragraph).
166
  -- These should be rather typesetter states, or something to that extent
167
  -- yet to clarify. Notably, current.parindent falls in that category,
168
  -- BUT probably current.hangAfter and current.hangIndent too.
169
  -- To avoid breaking too much code yet without being sure of the solution,
170
  -- we implement a hack of sorts for current.parindent only.
171
  -- Note moreover that current.parindent is currently probably a bad concept
172
  -- anyway:
173
  --   - It can be nil (= document.parindent applies)
174
  --   - It can be a zero-glue (\noindent, ragged environments, etc.)
175
  --   - It can be a valued glue set to document.parindent
176
  --     (e.g. from \indent, and document.parindent thus applies)
177
  --   - It could be another valued glue (uh, use case to ascertain)
178
  -- What we would _likely_ only need to track is whether document.parindent
179
  -- applies or not on the paragraph just composed afterwards...
180
  if parameter == "current.parindent" then
2,168✔
181
    if SILE.typesetter and not SILE.typesetter.state.hmodeOnly then
185✔
182
      SILE.typesetter.state.parindent = SU.cast("glue or nil", value)
334✔
183
    end
184
    return
185✔
185
  end
186
  if type(self) ~= "table" then return deprecator() end
1,983✔
187
  if not self.declarations[parameter] then
1,983✔
188
    SU.error("Undefined setting '"..parameter.."'")
×
189
  end
190
  if reset then
1,983✔
191
    if makedefault then
4✔
192
      SU.error("Can't set a new default and revert to and old default setting at the same time!")
×
193
    end
194
    value = self.defaults[parameter]
4✔
195
  else
196
    value = SU.cast(self.declarations[parameter].type, value)
3,958✔
197
  end
198
  self.state[parameter] = value
1,983✔
199
  if makedefault then
1,983✔
200
    self.defaults[parameter] = value
1,571✔
201
  end
202
end
203

204
function settings:temporarily (func)
34✔
205
  if not func then return deprecator() end
122✔
206
  self:pushState()
122✔
207
  func()
122✔
208
  self:popState()
122✔
209
end
210

211
function settings:wrap () -- Returns a closure which applies the current state, later
34✔
212
  if not self then return deprecator() end
×
213
  local clSettings = pl.tablex.copy(self.state)
×
214
  return function(content)
215
    table.insert(self.stateQueue, self.state)
×
216
    self.state = clSettings
×
217
    SILE.process(content)
×
218
    self:popState()
×
219
  end
220
end
221

222
return settings
34✔
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