Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auto-detect the rustc edition #463

Merged
merged 3 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Neotest: One test failure caused all succeeding tests to be marked as failed
when using cargo-nextest 0.9.7 [[#460](https://github.com/mrcjkb/rustaceanvim/issues/460)].
- Neotest: Disable ansi colour coding in output to ensure output can be parsed.
- `Rustc unpretty`: Support Windows.
- Auto-detect the `rustc` edition.
This deprecates the `vim.g.rustaceanvim.tools.rustc.edition` option
in favour of `vim.g.rustaceanvim.tools.rustc.default_edition`.

## [5.1.0] - 2024-07-27

Expand Down
7 changes: 4 additions & 3 deletions doc/rustaceanvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,10 @@ rustaceanvim.crate-graph.Opts *rustaceanvim.crate-graph.Opts*
rustaceanvim.rustc.Opts *rustaceanvim.rustc.Opts*

Fields: ~
{edition} (string)
The edition to use. See https://rustc-dev-guide.rust-lang.org/guides/editions.html.
Default '2021'.
{default_edition?} (string)
The default edition to use if it cannot be auto-detected.
See https://rustc-dev-guide.rust-lang.org/guides/editions.html.
Default '2021'.


rustaceanvim.lsp.ClientOpts *rustaceanvim.lsp.ClientOpts*
Expand Down
91 changes: 57 additions & 34 deletions lua/rustaceanvim/cargo.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,48 +44,71 @@ function cargo.get_config_root_dir(config, file_name)
end
end

---The default implementation used for `vim.g.rustaceanvim.server.root_dir`
---@param file_name string
---@return string | nil root_dir
function cargo.get_root_dir(file_name)
local path = file_name:find('%.rs$') and vim.fs.dirname(file_name) or file_name
if not path then
return nil
end
---@param path string The directory to search upward from
---@return string? cargo_crate_dir
---@return table? cargo_metadata
local function get_cargo_metadata(path)
---@diagnostic disable-next-line: missing-fields
local cargo_crate_dir = vim.fs.dirname(vim.fs.find({ 'Cargo.toml' }, {
upward = true,
path = path,
})[1])
---@type string | nil
local cargo_workspace_dir = nil
if vim.fn.executable('cargo') == 1 then
local cmd = { 'cargo', 'metadata', '--no-deps', '--format-version', '1' }
if cargo_crate_dir ~= nil then
cmd[#cmd + 1] = '--manifest-path'
cmd[#cmd + 1] = vim.fs.joinpath(cargo_crate_dir, 'Cargo.toml')
end
local cargo_metadata = ''
local cm = vim.fn.jobstart(cmd, {
on_stdout = function(_, d, _)
cargo_metadata = table.concat(d, '\n')
end,
stdout_buffered = true,
if vim.fn.executable('cargo') ~= 1 then
return cargo_crate_dir
end
local cmd = { 'cargo', 'metadata', '--no-deps', '--format-version', '1' }
if cargo_crate_dir ~= nil then
cmd[#cmd + 1] = '--manifest-path'
cmd[#cmd + 1] = vim.fs.joinpath(cargo_crate_dir, 'Cargo.toml')
end
local sc = vim
.system(cmd, {
cwd = vim.uv.fs_stat(path) and path or cargo_crate_dir or vim.fn.getcwd(),
})
if cm > 0 then
cm = vim.fn.jobwait({ cm })[1]
else
cm = -1
end
if cm == 0 then
local ok, cargo_metadata_json = pcall(vim.fn.json_decode, cargo_metadata)
if ok and cargo_metadata_json then
cargo_workspace_dir = cargo_metadata_json['workspace_root']
end
end
:wait()
if sc.code ~= 0 then
return cargo_crate_dir
end
local ok, cargo_metadata_json = pcall(vim.fn.json_decode, sc.stdout)
if ok and cargo_metadata_json then
return cargo_crate_dir, cargo_metadata_json
end
return cargo_crate_dir
end

---@param buf_name? string
---@return string edition
function cargo.get_rustc_edition(buf_name)
local config = require('rustaceanvim.config.internal')
---@diagnostic disable-next-line: undefined-field
if config.tools.rustc.edition then
vim.deprecate('vim.g.rustaceanvim.config.tools.edition', 'default_edition', '6.0.0', 'rustaceanvim')
---@diagnostic disable-next-line: undefined-field
return config.tools.rustc.edition
end
buf_name = buf_name or vim.api.nvim_buf_get_name(0)
local path = vim.fs.dirname(buf_name)
local _, cargo_metadata = get_cargo_metadata(path)
local default_edition = config.tools.rustc.default_edition
if not cargo_metadata then
return default_edition
end
local package = vim.iter(cargo_metadata.packages or {}):find(function(pkg)
return type(pkg.edition) == 'string'
end)
return package and package.edition or default_edition
end

---The default implementation used for `vim.g.rustaceanvim.server.root_dir`
---@param file_name string
---@return string | nil root_dir
function cargo.get_root_dir(file_name)
local path = file_name:find('%.rs$') and vim.fs.dirname(file_name) or file_name
if not path then
return nil
end
return cargo_workspace_dir
local cargo_crate_dir, cargo_metadata = get_cargo_metadata(path)
return cargo_metadata and cargo_metadata.workspace_root
or cargo_crate_dir
---@diagnostic disable-next-line: missing-fields
or vim.fs.dirname(vim.fs.find({ 'rust-project.json' }, {
Expand Down
12 changes: 9 additions & 3 deletions lua/rustaceanvim/commands/rustc_unpretty.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local M = {}

local config = require('rustaceanvim.config.internal')
local cargo = require('rustaceanvim.cargo')
local ui = require('rustaceanvim.ui')
local api = vim.api
local ts = vim.treesitter
Expand Down Expand Up @@ -92,9 +92,15 @@ local function handler(sc)
vim.api.nvim_buf_set_lines(latest_buf_id, 0, 0, false, lines)
end

---@return boolean
local function has_tree_sitter_rust()
return #api.nvim_get_runtime_file('parser/rust.so', true) > 0
or require('rustaceanvim.shell').is_windows() and #api.nvim_get_runtime_file('parser/rust.dll', true) > 0
end

---@param level rustaceanvim.rustcir.level
function M.rustc_unpretty(level)
if #api.nvim_get_runtime_file('parser/rust.so', true) == 0 then
if not has_tree_sitter_rust() then
vim.notify("a treesitter parser for Rust is required for 'rustc unpretty'", vim.log.levels.ERROR)
return
end
Expand Down Expand Up @@ -133,7 +139,7 @@ function M.rustc_unpretty(level)
'--crate-type',
'lib',
'--edition',
config.tools.rustc.edition,
cargo.get_rustc_edition(),
'-Z',
'unstable-options',
'-Z',
Expand Down
2 changes: 1 addition & 1 deletion lua/rustaceanvim/config/check.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function M.validate(cfg)
end
local rustc = tools.rustc
ok, err = validate('tools.rustc', {
edition = { rustc.edition, 'string' },
default_edition = { rustc.default_edition, 'string' },
})
if not ok then
return false, err
Expand Down
5 changes: 3 additions & 2 deletions lua/rustaceanvim/config/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,10 @@ vim.g.rustaceanvim = vim.g.rustaceanvim

---@class rustaceanvim.rustc.Opts
---
---The edition to use. See https://rustc-dev-guide.rust-lang.org/guides/editions.html.
---The default edition to use if it cannot be auto-detected.
---See https://rustc-dev-guide.rust-lang.org/guides/editions.html.
---Default '2021'.
---@field edition string
---@field default_edition? string

---@class rustaceanvim.lsp.ClientOpts
---
Expand Down
2 changes: 1 addition & 1 deletion lua/rustaceanvim/config/internal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ local RustaceanDefaultConfig = {
---@class rustaceanvim.rustc.Config
rustc = {
---@type string
edition = '2021',
default_edition = '2021',
},
},

Expand Down
Loading