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

sile-typesetter / sile / 11534409649

26 Oct 2024 07:27PM UTC coverage: 33.196% (-28.7%) from 61.897%
11534409649

push

github

alerque
chore(tooling): Update editor-config key for stylua as accepted upstream

Our setting addition is still not in a tagged release, but the PR was
accepted into the default branch of stylua. This means you no longer
need to run my fork of Stylua to get this project's style, you just nead
any build from the main development branch. However the config key was
renamed as part of the acceptance, so this is the relevant adjustment.

5810 of 17502 relevant lines covered (33.2%)

1300.57 hits per line

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

83.2
/inputters/sil.lua
1
local base = require("inputters.base")
10✔
2

3
local _variant = "epnf"
10✔
4
local parser
5
local function load_parser ()
6
   parser = require("inputters.sil-" .. _variant)
9✔
7
end
8

9
local inputter = pl.class(base)
10✔
10
inputter._name = "sil"
10✔
11

12
inputter.order = 50
10✔
13

14
inputter.appropriate = function (round, filename, doc)
15
   if not parser then
9✔
16
      load_parser()
9✔
17
   end
18
   if round == 1 then
9✔
19
      return filename:match(".sil$")
9✔
20
   elseif round == 2 then
×
21
      local sniff = doc:sub(1, 100)
×
22
      local promising = sniff:match("\\begin") or sniff:match("\\document") or sniff:match("\\sile")
×
23
      return promising and inputter.appropriate(3, filename, doc) or false
×
24
   elseif round == 3 then
×
25
      local status, _ = pcall(parser, doc)
×
26
      return status
×
27
   end
28
end
29

30
function inputter:_init (options)
10✔
31
   options = options or {}
9✔
32
   if options.variant then
9✔
33
      _variant = options.variant
×
34
      load_parser()
×
35
   else
36
      if not parser then
9✔
37
         load_parser()
×
38
      end
39
   end
40
   -- Save time when parsing strings by only setting up the grammar once per
41
   -- instantiation then re-using it on every use.
42
   self._parser = parser
9✔
43
   base._init(self)
9✔
44
end
45

46
local linecache = {}
10✔
47
local lno, col, lastpos
48
local function resetCache ()
49
   lno = 1
9✔
50
   col = 1
9✔
51
   lastpos = 0
9✔
52
   linecache = { { lno = 1, pos = 1 } }
9✔
53
end
54

55
local function getline (str, pos)
56
   local start = 1
248✔
57
   lno = 1
248✔
58
   if pos > lastpos then
