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

sile-typesetter / sile / 7246678005

18 Dec 2023 10:19AM UTC coverage: 67.096% (-7.5%) from 74.62%
7246678005

push

github

web-flow
chore(deps): Bump actions/upload-artifact from 3 to 4 (#1940)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

10583 of 15773 relevant lines covered (67.1%)

3150.6 hits per line

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

92.97
/languages/unicode.lua
1
local icu = require("justenoughicu")
64✔
2

3
local chardata = require("char-def")
64✔
4

5
SILE.settings:declare({
64✔
6
  parameter = "languages.fixedNbsp",
7
  type = "boolean",
8
  default = false,
9
  help = "Whether to treat U+00A0 (NO-BREAK SPACE) as a fixed-width space"
×
10
})
11

12
SILE.nodeMakers.base = pl.class({
128✔
13

14
    _init = function (self, options)
15
      self.contents = {}
3,457✔
16
      self.options = options
3,457✔
17
      self.token = ""
3,457✔
18
      self.lastnode = false
3,457✔
19
      self.lasttype = false
3,457✔
20
    end,
21

22
    makeToken = function (self)
23
      if #self.contents > 0 then
9,536✔
24
        coroutine.yield(SILE.shaper:formNnode(self.contents, self.token, self.options))
13,204✔
25
        SU.debug("tokenizer", "Token:", self.token)
6,602✔
26
        self.contents = {}
6,602✔
27
        self.token = ""
6,602✔
28
        self.lastnode = "nnode"
6,602✔
29
      end
30
    end,
31

32
    addToken = function (self, char, item)
33
      self.token = self.token .. char
22,757✔
34
      table.insert(self.contents, item)
22,757✔
35
    end,
36

37
    makeGlue = function (self, item)
38
      if SILE.settings:get("typesetter.obeyspaces") or self.lastnode ~= "glue" then
5,824✔
39
        SU.debug("tokenizer", "Space node")
2,891✔
40
        coroutine.yield(SILE.shaper:makeSpaceNode(self.options, item))
5,782✔
41
      end
42
      self.lastnode = "glue"
2,912✔
43
      self.lasttype = "sp"
2,912✔
44
    end,
45

46
    makePenalty = function (self, p)
47
      if self.lastnode ~= "penalty" and self.lastnode ~= "glue" then
2,780✔
48
        coroutine.yield( SILE.nodefactory.penalty({ penalty = p or 0 }) )
58✔
49
      end
50
      self.lastnode = "penalty"
2,780✔
51
    end,
52

53
    makeNonBreakingSpace = function (self)
54
      -- Unicode Line Breaking Algorithm (UAX 14) specifies that U+00A0
55
      -- (NO-BREAK SPACE) is expanded or compressed like a normal space.
56
      coroutine.yield(SILE.nodefactory.kern(SILE.shaper:measureSpace(self.options)))
87✔
57
      self.lastnode = "glue"
29✔
58
      self.lasttype = "sp"
29✔
59
    end,
60

61
    iterator = function (_, _)
62
      SU.error("Abstract function nodemaker:iterator called", true)
×
63
    end,
64

65
    charData = function (_, char)
66
      local cp = SU.codepoint(char)
91,201✔
67
      if not chardata[cp] then return {} end
91,201✔
68
      return chardata[cp]
90,349✔
69
    end,
70

71
    isPunctuation = function (self, char)
72
      return self.isPunctuationType[self:charData(char).category]
×
73
    end,
74

75
    isSpace = function (self, char)
76
      return self.isSpaceType[self:charData(char).linebreak]
58,344✔
77
    end,
78

79
    isNonBreakingSpace = function (self, char)
80
      local c = self:charData(char)
22,815✔
81
      return c.contextname and c.contextname == "nobreakspace"
22,815✔
82
    end,
83

84
    isActiveNonBreakingSpace = function (self, char)
85
      return self:isNonBreakingSpace(char) and not SILE.settings:get("languages.fixedNbsp")
45,591✔
86
    end,
87

88
    isBreaking = function (self, char)
89
      return self.isBreakingType[self:charData(char).linebreak]
39,218✔
90
    end,
91
    isQuote = function (self, char)
92
      return self.isQuoteType[self:charData(char).linebreak]
39,210✔
93
    end
94

95
  })
64✔
96

97
SILE.nodeMakers.unicode = pl.class(SILE.nodeMakers.base)
128✔
98

99
SILE.nodeMakers.unicode.isWordType = { cm = true }
64✔
100
SILE.nodeMakers.unicode.isSpaceType = { sp = true }
64✔
101
SILE.nodeMakers.unicode.isBreakingType = { ba = true, zw = true }
64✔
102
SILE.nodeMakers.unicode.isPunctuationType = { po = true }
64✔
103
SILE.nodeMakers.unicode.isQuoteType = {} -- quote linebreak category is ambiguous depending on the language
64✔
104

105
function SILE.nodeMakers.unicode:dealWith (item)
128✔
106
  local char = item.text
19,613✔
107
  local cp = SU.codepoint(char)
19,613✔
108
  local thistype = chardata[cp] and chardata[cp].linebreak
19,613✔
109
  if self:isSpace(item.text) then
39,226✔
110
    self:makeToken()
4✔
111
    self:makeGlue(item)
8✔
112
  elseif self:isActiveNonBreakingSpace(item.text) then
39,218✔
113
    self:makeToken()
×
114
    self:makeNonBreakingSpace()
×
115
  elseif self:isBreaking(item.text) then
39,218✔
116
    self:addToken(char, item)
4✔
117
    self:makeToken()
4✔
118
    self:makePenalty(0)
8✔
119
  elseif self:isQuote(item.text) then
39,210✔
120
    self:addToken(char, item)
×
121
    self:makeToken()
×
122
  elseif self.lasttype and (thistype and thistype ~= self.lasttype and not self.isWordType[thistype]) then
19,605✔
123
    self:addToken(char, item)
188✔
124
  else
125
    self:letterspace()
19,511✔
126
    self:addToken(char, item)
19,511✔
127
  end
128
  self.lasttype = thistype
19,613✔
129
end
130

131
function SILE.nodeMakers.unicode:handleInitialGlue (items)
128✔
132
  local i = 1
3,455✔
133
  while i <= #items do
3,527✔
134
    local item = items[i]
3,506✔
135
    if self:isSpace(item.text) then self:makeGlue(item) else break end
7,084✔
136
    i = i + 1
72✔
137
  end
138
  return i, items
3,455✔
139
end
140

141
function SILE.nodeMakers.unicode:letterspace ()
128✔
142
  if not SILE.settings:get("document.letterspaceglue") then return end
39,022✔
143
  if self.token then self:makeToken() end
55✔
144
  if self.lastnode and self.lastnode ~= "glue" then
55✔
145
    local w = SILE.settings:get("document.letterspaceglue").width
102✔
146
    SU.debug("tokenizer", "Letter space glue:", w)
51✔
147
    coroutine.yield(SILE.nodefactory.kern({ width = w }))
102✔
148
    self.lastnode = "glue"
51✔
149
    self.lasttype = "sp"
51✔
150
  end
151
end
152

153
function SILE.nodeMakers.unicode.isICUBreakHere (_, chunks, item)
128✔
154
  return chunks[1] and (item.index >= chunks[1].index)
25,626✔
155
end
156

157
function SILE.nodeMakers.unicode:handleICUBreak (chunks, item)
128✔
158
  -- The ICU library has told us there is a breakpoint at
159
  -- this index. We need to...
160
  local bp = chunks[1]
6,012✔
161
  -- ... remove this breakpoint (and any out of order ones)
162
  -- from the ICU breakpoints array so that chunks[1] is
163
  -- the next index point for comparison against the string...
164
  while chunks[1] and item.index >= chunks[1].index do
12,026✔
165
    table.remove(chunks, 1)
12,028✔
166
  end
167
  -- ...decide which kind of breakpoint we have here and
168
  -- handle it appropriately.
169
  if bp.type == "word" then
6,012✔
170
    self:handleWordBreak(item)
6,468✔
171
  elseif bp.type == "line" then
2,778✔
172
    self:handleLineBreak(item, bp.subtype)
2,778✔
173
  end
174
  return chunks
6,012✔
175
end
176

177
function SILE.nodeMakers.unicode:handleWordBreak (item)
128✔
178
  self:makeToken()
3,232✔
179
  if self:isSpace(item.text) then
6,464✔
180
    -- Spacing word break
181
    self:makeGlue(item)
5,672✔
182
  elseif self:isActiveNonBreakingSpace(item.text) then
792✔
183
    -- Non-breaking space word break
184
    self:makeNonBreakingSpace()
58✔
185
  else
186
     -- a word break which isn't a space
187
    self:addToken(item.text, item)
367✔
188
  end
189
end
190

191
function SILE.nodeMakers.unicode:handleLineBreak (item, subtype)
128✔
192
  -- Because we are in charge of paragraphing, we
193
  -- will override space-type line breaks, and treat
194
  -- them just as ordinary word spaces.
195
  if self:isSpace(item.text) or self:isActiveNonBreakingSpace(item.text) then
8,328✔
196
    self:handleWordBreak(item)
×
197
    return
×
198
  end
199
  -- But explicit line breaks we will turn into
200
  -- soft and hard breaks.
201
  self:makeToken()
2,776✔
202
  self:makePenalty(subtype == "soft" and 0 or -1000)
2,776✔
203
  local char = item.text
2,776✔
204
  self:addToken(char, item)
2,776✔
205
  local cp = SU.codepoint(char)
2,776✔
206
  self.lasttype = chardata[cp] and chardata[cp].linebreak
2,776✔
207
end
208

209
function SILE.nodeMakers.unicode:iterator (items)
128✔
210
  local fulltext = ""
3,455✔
211
  for i = 1, #items do
29,153✔
212
    fulltext = fulltext .. items[i].text
25,698✔
213
  end
214
  local chunks = { icu.breakpoints(fulltext, self.options.language) }
3,455✔
215
  table.remove(chunks, 1)
3,455✔
216
  return coroutine.wrap(function ()
3,455✔
217
    local i
218
    i, self.items = self:handleInitialGlue(items)
6,910✔
219
    for j = i, #items do
29,081✔
220
      self.i = j
25,626✔
221
      self.item = self.items[self.i]
25,626✔
222
      if self:isICUBreakHere(chunks, self.item) then
51,252✔
223
        chunks = self:handleICUBreak(chunks, self.item)
12,024✔
224
      else
225
        self:dealWith(self.item)
19,614✔
226
      end
227
    end
228
    self:makeToken()
3,455✔
229
  end)
230
end
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