Skip to content

Commit 40f6d3d

Browse files
authored
Merge pull request #3 from AckslD/dev
Dev
2 parents efe215e + 116a568 commit 40f6d3d

16 files changed

Lines changed: 756 additions & 500 deletions

LICENSE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Copyright (c) Axel Dahlberg. Distributed under the same terms as Vim itself. See `:help license`.

lua/pytrize/api.lua

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,56 @@
11
local M = {}
22

33
M.clear = function(bufnr)
4-
local marks = require('pytrize.marks')
5-
marks.clear(bufnr)
4+
local marks = require('pytrize.marks')
5+
6+
if bufnr == nil then bufnr = 0 end
7+
marks.clear(bufnr)
68
end
79

810
M.set = function(bufnr)
9-
local cs = require('pytrize.call_spec')
10-
local params = require('pytrize.params')
11-
local marks = require('pytrize.marks')
11+
local cs = require('pytrize.call_spec')
12+
local marks = require('pytrize.marks')
1213

13-
if bufnr == nil then
14-
bufnr = 0
15-
end
16-
marks.clear(bufnr)
17-
local param_order, call_specs = cs.get()
18-
if param_order == nil then
19-
return
20-
end
21-
local param_values = params.get_values(param_order, bufnr)
22-
if param_values == nil then
23-
return
24-
end
25-
local ext_id = 1 -- TODO why doesn't automatic assignment work
14+
if bufnr == nil then bufnr = 0 end
15+
marks.clear(bufnr)
16+
local call_specs_per_func = cs.get_calls(bufnr)
17+
if call_specs_per_func == nil then
18+
return
19+
end
20+
for _, call_specs in pairs(call_specs_per_func) do
2621
for _, call_spec in ipairs(call_specs) do
27-
for i, list_entry_node in ipairs(cs.list_entries(call_spec.call_node)) do
28-
local param_id = params.get_id(param_values[call_spec.func_name], call_spec.params, i)
29-
-- local ext_id = marks.set{ TODO
22+
for _, entry_spec in ipairs(call_spec.entries) do
23+
local entry_row = entry_spec.node:start()
24+
marks.set{
25+
bufnr = bufnr,
26+
text = entry_spec.id,
27+
row = entry_row,
28+
}
29+
for _, item_spec in ipairs(entry_spec.items) do
30+
local item_row = item_spec.node:start()
31+
if item_row ~= entry_row then
3032
marks.set{
3133
bufnr = bufnr,
32-
text = param_id,
33-
row = list_entry_node:start(),
34-
ext_id = ext_id,
34+
text = item_spec.id,
35+
row = item_spec.node:start(),
3536
}
36-
ext_id = ext_id + 1 -- TODO
37+
end
3738
end
39+
end
3840
end
41+
end
3942
end
4043

4144
M.jump = function()
42-
local jump = require('pytrize.jump')
43-
jump.to_param_declaration()
45+
local jump = require('pytrize.jump')
46+
47+
jump.to_param_declaration()
4448
end
4549

4650
M.jump_fixture = function()
47-
local jump = require('pytrize.jump')
48-
jump.to_fixture_declaration()
51+
local jump = require('pytrize.jump')
52+
53+
jump.to_fixture_declaration()
4954
end
5055

5156
return M

lua/pytrize/call_spec.lua

Lines changed: 147 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,183 @@
11
local M = {}
22

33
local ts = vim.treesitter
4-
local ts_utils = require('nvim-treesitter.ts_utils')
54
local ts_query = ts.query
6-
local reverse = require('pytrize.tables').reverse
5+
76
local warn = require('pytrize.warn').warn
7+
local tbls = require('pytrize.tables')
88

9-
local function get_root()
10-
local parser = ts.get_parser()
9+
local get_root = function(bufnr)
10+
local parser = ts.get_parser(bufnr)
1111
local tstree = parser:parse()[1]
1212
return tstree:root()
1313
end
1414

15-
local function get_param_call_nodes()
16-
local tsroot = get_root()
15+
local get_param_call_nodes = function(bufnr)
16+
local tsroot = get_root(bufnr)
1717
local query = ts_query.parse_query(
1818
'python',
19-
'(call function: (attribute) @param) (#eq? @param "pytest.mark.parametrize")'
19+
-- TODO not sure why eg (#eq? @param "pytest.mark.parametrize") does not work
20+
[[
21+
(decorated_definition (
22+
decorator (
23+
call
24+
function: ((attribute) @param)
25+
)
26+
))
27+
]]
2028
)
2129
local nodes = {}
2230
for _, node, _ in query:iter_captures(tsroot) do
31+
if ts.get_node_text(node, bufnr) == 'pytest.mark.parametrize' then
2332
table.insert(nodes, node:parent())
33+
end
2434
end
2535
return nodes
2636
end
2737

28-
M.get = function()
29-
local calls = get_param_call_nodes()
30-
local call_specs = {}
31-
local param_order = {}
32-
for _, call in ipairs(calls) do
33-
-- Move to separate func, better way?
34-
local decorated_definition = call:parent():parent()
35-
if decorated_definition:type() ~= 'decorated_definition' then
36-
warn("couldn't parse params")
37-
return
38-
end
39-
local func = decorated_definition:field('definition')[1]
40-
local func_name = ts_utils.get_node_text(func:field('name')[1])[1]
38+
local get_second_arg_node = function(call_node)
39+
local arguments = call_node:field('arguments')[1]
40+
return arguments:child(3)
41+
end
4142

42-
local arguments = call:field('arguments')[1]
43-
local params_node = arguments:child(1)
44-
if params_node:type() ~= 'string' then
45-
warn("couldn't parse params")
46-
return
47-
end
48-
local params_str = ts_utils.get_node_text(params_node)[1] -- TODO multiline strings?
49-
params_str = params_str:sub(2, -2)
50-
local params = vim.fn.split(params_str, [[,\s*]]) -- TODO avoid vim script?
51-
table.insert(call_specs, {
52-
call_node = call,
53-
params = params,
54-
func_name = func_name,
55-
})
56-
for _, param in ipairs(reverse(params)) do
57-
table.insert(param_order, param)
58-
end
43+
local get_named_children = function(node)
44+
local children = {}
45+
for child in node:iter_children() do
46+
if child:named() and child:type() ~= 'comment' then
47+
table.insert(children, child)
5948
end
60-
return reverse(param_order), call_specs
49+
end
50+
return children
6151
end
6252

63-
M.has_param = function(call_spec, param)
64-
for _, p in ipairs(call_spec.params) do
65-
if p == param then
66-
return true
67-
end
53+
local list_entries = function(call_node)
54+
local list = get_second_arg_node(call_node)
55+
if list:type() ~= 'list' then
56+
return {}
6857
end
69-
return false
58+
return get_named_children(list)
7059
end
7160

72-
local non_entry_types = {
73-
['comment'] = true,
74-
-- TODO why are these even entry types?
75-
['['] = true,
76-
[','] = true,
77-
[']'] = true,
61+
local LITERALS = {
62+
integer = true,
63+
float = true,
64+
['true'] = true,
65+
['false'] = true,
7866
}
7967

80-
M.get_second_arg_node = function(call_node)
81-
local arguments = call_node:field('arguments')[1]
82-
return arguments:child(3)
68+
local is_simple_literal = function(node)
69+
return LITERALS[node:type()] ~= nil
8370
end
8471

85-
M.list_entries = function(call_node)
86-
local entry_nodes = {}
87-
local list = M.get_second_arg_node(call_node)
88-
if list:type() ~= 'list' then
89-
return entry_nodes
72+
local get_item_id = function(entry_idx, item_node, param, bufnr)
73+
if item_node:type() == 'string' then
74+
local str = ts.get_node_text(item_node, bufnr)
75+
local quote = str:sub(1, 1)
76+
str = vim.fn.trim(str, quote):gsub('\n', '\\n')
77+
return str
78+
elseif is_simple_literal(item_node) then
79+
return ts.get_node_text(item_node, bufnr)
80+
end
81+
return string.format('%s%d', param, entry_idx)
82+
end
83+
84+
local get_entry = function(entry_idx, entry_node, params, bufnr)
85+
if entry_node:type() ~= 'tuple' then
86+
if #params == 1 then
87+
return {{
88+
id = get_item_id(entry_idx, entry_node, params[1], bufnr),
89+
node = entry_node,
90+
param = params[1],
91+
idx = entry_idx,
92+
}}
93+
else
94+
return {{
95+
id = string.format('unknown (%d)', entry_idx),
96+
node = entry_node,
97+
}}
98+
end
99+
end
100+
local items = {}
101+
local item_nodes = get_named_children(entry_node)
102+
if #params ~= #item_nodes then
103+
-- TODO warn here?
104+
-- warn(string.format(
105+
-- 'number of items in entry tuple differ from number of params, %d items and %d params (line %d in %s)',
106+
-- #item_nodes,
107+
-- #params,
108+
-- entry_node:start() + 1,
109+
-- vim.fn.bufname(bufnr)
110+
-- ))
111+
return nil
112+
end
113+
for i, param in ipairs(params) do
114+
table.insert(items, {
115+
id = get_item_id(entry_idx, item_nodes[i], param, bufnr),
116+
node = item_nodes[i],
117+
param = param,
118+
idx = entry_idx,
119+
})
120+
end
121+
return items
122+
end
123+
124+
local get_entries = function(call_node, params, bufnr)
125+
local entries = {}
126+
for entry_idx, entry_node in ipairs(list_entries(call_node)) do
127+
local items = get_entry(entry_idx - 1, entry_node, params, bufnr)
128+
if items ~= nil then
129+
table.insert(entries, {
130+
id = table.concat(tbls.list_map(function(item) return item.id end, items), '-'),
131+
items = items,
132+
node = entry_node,
133+
})
90134
end
91-
for child in list:iter_children() do
92-
if non_entry_types[child:type()] == nil then
93-
table.insert(entry_nodes, child)
94-
end
135+
end
136+
return entries
137+
end
138+
139+
M.get_calls = function(bufnr)
140+
local calls = get_param_call_nodes(bufnr or 0)
141+
local call_specs = {}
142+
for _, call in ipairs(calls) do
143+
-- Move to separate func, better way?
144+
local decorated_definition = call:parent():parent()
145+
if decorated_definition:type() ~= 'decorated_definition' then
146+
local row = call:start()
147+
warn(string.format(
148+
"couldn't parse params (line %d)\n expected `decorated_definition`\n got `%s`",
149+
row,
150+
decorated_definition:type()
151+
))
152+
return
153+
end
154+
local func = decorated_definition:field('definition')[1]
155+
local func_name = ts.get_node_text(func:field('name')[1], bufnr)
156+
157+
local arguments = call:field('arguments')[1]
158+
local params_node = arguments:child(1)
159+
if params_node:type() ~= 'string' then
160+
local row = call:start()
161+
warn(string.format(
162+
"couldn't parse params (line %d)\n expected `string`\n got `%s`",
163+
row,
164+
params_node:type()
165+
))
166+
return
95167
end
96-
return entry_nodes
168+
local params_str = ts.get_node_text(params_node, bufnr)
169+
params_str = params_str:sub(2, -2)
170+
local params = vim.fn.split(params_str, [[,\s*]]) -- TODO avoid vim script?
171+
local entries = get_entries(call, params, bufnr)
172+
if call_specs[func_name] == nil then call_specs[func_name] = {} end
173+
table.insert(call_specs[func_name], {
174+
node = call,
175+
entries = entries,
176+
params = params,
177+
func_name = func_name,
178+
})
179+
end
180+
return call_specs
97181
end
98182

99183
return M

lua/pytrize/input/builtin.lua

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
local M = {}
2-
local handler = {}
3-
4-
handler.prompt_files = function(prompt, files, callback)
5-
local textlist = {prompt}
6-
for i, file in ipairs(files) do
7-
table.insert(textlist, string.format('%d. %s', i, file))
8-
end
9-
local choice = vim.fn.inputlist(textlist)
10-
local file = files[choice]
11-
if file then
12-
callback(file)
13-
end
14-
end
15-
16-
M.load = function()
17-
return handler
18-
end
19-
20-
return M
1+
-- local M = {}
2+
-- local handler = {}
3+
--
4+
-- handler.prompt_files = function(prompt, files, callback)
5+
-- local textlist = {prompt}
6+
-- for i, file in ipairs(files) do
7+
-- table.insert(textlist, string.format('%d. %s', i, file))
8+
-- end
9+
-- local choice = vim.fn.inputlist(textlist)
10+
-- local file = files[choice]
11+
-- if file then
12+
-- callback(file)
13+
-- end
14+
-- end
15+
--
16+
-- M.load = function()
17+
-- return handler
18+
-- end
19+
--
20+
-- return M

0 commit comments

Comments
 (0)