-
-
Notifications
You must be signed in to change notification settings - Fork 92
/
Copy pathinternal.lua
453 lines (415 loc) · 15.1 KB
/
internal.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
local types = require('rustaceanvim.types.internal')
local cargo = require('rustaceanvim.cargo')
local config = require('rustaceanvim.config')
local executors = require('rustaceanvim.executors')
local os = require('rustaceanvim.os')
local server_config = require('rustaceanvim.config.server')
local RustaceanConfig
local rustaceanvim = vim.g.rustaceanvim or {}
local rustaceanvim_opts = type(rustaceanvim) == 'function' and rustaceanvim() or rustaceanvim
---@class rustaceanvim.internal.RAInitializedStatus : rustaceanvim.RAInitializedStatus
---@field health rustaceanvim.lsp_server_health_status
---@field quiescent boolean inactive?
---@field message string | nil
---
---@param dap_adapter rustaceanvim.dap.executable.Config | rustaceanvim.dap.server.Config | rustaceanvim.disable
---@return boolean
local function should_enable_dap_config_value(dap_adapter)
local adapter = types.evaluate(dap_adapter)
if adapter == false then
return false
end
return vim.fn.executable('rustc') == 1
end
---@param adapter rustaceanvim.dap.server.Config | rustaceanvim.dap.executable.Config
local function is_codelldb_adapter(adapter)
return adapter.type == 'server'
end
---@param adapter rustaceanvim.dap.server.Config | rustaceanvim.dap.executable.Config
local function is_lldb_adapter(adapter)
return adapter.type == 'executable'
end
---@param type string
---@return rustaceanvim.dap.client.Config
local function load_dap_configuration(type)
-- default
---@type rustaceanvim.dap.client.Config
local dap_config = {
name = 'Rust debug client',
type = type,
request = 'launch',
stopOnEntry = false,
}
if type == 'lldb' then
---@diagnostic disable-next-line: inject-field
dap_config.runInTerminal = true
end
---@diagnostic disable-next-line: different-requires
local dap = require('dap')
-- Load configurations from a `launch.json`.
-- It is necessary to check for changes in the `dap.configurations` table, as
-- `load_launchjs` does not return anything, it loads directly into `dap.configurations`.
local pre_launch = vim.deepcopy(dap.configurations) or {}
require('dap.ext.vscode').load_launchjs(nil, { lldb = { 'rust' }, codelldb = { 'rust' } })
for name, configuration_entries in pairs(dap.configurations) do
if pre_launch[name] == nil or not vim.deep_equal(pre_launch[name], configuration_entries) then
-- `configurations` are tables of `configuration` entries
-- use the first `configuration` that matches
for _, entry in pairs(configuration_entries) do
---@cast entry rustaceanvim.dap.client.Config
if entry.type == type then
dap_config = entry
break
end
end
end
end
return dap_config
end
---@return rustaceanvim.Executor
local function get_test_executor()
if package.loaded['rustaceanvim.neotest'] ~= nil then
-- neotest has been set up with rustaceanvim as an adapter
return executors.neotest
end
return executors.termopen
end
---@class rustaceanvim.Config
local RustaceanDefaultConfig = {
---@class rustaceanvim.tools.Config
tools = {
--- how to execute terminal commands
--- options right now: termopen / quickfix / toggleterm / vimux
---@type rustaceanvim.Executor
executor = executors.termopen,
---@type rustaceanvim.Executor
test_executor = get_test_executor(),
---@type rustaceanvim.Executor
crate_test_executor = executors.termopen,
---@type string | nil
cargo_override = nil,
---@type boolean
enable_nextest = vim.fn.executable('cargo-nextest') == 1,
---@type boolean
enable_clippy = true,
--- callback to execute once rust-analyzer is done initializing the workspace
--- The callback receives one parameter indicating the `health` of the server: "ok" | "warning" | "error"
---@type fun(health:rustaceanvim.RAInitializedStatus, client_id:integer) | nil
on_initialized = nil,
--- automatically call RustReloadWorkspace when writing to a Cargo.toml file.
---@type boolean
reload_workspace_from_cargo_toml = true,
--- options same as lsp hover
---@see vim.lsp.util.open_floating_preview
---@class rustaceanvim.hover-actions.Config
hover_actions = {
--- whether to replace Neovim's built-in `vim.lsp.buf.hover`.
---@type boolean
replace_builtin_hover = true,
},
code_actions = {
--- text appended to a group action
---@type string
group_icon = ' ▶',
--- whether to fall back to `vim.ui.select` if there are no grouped code actions
---@type boolean
ui_select_fallback = false,
---@class rustaceanvim.internal.code_action.Keys
keys = {
---@type string | string[]
confirm = { '<CR>' },
---@type string | string[]
quit = { 'q', '<Esc>' },
},
},
--- options same as lsp hover
---@see vim.lsp.util.open_floating_preview
---@see vim.api.nvim_open_win
---@type table Options applied to floating windows.
float_win_config = {
--- whether the window gets automatically focused
--- default: false
---@type boolean
auto_focus = false,
--- whether splits opened from floating preview are vertical
--- default: false
---@type 'horizontal' | 'vertical'
open_split = 'horizontal',
},
--- settings for showing the crate graph based on graphviz and the dot
--- command
---@class rustaceanvim.crate-graph.Config
crate_graph = {
-- backend used for displaying the graph
-- see: https://graphviz.org/docs/outputs/
-- default: x11
---@type string
backend = 'x11',
-- where to store the output, nil for no output stored (relative
-- path from pwd)
-- default: nil
---@type string | nil
output = nil,
-- true for all crates.io and external crates, false only the local
-- crates
-- default: true
---@type boolean
full = true,
-- List of backends found on: https://graphviz.org/docs/outputs/
-- Is used for input validation and autocompletion
-- Last updated: 2021-08-26
---@type string[]
enabled_graphviz_backends = {
'bmp',
'cgimage',
'canon',
'dot',
'gv',
'xdot',
'xdot1.2',
'xdot1.4',
'eps',
'exr',
'fig',
'gd',
'gd2',
'gif',
'gtk',
'ico',
'cmap',
'ismap',
'imap',
'cmapx',
'imap_np',
'cmapx_np',
'jpg',
'jpeg',
'jpe',
'jp2',
'json',
'json0',
'dot_json',
'xdot_json',
'pdf',
'pic',
'pct',
'pict',
'plain',
'plain-ext',
'png',
'pov',
'ps',
'ps2',
'psd',
'sgi',
'svg',
'svgz',
'tga',
'tiff',
'tif',
'tk',
'vml',
'vmlz',
'wbmp',
'webp',
'xlib',
'x11',
},
---@type string | nil
pipe = nil,
},
---@type fun(url:string):nil
open_url = function(url)
require('rustaceanvim.os').open_url(url)
end,
---settings for rustc
---@class rustaceanvim.rustc.Config
rustc = {
---@type string
default_edition = '2021',
},
},
--- all the opts to send to the LSP client
--- these override the defaults set by rust-tools.nvim
---@class rustaceanvim.lsp.ClientConfig: vim.lsp.ClientConfig
server = {
---@type lsp.ClientCapabilities
capabilities = server_config.create_client_capabilities(),
---@type boolean | fun(bufnr: integer):boolean Whether to automatically attach the LSP client.
---Defaults to `true` if the `rust-analyzer` executable is found.
auto_attach = function(bufnr)
if #vim.bo[bufnr].buftype > 0 then
return false
end
local path = vim.api.nvim_buf_get_name(bufnr)
if not os.is_valid_file_path(path) then
return false
end
local cmd = types.evaluate(RustaceanConfig.server.cmd)
if type(cmd) == 'function' then
-- This could be a function that connects via a TCP socket, so we don't want to evaluate it.
return true
end
---@cast cmd string[]
local rs_bin = cmd[1]
return vim.fn.executable(rs_bin) == 1
end,
---@type string[] | fun():(string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient)
cmd = function()
return { 'rust-analyzer', '--log-file', RustaceanConfig.server.logfile }
end,
---@type string | fun(filename: string, default: fun(filename: string):string|nil):string|nil
root_dir = cargo.get_root_dir,
ra_multiplex = {
---@type boolean
enable = vim.tbl_get(rustaceanvim_opts, 'server', 'cmd') == nil,
---@type string
host = '127.0.0.1',
---@type integer
port = 27631,
},
--- standalone file support
--- setting it to false may improve startup time
---@type boolean
standalone = true,
---@type string The path to the rust-analyzer log file.
logfile = vim.fn.tempname() .. '-rust-analyzer.log',
---@type table | (fun(project_root:string|nil, default_settings: table|nil):table) -- The rust-analyzer settings or a function that creates them.
settings = function(project_root, default_settings)
return server_config.load_rust_analyzer_settings(project_root, { default_settings = default_settings })
end,
--- @type table
default_settings = {
--- options to send to rust-analyzer
--- See: https://rust-analyzer.github.io/manual.html#configuration
--- @type table
['rust-analyzer'] = {},
},
---@type boolean Whether to search (upward from the buffer) for rust-analyzer settings in .vscode/settings json.
load_vscode_settings = true,
---@type rustaceanvim.server.status_notify_level
status_notify_level = 'error',
},
--- debugging stuff
--- @class rustaceanvim.dap.Config
dap = {
--- @type boolean Whether to autoload nvim-dap configurations when rust-analyzer has attached?
autoload_configurations = true,
--- @type rustaceanvim.dap.executable.Config | rustaceanvim.dap.server.Config | rustaceanvim.disable | fun():(rustaceanvim.dap.executable.Config | rustaceanvim.dap.server.Config | rustaceanvim.disable)
adapter = function()
--- @type rustaceanvim.dap.executable.Config | rustaceanvim.dap.server.Config | rustaceanvim.disable
local result = false
local has_mason, mason_registry = pcall(require, 'mason-registry')
if has_mason and mason_registry.is_installed('codelldb') then
local codelldb_package = mason_registry.get_package('codelldb')
local mason_codelldb_path = vim.fs.joinpath(codelldb_package:get_install_path(), 'extension')
local codelldb_path = vim.fs.joinpath(mason_codelldb_path, 'adapter', 'codelldb')
local liblldb_path = vim.fs.joinpath(mason_codelldb_path, 'lldb', 'lib', 'liblldb')
local shell = require('rustaceanvim.shell')
if shell.is_windows() then
codelldb_path = codelldb_path .. '.exe'
liblldb_path = vim.fs.joinpath(mason_codelldb_path, 'lldb', 'bin', 'liblldb.dll')
else
liblldb_path = liblldb_path .. (shell.is_macos() and '.dylib' or '.so')
end
result = config.get_codelldb_adapter(codelldb_path, liblldb_path)
elseif vim.fn.executable('codelldb') == 1 then
---@cast result rustaceanvim.dap.server.Config
result = {
type = 'server',
host = '127.0.0.1',
port = '${port}',
executable = {
command = 'codelldb',
args = { '--port', '${port}' },
},
}
else
local has_lldb_dap = vim.fn.executable('lldb-dap') == 1
local has_lldb_vscode = vim.fn.executable('lldb-vscode') == 1
if not has_lldb_dap and not has_lldb_vscode then
return result
end
local command = has_lldb_dap and 'lldb-dap' or 'lldb-vscode'
---@cast result rustaceanvim.dap.executable.Config
result = {
type = 'executable',
command = command,
name = 'lldb',
}
end
return result
end,
--- Accommodate dynamically-linked targets by passing library paths to lldb.
---@type boolean | fun():boolean
add_dynamic_library_paths = function()
return should_enable_dap_config_value(RustaceanConfig.dap.adapter)
end,
--- Auto-generate a source map for the standard library.
---@type boolean | fun():boolean
auto_generate_source_map = function()
return should_enable_dap_config_value(RustaceanConfig.dap.adapter)
end,
--- Get Rust types via initCommands (rustlib/etc/lldb_commands).
---@type boolean | fun():boolean
load_rust_types = function()
if not should_enable_dap_config_value(RustaceanConfig.dap.adapter) then
return false
end
local adapter = types.evaluate(RustaceanConfig.dap.adapter)
---@cast adapter rustaceanvim.dap.executable.Config | rustaceanvim.dap.server.Config | rustaceanvim.disable
return adapter ~= false and is_lldb_adapter(adapter)
end,
--- @type rustaceanvim.dap.client.Config | rustaceanvim.disable | fun():(rustaceanvim.dap.client.Config | rustaceanvim.disable)
configuration = function()
local ok, _ = pcall(require, 'dap')
if not ok then
return false
end
local adapter = types.evaluate(RustaceanConfig.dap.adapter)
---@cast adapter rustaceanvim.dap.executable.Config | rustaceanvim.dap.server.Config | rustaceanvim.disable
if adapter == false then
return false
end
---@cast adapter rustaceanvim.dap.executable.Config | rustaceanvim.dap.server.Config
local type = is_codelldb_adapter(adapter) and 'codelldb' or 'lldb'
return load_dap_configuration(type)
end,
},
-- debug info
was_g_rustaceanvim_sourced = vim.g.rustaceanvim ~= nil,
}
for _, executor in pairs { 'executor', 'test_executor', 'crate_test_executor' } do
if
rustaceanvim_opts.tools
and rustaceanvim_opts.tools[executor]
and type(rustaceanvim_opts.tools[executor]) == 'string'
then
rustaceanvim_opts.tools[executor] =
assert(executors[rustaceanvim_opts.tools[executor]], 'Unknown RustaceanExecutor')
end
end
---@type rustaceanvim.Config
RustaceanConfig = vim.tbl_deep_extend('force', {}, RustaceanDefaultConfig, rustaceanvim_opts)
-- Override user dap.adapter config in a backward compatible way
if rustaceanvim_opts.dap and rustaceanvim_opts.dap.adapter then
local user_adapter = rustaceanvim_opts.dap.adapter
local default_adapter = types.evaluate(RustaceanConfig.dap.adapter)
if
type(user_adapter) == 'table'
and type(default_adapter) == 'table'
and user_adapter.type == default_adapter.type
then
---@diagnostic disable-next-line: inject-field
RustaceanConfig.dap.adapter = vim.tbl_deep_extend('force', default_adapter, user_adapter)
elseif user_adapter ~= nil then
---@diagnostic disable-next-line: inject-field
RustaceanConfig.dap.adapter = user_adapter
end
end
local check = require('rustaceanvim.config.check')
local ok, err = check.validate(RustaceanConfig)
if not ok then
vim.notify('rustaceanvim: ' .. err, vim.log.levels.ERROR)
end
return RustaceanConfig