diff --git a/CHANGELOG.md b/CHANGELOG.md index b78648dc..b58c6b3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [3.1.0] - 2023-10-28 ### Added +- `:RustLsp explainErrors` command, uses `rustc --explain` on error diagnostics with + an error code. - `:RustLsp rebuildProcMacros` command. ## [3.0.4] - 2023-10-25 diff --git a/README.md b/README.md index a3d21b5b..31d1d1fc 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,25 @@ for more configuration options. ``` +
+ + Explain errors + + + Display a hover window with explanations from the [rust error codes index](https://doc.rust-lang.org/error_codes/error-index.html) + over error diagnostics (if they have an error code). + + ```vimscript + :RustLsp explainError + ``` + ```lua + vim.cmd.RustLsp('explainError') + ``` + +![](https://github.com/mrcjkb/rustaceanvim/assets/12857160/bac9b31c-22ca-40c4-bfd3-b8c5ba4cc49a) + +
+
Open Cargo.toml diff --git a/lua/rustaceanvim/commands/explain_error.lua b/lua/rustaceanvim/commands/explain_error.lua new file mode 100644 index 00000000..d1e9626f --- /dev/null +++ b/lua/rustaceanvim/commands/explain_error.lua @@ -0,0 +1,70 @@ +local M = {} + +local rustc = 'rustc' + +function M.explain_error() + if vim.fn.executable(rustc) ~= 1 then + vim.notify('rustc is needed to explain errors.', vim.log.levels.ERROR) + return + end + + local diagnostics = vim.tbl_filter(function(diagnostic) + return diagnostic.code ~= nil and diagnostic.source == 'rustc' + end, vim.diagnostic.get(0, {})) + if #diagnostics == 0 then + vim.notify('No explainnable errors found.', vim.log.levels.INFO) + return + end + local win_id = vim.api.nvim_get_current_win() + local opts = { + cursor_position = vim.api.nvim_win_get_cursor(win_id), + severity = vim.diagnostic.severity.ERROR, + wrap = true, + } + local found = false + local diagnostic + local pos_map = {} + local pos_id = 1 + repeat + diagnostic = vim.diagnostic.get_next(opts) + pos_map[pos_id] = diagnostic + if diagnostic == nil then + break + end + found = diagnostic.code ~= nil and diagnostic.source == 'rustc' + local pos = { diagnostic.lnum, diagnostic.col } + pos_id = pos[1] + pos[2] + opts.cursor_position = pos + local searched_all = pos_map[pos_id] ~= nil + until diagnostic == nil or found or searched_all + if not found then + return + end + + ---@param sc vim.SystemCompleted + local function handler(sc) + if sc.code ~= 0 or not sc.stdout then + vim.notify('Error calling rustc --explain' .. (sc.stderr and ': ' .. sc.stderr or ''), vim.log.levels.ERROR) + return + end + local output = sc.stdout:gsub('```', '```rust', 1) + local markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(output, {}) + vim.schedule(function() + vim.lsp.util.open_floating_preview(markdown_lines, 'markdown', { + focus = false, + focusable = true, + focus_id = 'rustc-explain-error', + close_events = { 'CursorMoved', 'BufHidden', 'InsertCharPre' }, + }) + end) + end + + -- Save position in the window's jumplist + vim.cmd("normal! m'") + vim.api.nvim_win_set_cursor(win_id, { diagnostic.lnum + 1, diagnostic.col }) + -- Open folds under the cursor + vim.cmd('normal! zv') + vim.system({ rustc, '--explain', diagnostic.code }, nil, vim.schedule_wrap(handler)) +end + +return M.explain_error diff --git a/lua/rustaceanvim/commands/init.lua b/lua/rustaceanvim/commands/init.lua index 6b370b15..fbfd3392 100644 --- a/lua/rustaceanvim/commands/init.lua +++ b/lua/rustaceanvim/commands/init.lua @@ -27,6 +27,9 @@ local command_tbl = { expandMacro = function(_) require('rustaceanvim.commands.expand_macro')() end, + explainError = function(_) + require('rustaceanvim.commands.explain_error')() + end, rebuildProcMacros = function() require('rustaceanvim.commands.rebuild_proc_macros')() end, diff --git a/lua/rustaceanvim/health.lua b/lua/rustaceanvim/health.lua index 9f5db1cf..de19e2cf 100644 --- a/lua/rustaceanvim/health.lua +++ b/lua/rustaceanvim/health.lua @@ -81,6 +81,20 @@ local external_dependencies = { Not required in standalone files. ]], }, + { + name = 'rustc', + get_binaries = function() + return { 'rustc' } + end, + optional = function() + return true + end, + url = '[rustc](https://doc.rust-lang.org/rustc/what-is-rustc.html)', + info = [[ + The Rust compiler. + Called by `:RustLsp explainError`. + ]], + }, { name = config.dap.adapter.command, get_binaries = function() diff --git a/lua/rustaceanvim/hover_actions.lua b/lua/rustaceanvim/hover_actions.lua index 9338a708..db7a5488 100644 --- a/lua/rustaceanvim/hover_actions.lua +++ b/lua/rustaceanvim/hover_actions.lua @@ -83,7 +83,7 @@ function M.handler(_, result, ctx) 'markdown', vim.tbl_extend('keep', config.tools.hover_actions, { focusable = true, - focus_id = 'rust-tools-hover-actions', + focus_id = 'rust-analyzer-hover-actions', close_events = { 'CursorMoved', 'BufHidden', 'InsertCharPre' }, }) )