248✔
59
      lno = linecache[#linecache].lno
236✔
60
      start = linecache[#linecache].pos + 1
236✔
61
      col = 1
236✔
62
   else
63
      for j = 1, #linecache - 1 do
25✔
64
         if linecache[j + 1].pos >= pos then
25✔
65
            lno = linecache[j].lno
12✔
66
            col = pos - linecache[j].pos
12✔
67
            return lno, col
12✔
68
         end
69
      end
70
   end
71
   for i = start, pos do
7,578✔
72
      if string.sub(str, i, i) == "\n" then
14,684✔
73
         lno = lno + 1
163✔
74
         col = 1
163✔
75
         linecache[#linecache + 1] = { pos = i, lno = lno }
163✔
76
         lastpos = i
163✔
77
      end
78
      col = col + 1
7,342✔
79
   end
80
   return lno, col
236✔
81
end
82

83
local function ast_from_parse_tree (tree, doc, depth)
84
   if type(tree) == "string" then
349✔
85
      return tree
101✔
86
   end
87

88
   if tree.pos then
248✔
89
      tree.lno, tree.col = getline(doc, tree.pos)
496✔
90
      tree.pos = nil
248✔
91
   end
92

93
   local sep -- luacheck: ignore 211
94
   if SU.debugging("inputter") then
496✔
95
      depth = depth + 1
×
96
      sep = ("   "):rep(depth)
×
97
   end
98
   SU.debug("inputter", sep and (sep .. "Processing ID:"), tree.id)
248✔
99

100
   local res
101
   if tree.id == "comment" then
248✔
102
      -- Drop comments
103
      SU.debug("inputter", sep and (sep .. "Discarding comment"))
15✔
104
      res = {}
15✔
105
   elseif
×
106
      false
107
      or tree.id == "document"
233✔
108
      or tree.id == "braced_content"
233✔
109
      or tree.id == "passthrough_content"
221✔
110
      or tree.id == "braced_passthrough_content"
217✔
111
      or tree.id == "env_passthrough_content"
217✔
112
      or tree.id == "text"
216✔
113
      or tree.id == "passthrough_text"
120✔
114
      or tree.id == "braced_passthrough_text"
120✔
115
      or tree.id == "env_passthrough_text"
116✔
116
   then
117
      -- These nodes have only one child, which needs recursion.
118
      SU.debug("inputter", sep and (sep .. "Massaging a node"))
118✔
119
      res = ast_from_parse_tree(tree[1], doc, depth)
236✔
120
      --res = #res > 1 and not res.id and res or res[1]
121
   elseif false or tree.id == "environment" or tree.id == "command" then
115✔
122
      -- These nodes have multiple children, which need recursion.
123
      SU.debug("inputter", sep and (sep .. "Processing command"), tree.command, #tree, "subtrees")
83✔
124
      local newtree = { -- I don't think we can avoid a shallow copy here
83✔
125
         command = tree.command,
83✔
126
         options = tree.options,
83✔
127
         id = tree.id,
83✔
128
         lno = tree.lno,
83✔
129
         col = tree.col,
83✔
130
      }
131
      for _, node in ipairs(tree) do
113✔
132
         if type(node) == "table" then
30✔
133
            SU.debug("inputter", sep and (sep .. " -"), node.id or "table")
28✔
134
            local ast_node = ast_from_parse_tree(node, doc, depth)
28✔
135
            if type(ast_node) == "table" and not ast_node.id then
28✔
136
               SU.debug("inputter", sep and (sep .. " -"), "Collapsing subtree")
10✔
137
               -- Comments can an empty table, skip them
138
               if #ast_node > 0 then
10✔
139
                  -- Simplify the tree if it's just a plain list
140
                  for _, child in ipairs(ast_node) do
173✔
141
                     if type(child) ~= "table" or child.id or #child > 0 then
163✔
142
                        table.insert(newtree, child)
148✔
143
                     end
144
                  end
145
               end
146
            else
147
               table.insert(newtree, ast_node)
18✔
148
            end
149
         end
150
         -- Non table nodes are skipped (e.g. extraneous text from 'raw' commands)
151
      end
152
      res = newtree
83✔
153
   elseif tree.id == "content" then
32✔
154
      -- This node has multiple children, which need recursion
155
      -- And the node itself needs to be replaced with its children
156
      SU.debug("inputter", sep and (sep .. "Massage content node"), #tree, "subtrees")
32✔
157
      local newtree = {} -- I don't think we can avoid a shallow copy here
32✔
158
      for i, node in ipairs(tree) do
226✔
159
         SU.debug("inputter", sep and (sep .. " -"), node.id)
194✔
160
         newtree[i] = ast_from_parse_tree(node, doc, depth)
388✔
161
      end
162
      -- Simplify the tree if it has only one child
163
      res = #newtree == 1 and not newtree.id and newtree[1] or newtree
32✔
164
   elseif tree.id then
×
165
      -- Shouldn't happen, or we missed something
166
      SU.error("Unknown node type: " .. tree.id)
×
167
   else
168
      SU.debug("inputter", sep and (sep .. "Table node"), #tree, "subtrees")
×
169
      res = #tree == 1 and tree[1] or tree
×
170
   end
171
   SU.debug("inputter", sep and (sep .. "Returning a"), type(res) == "table" and res.id or "string")
248✔
172
   return res
248✔
173
end
174

175
function inputter:parse (doc)
10✔
176
   local status, result = pcall(self._parser, doc)
9✔
177
   if not status then
9✔
178
      return SU.error(([[
×
179
         Unable to parse input document to an AST tree
180

181
         Parser error:
182

183
           %s
184

185
         thrown from document beginning.]]):format(pl.stringx.indent(result, 6)))
×
186
   end
187
   resetCache()
9✔
188
   local top = ast_from_parse_tree(result[1], doc, 0)
9✔
189
   local tree
190
   -- Content not part of a tagged command could either be part of a document
191
   -- fragment or junk (e.g. comments, whitespace) outside of a document tag. We
192
   -- need to either capture the document tag only or decide this is a fragment
193
   -- and wrap it in a document tag.
194
   if top.command == "document" or top.command == "sile" then
9✔
195
      tree = top
×
196
   elseif type(top) == "table" then
9✔
197
      for _, leaf in ipairs(top) do
9✔
198
         if leaf.command and (leaf.command == "document" or leaf.command == "sile") then
9✔
199
            tree = leaf
9✔
200
            break
9✔
201
         end
202
      end
203
   end
204
   -- In the event we didn't isolate a top level document tag above, assume this
205
   -- is a fragment and wrap it in one.
206
   if not tree then
9✔
207
      tree = { top, command = "document" }
×
208
   end
209
   return { tree }
9✔
210
end
211

212
return inputter
10✔
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