Skip to content

Commit cda05cb

Browse files
authored
feat: RustLsp relatedTests command (#779) (#942)
1 parent 7589ee1 commit cda05cb

File tree

7 files changed

+128
-7
lines changed

7 files changed

+128
-7
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,24 @@ vim.keymap.set(
536536

537537
</details>
538538

539+
<details>
540+
<summary>
541+
<b>Related tests</b>
542+
</summary>
543+
544+
Query rust-analyzer for tests associated with the symbol under
545+
the cursor (or its enclosing function) and quickly jump to one.
546+
547+
```vim
548+
:RustLsp relatedTests
549+
```
550+
551+
```lua
552+
vim.cmd.RustLsp('relatedTests')
553+
```
554+
555+
</details>
556+
539557
<details>
540558
<summary>
541559
<b>Open Cargo.toml</b>

doc/rustaceanvim.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ It accepts the following subcommands:
4949
'testables {args[]}?' - Run tests
5050
':RustLsp!' means run the last testable (ignores any args).
5151
`args[]` allows you to override the executable's arguments.
52+
'relatedTests' - Open the tests rust-analyzer associates with the symbol under the cursor.
5253
'expandMacro' - Expand macros recursively.
5354
'moveItem {up|down}' - Move items up or down.
5455
'codeAction' - Sometimes, rust-analyzer groups code actions by category,

lua/rustaceanvim/commands/init.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ local rustlsp_command_tbl = {
8989
require('rustaceanvim.commands.diagnostic').related_diagnostics()
9090
end,
9191
},
92+
relatedTests = {
93+
impl = function()
94+
require('rustaceanvim.commands.related_tests').related_tests()
95+
end,
96+
},
9297
renderDiagnostic = {
9398
impl = function(args)
9499
local subcmd = args[1] or 'cycle'
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
local ra = require('rustaceanvim.rust_analyzer')
2+
local rts = require('rustaceanvim.treesitter')
3+
4+
local M = {}
5+
6+
---@class rustaceanvim.RATestInfo
7+
---@field runnable rustaceanvim.RARunnable
8+
9+
---@param offset_encoding string
10+
---@return lsp.TextDocumentPositionParams
11+
local function get_params(offset_encoding)
12+
local position_params = vim.lsp.util.make_position_params(0, offset_encoding)
13+
14+
if rts.has_tree_sitter_rust() then
15+
local fn_identifier_position = rts.find_fn_identifier_position()
16+
if fn_identifier_position ~= nil then
17+
position_params.position = fn_identifier_position
18+
end
19+
end
20+
21+
return position_params
22+
end
23+
24+
---@param offset_encoding string
25+
---@return lsp.Handler See |lsp-handler|
26+
local function mk_handler(offset_encoding)
27+
---@param tests? rustaceanvim.RATestInfo[]
28+
return function(_, tests)
29+
if tests == nil then
30+
-- this can be nil when LSP has not finished loading
31+
return
32+
end
33+
34+
local test_locations = {}
35+
for _, test in ipairs(tests) do
36+
table.insert(test_locations, test.runnable.location)
37+
end
38+
39+
if #test_locations == 0 then
40+
return
41+
elseif #test_locations == 1 then
42+
vim.lsp.util.show_document(test_locations[1], offset_encoding, { reuse_win = true, focus = true })
43+
return
44+
else
45+
local quickfix_entries = vim.lsp.util.locations_to_items(test_locations, offset_encoding)
46+
vim.fn.setqflist({}, ' ', { title = 'related tests', items = quickfix_entries })
47+
vim.cmd([[ botright copen ]])
48+
end
49+
end
50+
end
51+
52+
---@return nil
53+
function M.related_tests()
54+
local clients = ra.get_active_rustaceanvim_clients(0)
55+
if #clients == 0 then
56+
return
57+
end
58+
59+
local offset_encoding = clients[1].offset_encoding or 'utf-8'
60+
61+
local params = get_params(offset_encoding)
62+
ra.buf_request(0, 'rust-analyzer/relatedTests', params, mk_handler(offset_encoding))
63+
end
64+
65+
return M

lua/rustaceanvim/commands/rustc_unpretty.lua

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local M = {}
22

33
local cargo = require('rustaceanvim.cargo')
44
local ui = require('rustaceanvim.ui')
5+
local rts = require('rustaceanvim.treesitter')
56
local api = vim.api
67
local ts = vim.treesitter
78

@@ -93,15 +94,9 @@ local function handler(sc)
9394
vim.api.nvim_buf_set_lines(latest_buf_id, 0, 0, false, lines)
9495
end
9596

96-
---@return boolean
97-
local function has_tree_sitter_rust()
98-
return #api.nvim_get_runtime_file('parser/rust.so', true) > 0
99-
or require('rustaceanvim.shell').is_windows() and #api.nvim_get_runtime_file('parser/rust.dll', true) > 0
100-
end
101-
10297
---@param level rustaceanvim.rustcir.level
10398
function M.rustc_unpretty(level)
104-
if not has_tree_sitter_rust() then
99+
if not rts.has_tree_sitter_rust() then
105100
vim.notify("a treesitter parser for Rust is required for 'rustc unpretty'", vim.log.levels.ERROR)
106101
return
107102
end

lua/rustaceanvim/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
--- 'testables {args[]}?' - Run tests
4343
--- ':RustLsp!' means run the last testable (ignores any args).
4444
--- `args[]` allows you to override the executable's arguments.
45+
--- 'relatedTests' - Open the tests rust-analyzer associates with the symbol under the cursor.
4546
--- 'expandMacro' - Expand macros recursively.
4647
--- 'moveItem {up|down}' - Move items up or down.
4748
--- 'codeAction' - Sometimes, rust-analyzer groups code actions by category,

lua/rustaceanvim/treesitter.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
local M = {}
2+
3+
local api = vim.api
4+
5+
---@return boolean
6+
function M.has_tree_sitter_rust()
7+
return #api.nvim_get_runtime_file('parser/rust.so', true) > 0
8+
or require('rustaceanvim.shell').is_windows() and #api.nvim_get_runtime_file('parser/rust.dll', true) > 0
9+
end
10+
11+
-- The `rust-analyzer/relatedTests` resolves using the identifier under the cursor,
12+
-- but it is useful to resolve related tests while having the cursor in the function body.
13+
-- This function will recursively search for the parent fn and then descend to find the child
14+
-- identifier, so that the `relatedTest` method works even if the cursor is inside the
15+
-- function.
16+
---@return lsp.Position|nil
17+
function M.find_fn_identifier_position()
18+
local cursor = vim.api.nvim_win_get_cursor(0)
19+
local start_pos = { math.max(cursor[1] - 1, 0), cursor[2] }
20+
21+
local node = vim.treesitter.get_node { pos = start_pos }
22+
while node do
23+
if node:type() == 'function_item' then
24+
for child in node:iter_children() do
25+
if child:type() == 'identifier' then
26+
local start_row, start_col = child:start()
27+
return { line = start_row, character = start_col }
28+
end
29+
end
30+
end
31+
node = node:parent()
32+
end
33+
return nil
34+
end
35+
36+
return M

0 commit comments

Comments
 (0)