summaryrefslogtreecommitdiff
path: root/mac/.config/mpv/script-modules/utf8/charclass/runtime/base.lua
blob: 33d77138e43161350705ea68e8ea62e19eb37ffc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
return function(utf8)

local class = {}
local mt = {__index = class}

local utf8gensub = utf8.gensub

function class.new()
  return setmetatable({}, mt)
end

function class:invert()
  self.inverted = true
  return self
end

function class:with_codes(...)
  local codes = {...}
  self.codes = self.codes or {}

  for _, v in ipairs(codes) do
    table.insert(self.codes, v)
  end

  table.sort(self.codes)
  return self
end

function class:with_ranges(...)
  local ranges = {...}
  self.ranges = self.ranges or {}

  for _, v in ipairs(ranges) do
    table.insert(self.ranges, v)
  end

  return self
end

function class:with_classes(...)
  local classes = {...}
  self.classes = self.classes or {}

  for _, v in ipairs(classes) do
    table.insert(self.classes, v)
  end

  return self
end

function class:without_classes(...)
  local not_classes = {...}
  self.not_classes = self.not_classes or {}

  for _, v in ipairs(not_classes) do
    table.insert(self.not_classes, v)
  end

  return self
end

function class:with_subs(...)
  local subs = {...}
  self.subs = self.subs or {}

  for _, v in ipairs(subs) do
    table.insert(self.subs, v)
  end

  return self
end

function class:in_codes(item)
  if not self.codes or #self.codes == 0 then return nil end

  local head, tail = 1, #self.codes
  local mid = math.floor((head + tail)/2)
  while (tail - head) > 1 do
    if self.codes[mid] > item then
      tail = mid
    else
      head = mid
    end
    mid = math.floor((head + tail)/2)
  end
  if self.codes[head] == item then
    return true, head
  elseif self.codes[tail] == item then
    return true, tail
  else
    return false
  end
end

function class:in_ranges(char_code)
  if not self.ranges or #self.ranges == 0 then return nil end

  for _,r in ipairs(self.ranges) do
    if r[1] <= char_code and char_code <= r[2] then
      return true
    end
  end
  return false
end

function class:in_classes(char_code)
  if not self.classes or #self.classes == 0 then return nil end

  for _, class in ipairs(self.classes) do
    if self:is(class, char_code) then
      return true
    end
  end
  return false
end

function class:in_not_classes(char_code)
  if not self.not_classes or #self.not_classes == 0 then return nil end

  for _, class in ipairs(self.not_classes) do
    if self:is(class, char_code) then
      return true
    end
  end
  return false
end

function class:is(class, char_code)
  error("not implemented")
end

function class:in_subs(char_code)
  if not self.subs or #self.subs == 0 then return nil end

  for _, c in ipairs(self.subs) do
    if not c:test(char_code) then
      return false
    end
  end
  return true
end

function class:test(char_code)
  local result = self:do_test(char_code)
  -- utf8.debug('class:test', result, "'" .. (char_code and utf8.char(char_code) or 'nil') .. "'", char_code)
  return result
end

function class:do_test(char_code)
  if not char_code then return false end
  local in_not_classes = self:in_not_classes(char_code)
  if in_not_classes then
    return not not self.inverted
  end
  local in_codes = self:in_codes(char_code)
  if in_codes then
    return not self.inverted
  end
  local in_ranges = self:in_ranges(char_code)
  if in_ranges then
    return not self.inverted
  end
  local in_classes = self:in_classes(char_code)
  if in_classes then
    return not self.inverted
  end
  local in_subs = self:in_subs(char_code)
  if in_subs then
    return not self.inverted
  end
  if (in_codes == nil)
  and (in_ranges == nil)
  and (in_classes == nil)
  and (in_subs == nil)
  and (in_not_classes == false) then
    return not self.inverted
  else
    return not not self.inverted
  end
end

return class

end