diff options
| author | xs <xs@xs.local> | 2026-11-03 19:49:53 +0800 |
|---|---|---|
| committer | xs <xs@xs.local> | 2026-11-05 10:45:32 +0800 |
| commit | be7440b5c365303865ebf7a3c437039e96c170c1 (patch) | |
| tree | 6b799c10f38d9825a5d2e40c94532b209daa4bc5 | |
| parent | 6eefc4d7422e8efc5410709f28ea5b710ee6a7e0 (diff) | |
vimrc: rust-analyzer gd/completion on standalone .rs files
Root rust-analyzer at the owning crate only if the file is one of its
targets; otherwise list the file in detachedFiles (init options for the
first file, workspace config for later ones) so std resolves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | core/vimrc | 50 |
1 files changed, 49 insertions, 1 deletions
| @@ -153,20 +153,68 @@ endif | |||
| 153 | let g:gitgutter_sign_column_always = 0 | 153 | let g:gitgutter_sign_column_always = 0 |
| 154 | 154 | ||
| 155 | 155 | ||
| 156 | " rust-analyzer root: nearest Cargo.toml dir only if this file is a target of that crate | ||
| 157 | " (src/ examples/ tests/ benches/ build.rs, or its path appears in the manifest); else the | ||
| 158 | " file's own dir, so rust-analyzer loads it standalone (std resolves) instead of detached-in-a-foreign-project | ||
| 159 | " RustCrate(): crate dir if this buffer is a target of its nearest Cargo.toml, else '' | ||
| 160 | function! RustCrate() abort | ||
| 161 | let l:p = expand('%:p') | ||
| 162 | let l:d = lsp#utils#find_nearest_parent_file_directory(l:p, 'Cargo.toml') | ||
| 163 | if !empty(l:d) | ||
| 164 | let l:d = substitute(fnamemodify(l:d, ':p'), '/$', '', '') | ||
| 165 | let l:rel = stridx(l:p, l:d . '/') == 0 ? l:p[len(l:d) + 1:] : '' | ||
| 166 | let l:target = l:rel =~# '^\(src\|examples\|tests\|benches\)/' || l:rel ==# 'build.rs' | ||
| 167 | if !l:target && !empty(l:rel) | ||
| 168 | let l:target = stridx(join(readfile(l:d . '/Cargo.toml'), "\n"), '"' . l:rel . '"') >= 0 | ||
| 169 | endif | ||
| 170 | if l:target | ||
| 171 | return l:d | ||
| 172 | endif | ||
| 173 | endif | ||
| 174 | return '' | ||
| 175 | endfunction | ||
| 176 | function! RustRoot() abort | ||
| 177 | let l:c = RustCrate() | ||
| 178 | return empty(l:c) ? expand('%:p:h') : l:c | ||
| 179 | endfunction | ||
| 180 | " Standalone .rs files (no owning crate) must be listed in rust-analyzer's detachedFiles, | ||
| 181 | " else it loads nothing for them (no gd/completion). The list is shared by reference with | ||
| 182 | " the init options below (covers the first file) and pushed as config for later files. | ||
| 183 | let g:ra_detached = [] | ||
| 184 | function! RustDetach() abort | ||
| 185 | if !exists('g:lsp_loaded') | ||
| 186 | return | ||
| 187 | endif | ||
| 188 | let l:p = expand('%:p') | ||
| 189 | if empty(l:p) || !empty(RustCrate()) || index(g:ra_detached, l:p) >= 0 | ||
| 190 | return | ||
| 191 | endif | ||
| 192 | call add(g:ra_detached, l:p) | ||
| 193 | if lsp#get_server_status('rust-analyzer') ==# 'running' | ||
| 194 | call lsp#update_workspace_config('rust-analyzer', {'rust-analyzer': {'detachedFiles': copy(g:ra_detached)}}) | ||
| 195 | endif | ||
| 196 | endfunction | ||
| 197 | augroup rust_detached | ||
| 198 | au! | ||
| 199 | au BufEnter *.rs call RustDetach() | ||
| 200 | augroup END | ||
| 201 | |||
| 156 | " rust-analyzer via the rustup proxy shim (portable across toolchains/machines) | 202 | " rust-analyzer via the rustup proxy shim (portable across toolchains/machines) |
| 157 | if executable(expand('~/.cargo/bin/rust-analyzer')) | 203 | if executable(expand('~/.cargo/bin/rust-analyzer')) |
| 158 | au User lsp_setup call lsp#register_server({ | 204 | au User lsp_setup call lsp#register_server({ |
| 159 | \ 'name': 'rust-analyzer', | 205 | \ 'name': 'rust-analyzer', |
| 160 | \ 'cmd': {server_info -> [expand('~/.cargo/bin/rust-analyzer')]}, | 206 | \ 'cmd': {server_info -> [expand('~/.cargo/bin/rust-analyzer')]}, |
| 161 | \ 'allowlist': ['rust'], | 207 | \ 'allowlist': ['rust'], |
| 162 | \ 'root_uri': {server_info -> lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), 'Cargo.toml'))}, | 208 | \ 'root_uri': {server_info -> lsp#utils#path_to_uri(RustRoot())}, |
| 163 | \ 'initialization_options': { | 209 | \ 'initialization_options': { |
| 164 | \ 'completion': { | 210 | \ 'completion': { |
| 165 | \ 'autoimport': { 'enable': v:true }, | 211 | \ 'autoimport': { 'enable': v:true }, |
| 166 | \ 'postfix': { 'enable': v:true }, | 212 | \ 'postfix': { 'enable': v:true }, |
| 167 | \ }, | 213 | \ }, |
| 168 | \ 'checkOnSave': v:true, | 214 | \ 'checkOnSave': v:true, |
| 215 | \ 'detachedFiles': g:ra_detached, | ||
| 169 | \ }, | 216 | \ }, |
| 217 | \ 'workspace_config': {'rust-analyzer': {'detachedFiles': g:ra_detached}}, | ||
| 170 | \ }) | 218 | \ }) |
| 171 | endif | 219 | endif |
| 172 | if executable(expand('~/.local/bin/ruff')) | 220 | if executable(expand('~/.local/bin/ruff')) |
