-
-
Notifications
You must be signed in to change notification settings - Fork 75
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
perf: optimize target_arch switching #548
Changes from 8 commits
b9601a2
dd8f57c
f63ac83
8a7b846
5d93ea2
f75ce6e
d18d5ef
1ea2cc8
350e663
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,9 +6,7 @@ local rust_analyzer = require('rustaceanvim.rust_analyzer') | |
local server_status = require('rustaceanvim.server_status') | ||
local cargo = require('rustaceanvim.cargo') | ||
local os = require('rustaceanvim.os') | ||
|
||
---Local rustc targets cache | ||
local rustc_targets_cache = nil | ||
local rustc = require('rustaceanvim.rustc') | ||
|
||
local function override_apply_text_edits() | ||
local old_func = vim.lsp.util.apply_text_edits | ||
|
@@ -96,42 +94,14 @@ local function configure_file_watcher(server_cfg) | |
end | ||
end | ||
|
||
---Handles retrieving rustc target architectures and running the passed in callback | ||
---to perform certain actions using the retrieved targets. | ||
---@param callback fun(targets: string[]) | ||
local function with_rustc_target_architectures(callback) | ||
if rustc_targets_cache then | ||
return callback(rustc_targets_cache) | ||
end | ||
vim.system( | ||
{ 'rustc', '--print', 'target-list' }, | ||
{ text = true }, | ||
---@param result vim.SystemCompleted | ||
function(result) | ||
if result.code ~= 0 then | ||
error('Failed to retrieve rustc targets: ' .. result.stderr) | ||
end | ||
rustc_targets_cache = vim.iter(result.stdout:gmatch('[^\r\n]+')):fold( | ||
{}, | ||
---@param acc table<string, boolean> | ||
---@param target string | ||
function(acc, target) | ||
acc[target] = true | ||
return acc | ||
end | ||
) | ||
return callback(rustc_targets_cache) | ||
end | ||
) | ||
end | ||
|
||
---LSP restart internal implementations | ||
---@param bufnr? number | ||
---@param bufnr? number The buffer number, defaults to the current buffer | ||
---@param exclude_rustc_target? string Cargo target triple (e.g., 'x86_64-unknown-linux-gnu') to filter rust-analyzer clients | ||
---@param callback? fun(client: vim.lsp.Client) Optional callback to run for each client before restarting. | ||
---@return number|nil client_id | ||
local function restart(bufnr, callback) | ||
local function restart(bufnr, exclude_rustc_target, callback) | ||
bufnr = bufnr or vim.api.nvim_get_current_buf() | ||
local clients = M.stop(bufnr) | ||
local clients = M.stop(bufnr, exclude_rustc_target) | ||
local timer, _, _ = vim.uv.new_timer() | ||
if not timer then | ||
vim.notify('Failed to init timer for LSP client restart.', vim.log.levels.ERROR) | ||
|
@@ -285,10 +255,14 @@ end | |
|
||
---Stop the LSP client. | ||
---@param bufnr? number The buffer number, defaults to the current buffer | ||
---@param exclude_rustc_target? string Cargo target triple (e.g., 'x86_64-unknown-linux-gnu') to filter rust-analyzer clients | ||
---@return vim.lsp.Client[] clients A list of clients that will be stopped | ||
M.stop = function(bufnr) | ||
M.stop = function(bufnr, exclude_rustc_target) | ||
bufnr = bufnr or vim.api.nvim_get_current_buf() | ||
local clients = rust_analyzer.get_active_rustaceanvim_clients(bufnr) | ||
local clients = rust_analyzer.get_active_rustaceanvim_clients( | ||
bufnr, | ||
{ exclude_rustc_target = exclude_rustc_target or DEFAULT_RUSTC_TARGET } | ||
) | ||
vim.lsp.stop_client(clients) | ||
if type(clients) == 'table' then | ||
---@cast clients vim.lsp.Client[] | ||
|
@@ -322,30 +296,18 @@ end | |
|
||
---Updates the target architecture setting for the LSP client associated with the given buffer. | ||
---@param bufnr? number The buffer number, defaults to the current buffer | ||
---@param target? string The target architecture. Defaults to nil(the current buffer's target if not provided). | ||
M.set_target_arch = function(bufnr, target) | ||
---@param exclude_rustc_target? string Cargo target triple (e.g., 'x86_64-unknown-linux-gnu') to filter rust-analyzer clients | ||
M.set_target_arch = function(bufnr, exclude_rustc_target) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: Here (just not in |
||
---@param client vim.lsp.Client | ||
restart(bufnr, function(client) | ||
-- Get current user's rust-analyzer target | ||
local current_target = vim.tbl_get(client, 'config', 'settings', 'rust-analyzer', 'cargo', 'target') | ||
|
||
if not target then | ||
if not current_target then | ||
vim.notify('Using default OS target architecture.', vim.log.levels.INFO) | ||
else | ||
vim.notify('Target architecture is already set to the default OS target.', vim.log.levels.INFO) | ||
end | ||
return | ||
end | ||
|
||
with_rustc_target_architectures(function(rustc_targets) | ||
if target == nil or rustc_targets[target] then | ||
client.settings['rust-analyzer'].cargo.target = target | ||
restart(bufnr, exclude_rustc_target, function(client) | ||
rustc.with_rustc_target_architectures(function(rustc_targets) | ||
if rustc_targets[exclude_rustc_target] then | ||
client.settings['rust-analyzer'].cargo.target = exclude_rustc_target | ||
client.notify('workspace/didChangeConfiguration', { settings = client.config.settings }) | ||
vim.notify('Target architecture updated successfully to: ' .. target, vim.log.levels.INFO) | ||
vim.notify('Target architecture updated successfully to: ' .. exclude_rustc_target, vim.log.levels.INFO) | ||
return | ||
else | ||
vim.notify('Invalid target architecture provided: ' .. tostring(target), vim.log.levels.ERROR) | ||
vim.notify('Invalid target architecture provided: ' .. tostring(exclude_rustc_target), vim.log.levels.ERROR) | ||
return | ||
end | ||
end) | ||
|
@@ -354,10 +316,9 @@ end | |
|
||
---Restart the LSP client. | ||
---Fails silently if the buffer's filetype is not one of the filetypes specified in the config. | ||
---@param bufnr? number The buffer number (optional), defaults to the current buffer | ||
mrcjkb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
---@return number|nil client_id The LSP client ID after restart | ||
M.restart = function(bufnr) | ||
M.restart(bufnr) | ||
M.restart = function() | ||
return restart() | ||
end | ||
|
||
---@enum RustAnalyzerCmd | ||
|
@@ -372,7 +333,6 @@ local RustAnalyzerCmd = { | |
local function rust_analyzer_cmd(opts) | ||
local fargs = opts.fargs | ||
local cmd = fargs[1] | ||
local arch = fargs[2] | ||
---@cast cmd RustAnalyzerCmd | ||
if cmd == RustAnalyzerCmd.start then | ||
M.start() | ||
|
@@ -383,7 +343,8 @@ local function rust_analyzer_cmd(opts) | |
elseif cmd == RustAnalyzerCmd.reload_settings then | ||
M.reload_settings() | ||
elseif cmd == RustAnalyzerCmd.target then | ||
M.set_target_arch(nil, arch) | ||
local target_arch = fargs[2] | ||
M.set_target_arch(target_arch) | ||
end | ||
end | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,18 +5,46 @@ local os = require('rustaceanvim.os') | |
---@class rustaceanvim.rust-analyzer.ClientAdapter | ||
local M = {} | ||
|
||
M.load_os_rustc_target = function() | ||
mrcjkb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
vim.system({ 'rustc', '-Vv' }, { text = true }, function(result) | ||
if result.code == 0 then | ||
for line in result.stdout:gmatch('[^\r\n]+') do | ||
local host = line:match('^host:%s*(.+)$') | ||
if host then | ||
M.os_rustc_target = host | ||
break | ||
end | ||
end | ||
end | ||
end) | ||
end | ||
|
||
---@class rustaceanvim.lsp.get_clients.Filter: vim.lsp.get_clients.Filter | ||
---@field exclude_rustc_target? string Cargo target triple (e.g., 'x86_64-unknown-linux-gnu') to filter rust-analyzer clients | ||
|
||
---@param bufnr number | nil 0 for the current buffer, `nil` for no buffer filter | ||
---@param filter? vim.lsp.get_clients.Filter | ||
---@param filter? rustaceanvim.lsp.get_clients.Filter | ||
---@return vim.lsp.Client[] | ||
M.get_active_rustaceanvim_clients = function(bufnr, filter) | ||
---@type vim.lsp.get_clients.Filter | ||
filter = vim.tbl_deep_extend('force', filter or {}, { | ||
local client_filter = vim.tbl_deep_extend('force', filter or {}, { | ||
name = 'rust-analyzer', | ||
}) | ||
if bufnr then | ||
filter.bufnr = bufnr | ||
client_filter.bufnr = bufnr | ||
end | ||
local clients = vim.lsp.get_clients(client_filter) | ||
if filter and filter.exclude_rustc_target then | ||
clients = vim.tbl_filter(function(client) | ||
local cargo_target = vim.tbl_get(client, 'config', 'settings', 'rust-analyzer', 'cargo', 'target') | ||
if filter.exclude_rustc_target == DEFAULT_RUSTC_TARGET and cargo_target == nil then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: tip: If you have Nix installed, I recommend you enter a nix devShell ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks! done |
||
return false | ||
end | ||
return cargo_target ~= filter.exclude_rustc_target | ||
end, clients) | ||
end | ||
return vim.lsp.get_clients(filter) | ||
|
||
return clients | ||
end | ||
|
||
---@param method string LSP method name | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
local M = {} | ||
|
||
--- Default target value for rustc when no specific target is provided. | ||
--- Used as a fallback to let rustc determine the appropriate target based on the OS. | ||
DEFAULT_RUSTC_TARGET = 'OS' | ||
|
||
---Local rustc targets cache | ||
local rustc_targets_cache = nil | ||
|
||
---Handles retrieving rustc target architectures and running the passed in callback | ||
---to perform certain actions using the retrieved targets. | ||
---@param callback fun(targets: string[]) | ||
M.with_rustc_target_architectures = function(callback) | ||
if rustc_targets_cache then | ||
return callback(rustc_targets_cache) | ||
end | ||
vim.system( | ||
{ 'rustc', '--print', 'target-list' }, | ||
{ text = true }, | ||
---@param result vim.SystemCompleted | ||
function(result) | ||
if result.code ~= 0 then | ||
error('Failed to retrieve rustc targets: ' .. result.stderr) | ||
end | ||
rustc_targets_cache = vim.iter(result.stdout:gmatch('[^\r\n]+')):fold( | ||
{}, | ||
---@param acc table<string, boolean> | ||
---@param target string | ||
function(acc, target) | ||
acc[target] = true | ||
return acc | ||
end | ||
) | ||
return callback(rustc_targets_cache) | ||
end | ||
) | ||
end | ||
|
||
return M |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: The
stop
function shouldn't set a rustc target by default, otherwise it will always try to filter, even when we don't need it to.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah make sense. thanks