@@ -3,6 +3,84 @@ local os = require('rustaceanvim.os')
33
44local cargo = {}
55
6+ --- @param path string The directory to search upward from
7+ --- @param callback ? fun ( cargo_crate_dir : string ?, cargo_metadata : table ?) If ` nil` , this function runs synchronously
8+ --- @return string ? cargo_crate_dir (if ` callback ~= nil` and successful )
9+ --- @return table ? cargo_metadata (if ` callback ~= nil` and successful )
10+ local function get_cargo_metadata (path , callback )
11+ --- @diagnostic disable-next-line : missing-fields
12+ local cargo_crate_dir = vim .fs .dirname (vim .fs .find ({ ' Cargo.toml' }, {
13+ upward = true ,
14+ path = path ,
15+ })[1 ])
16+ if vim .fn .executable (' cargo' ) ~= 1 then
17+ return callback and callback (cargo_crate_dir ) or cargo_crate_dir
18+ end
19+ local cmd = { ' cargo' , ' metadata' , ' --no-deps' , ' --format-version' , ' 1' }
20+ if cargo_crate_dir ~= nil then
21+ cmd [# cmd + 1 ] = ' --manifest-path'
22+ cmd [# cmd + 1 ] = vim .fs .joinpath (cargo_crate_dir , ' Cargo.toml' )
23+ end
24+
25+ --- @param sc vim.SystemCompleted
26+ local function on_exit (sc )
27+ if sc .code ~= 0 then
28+ return callback and callback (cargo_crate_dir ) or cargo_crate_dir
29+ end
30+ local ok , cargo_metadata_json = pcall (vim .fn .json_decode , sc .stdout )
31+ if ok and cargo_metadata_json then
32+ return callback and callback (cargo_crate_dir , cargo_metadata_json ) or cargo_crate_dir , cargo_metadata_json
33+ end
34+ return callback and callback (cargo_crate_dir ) or cargo_crate_dir
35+ end
36+
37+ if callback then
38+ vim .uv .fs_stat (path , function (_ , stat )
39+ vim .system (cmd , {
40+ cwd = stat and path or cargo_crate_dir or vim .fn .getcwd (),
41+ }, on_exit )
42+ end )
43+ else
44+ local sc = vim
45+ .system (cmd , {
46+ cwd = vim .uv .fs_stat (path ) and path or cargo_crate_dir or vim .fn .getcwd (),
47+ })
48+ :wait ()
49+ return on_exit (sc )
50+ end
51+ end
52+
53+ --- The default implementation used for `vim.g.rustaceanvim.server.root_dir`
54+ --- @param file_name string
55+ --- @param callback ? fun ( root_dir : string | nil ) If ` nil` , this function runs synchronously
56+ --- @return string | nil root_dir (if ` callback ~= nil` and successful )
57+ local function default_get_root_dir (file_name , callback )
58+ local path = file_name :find (' %.rs$' ) and vim .fs .dirname (file_name ) or file_name
59+ if not path then
60+ return nil
61+ end
62+
63+ --- @param cargo_crate_dir ? string
64+ --- @param cargo_metadata ? table
65+ --- @return string | nil root_dir
66+ local function root_dir (cargo_crate_dir , cargo_metadata )
67+ return cargo_metadata and cargo_metadata .workspace_root
68+ or cargo_crate_dir
69+ or vim .fs .dirname (vim .fs .find ({ ' rust-project.json' }, {
70+ upward = true ,
71+ path = path ,
72+ })[1 ])
73+ end
74+ if callback then
75+ get_cargo_metadata (path , function (cargo_crate_dir , cargo_metadata )
76+ callback (root_dir (cargo_crate_dir , cargo_metadata ))
77+ end )
78+ else
79+ local cargo_crate_dir , cargo_metadata = get_cargo_metadata (path )
80+ return root_dir (cargo_crate_dir , cargo_metadata )
81+ end
82+ end
83+
684--- Checks if there is an active client for file_name and returns its root directory if found.
785--- @param file_name string
886--- @return string | nil root_dir The root directory of the active client for file_name (if there is one )
29107--- client root is found, returns the result of evaluating `config.root_dir`.
30108--- @param config rustaceanvim.lsp.ClientConfig
31109--- @param file_name string
110+ --- @param callback ? fun ( root_dir : string ?) If ` nil` , this function runs synchronously
32111--- @return string | nil root_dir
33- function cargo .get_config_root_dir (config , file_name )
112+ function cargo .get_config_root_dir (config , file_name , callback )
34113 local reuse_active = get_mb_active_client_root (file_name )
35114 if reuse_active then
36115 return reuse_active
37116 end
38-
39- local config_root_dir = config .root_dir
40- if type (config_root_dir ) == ' function' then
41- return config_root_dir (file_name , cargo .get_root_dir )
117+ if type (config .root_dir ) == ' function' then
118+ local root_dir = config .root_dir (file_name , default_get_root_dir )
119+ return callback and callback (root_dir ) or root_dir
120+ elseif type (config .root_dir ) == ' string' then
121+ local root_dir = config .root_dir
122+ --- @cast root_dir string
123+ return callback and callback (root_dir ) or root_dir
42124 else
43- return config_root_dir
44- end
45- end
46-
47- --- @param path string The directory to search upward from
48- --- @return string ? cargo_crate_dir
49- --- @return table ? cargo_metadata
50- local function get_cargo_metadata (path )
51- --- @diagnostic disable-next-line : missing-fields
52- local cargo_crate_dir = vim .fs .dirname (vim .fs .find ({ ' Cargo.toml' }, {
53- upward = true ,
54- path = path ,
55- })[1 ])
56- if vim .fn .executable (' cargo' ) ~= 1 then
57- return cargo_crate_dir
58- end
59- local cmd = { ' cargo' , ' metadata' , ' --no-deps' , ' --format-version' , ' 1' }
60- if cargo_crate_dir ~= nil then
61- cmd [# cmd + 1 ] = ' --manifest-path'
62- cmd [# cmd + 1 ] = vim .fs .joinpath (cargo_crate_dir , ' Cargo.toml' )
125+ callback = callback and vim .schedule_wrap (callback )
126+ return default_get_root_dir (file_name , callback )
63127 end
64- local sc = vim
65- .system (cmd , {
66- cwd = vim .uv .fs_stat (path ) and path or cargo_crate_dir or vim .fn .getcwd (),
67- })
68- :wait ()
69- if sc .code ~= 0 then
70- return cargo_crate_dir
71- end
72- local ok , cargo_metadata_json = pcall (vim .fn .json_decode , sc .stdout )
73- if ok and cargo_metadata_json then
74- return cargo_crate_dir , cargo_metadata_json
75- end
76- return cargo_crate_dir
77128end
78129
79130--- @param buf_name ? string
@@ -99,22 +150,4 @@ function cargo.get_rustc_edition(buf_name)
99150 return package and package .edition or default_edition
100151end
101152
102- --- The default implementation used for `vim.g.rustaceanvim.server.root_dir`
103- --- @param file_name string
104- --- @return string | nil root_dir
105- function cargo .get_root_dir (file_name )
106- local path = file_name :find (' %.rs$' ) and vim .fs .dirname (file_name ) or file_name
107- if not path then
108- return nil
109- end
110- local cargo_crate_dir , cargo_metadata = get_cargo_metadata (path )
111- return cargo_metadata and cargo_metadata .workspace_root
112- or cargo_crate_dir
113- --- @diagnostic disable-next-line : missing-fields
114- or vim .fs .dirname (vim .fs .find ({ ' rust-project.json' }, {
115- upward = true ,
116- path = path ,
117- })[1 ])
118- end
119-
120153return cargo
0 commit comments