1 //! Config used by the language server.
3 //! We currently get this config from `initialize` LSP request, which is not the
4 //! best way to do it, but was the simplest thing we could implement.
6 //! Of particular interest is the `feature_flags` hash map: while other fields
7 //! configure the server itself, feature flags are passed into analysis, and
8 //! tweak things like automatic insertion of `()` in completions.
10 use std
::{fmt, iter, path::PathBuf}
;
12 use flycheck
::FlycheckConfig
;
14 AssistConfig
, CallableSnippets
, CompletionConfig
, DiagnosticsConfig
, ExprFillDefaultMode
,
15 HighlightConfig
, HighlightRelatedConfig
, HoverConfig
, HoverDocFormat
, InlayHintsConfig
,
16 JoinLinesConfig
, Snippet
, SnippetScope
,
19 imports
::insert_use
::{ImportGranularity, InsertUseConfig, PrefixKind}
,
22 use itertools
::Itertools
;
23 use lsp_types
::{ClientCapabilities, MarkupKind}
;
25 CargoConfig
, CargoFeatures
, ProjectJson
, ProjectJsonData
, ProjectManifest
, RustLibSource
,
28 use rustc_hash
::{FxHashMap, FxHashSet}
;
29 use serde
::{de::DeserializeOwned, Deserialize}
;
33 caps
::completion_item_edit_resolve
,
34 diagnostics
::DiagnosticsMapConfig
,
35 line_index
::PositionEncoding
,
36 lsp_ext
::{self, negotiated_encoding, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope}
,
41 // Conventions for configuration keys to preserve maximal extendability without breakage:
42 // - Toggles (be it binary true/false or with more options in-between) should almost always suffix as `_enable`
43 // This has the benefit of namespaces being extensible, and if the suffix doesn't fit later it can be changed without breakage.
44 // - In general be wary of using the namespace of something verbatim, it prevents us from adding subkeys in the future
45 // - Don't use abbreviations unless really necessary
46 // - foo_command = overrides the subcommand, foo_overrideCommand allows full overwriting, extra args only applies for foo_command
48 // Defines the server-side configuration of the rust-analyzer. We generate
49 // *parts* of VS Code's `package.json` config from this. Run `cargo test` to
50 // re-generate that file.
52 // However, editor specific config, which the server doesn't know about, should
53 // be specified directly in `package.json`.
55 // To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
56 // parsing the old name.
59 /// Whether to insert #[must_use] when generating `as_` methods
60 /// for enum variants.
61 assist_emitMustUse
: bool
= "false",
62 /// Placeholder expression to use for missing expressions in assists.
63 assist_expressionFillDefault
: ExprFillDefaultDef
= "\"todo\"",
65 /// Warm up caches on project load.
66 cachePriming_enable
: bool
= "true",
67 /// How many worker threads to handle priming caches. The default `0` means to pick automatically.
68 cachePriming_numThreads
: ParallelCachePrimingNumThreads
= "0",
70 /// Automatically refresh project info via `cargo metadata` on
71 /// `Cargo.toml` or `.cargo/config.toml` changes.
72 cargo_autoreload
: bool
= "true",
73 /// Run build scripts (`build.rs`) for more precise code analysis.
74 cargo_buildScripts_enable
: bool
= "true",
75 /// Specifies the working directory for running build scripts.
76 /// - "workspace": run build scripts for a workspace in the workspace's root directory.
77 /// This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.
78 /// - "root": run build scripts in the project's root directory.
79 /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
81 cargo_buildScripts_invocationLocation
: InvocationLocation
= "\"workspace\"",
82 /// Specifies the invocation strategy to use when running the build scripts command.
83 /// If `per_workspace` is set, the command will be executed for each workspace.
84 /// If `once` is set, the command will be executed once.
85 /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
87 cargo_buildScripts_invocationStrategy
: InvocationStrategy
= "\"per_workspace\"",
88 /// Override the command rust-analyzer uses to run build scripts and
89 /// build procedural macros. The command is required to output json
90 /// and should therefore include `--message-format=json` or a similar
93 /// By default, a cargo invocation will be constructed for the configured
94 /// targets and features, with the following base command line:
97 /// cargo check --quiet --workspace --message-format=json --all-targets
100 cargo_buildScripts_overrideCommand
: Option
<Vec
<String
>> = "null",
101 /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
102 /// avoid checking unnecessary things.
103 cargo_buildScripts_useRustcWrapper
: bool
= "true",
104 /// Extra arguments that are passed to every cargo invocation.
105 cargo_extraArgs
: Vec
<String
> = "[]",
106 /// Extra environment variables that will be set when running cargo, rustc
107 /// or other commands within the workspace. Useful for setting RUSTFLAGS.
108 cargo_extraEnv
: FxHashMap
<String
, String
> = "{}",
109 /// List of features to activate.
111 /// Set this to `"all"` to pass `--all-features` to cargo.
112 cargo_features
: CargoFeaturesDef
= "[]",
113 /// Whether to pass `--no-default-features` to cargo.
114 cargo_noDefaultFeatures
: bool
= "false",
115 /// Relative path to the sysroot, or "discover" to try to automatically find it via
116 /// "rustc --print sysroot".
118 /// Unsetting this disables sysroot loading.
120 /// This option does not take effect until rust-analyzer is restarted.
121 cargo_sysroot
: Option
<String
> = "\"discover\"",
122 /// Relative path to the sysroot library sources. If left unset, this will default to
123 /// `{cargo.sysroot}/lib/rustlib/src/rust/library`.
125 /// This option does not take effect until rust-analyzer is restarted.
126 cargo_sysrootSrc
: Option
<String
> = "null",
127 /// Compilation target override (target triple).
128 // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
129 // than `checkOnSave_target`
130 cargo_target
: Option
<String
> = "null",
131 /// Unsets `#[cfg(test)]` for the specified crates.
132 cargo_unsetTest
: Vec
<String
> = "[\"core\"]",
134 /// Run the check command for diagnostics on save.
135 checkOnSave
| checkOnSave_enable
: bool
= "true",
137 /// Check all targets and tests (`--all-targets`).
138 check_allTargets
| checkOnSave_allTargets
: bool
= "true",
139 /// Cargo command to use for `cargo check`.
140 check_command
| checkOnSave_command
: String
= "\"check\"",
141 /// Extra arguments for `cargo check`.
142 check_extraArgs
| checkOnSave_extraArgs
: Vec
<String
> = "[]",
143 /// Extra environment variables that will be set when running `cargo check`.
144 /// Extends `#rust-analyzer.cargo.extraEnv#`.
145 check_extraEnv
| checkOnSave_extraEnv
: FxHashMap
<String
, String
> = "{}",
146 /// List of features to activate. Defaults to
147 /// `#rust-analyzer.cargo.features#`.
149 /// Set to `"all"` to pass `--all-features` to Cargo.
150 check_features
| checkOnSave_features
: Option
<CargoFeaturesDef
> = "null",
151 /// Specifies the working directory for running checks.
152 /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories.
153 // FIXME: Ideally we would support this in some way
154 /// This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
155 /// - "root": run checks in the project's root directory.
156 /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
158 check_invocationLocation
| checkOnSave_invocationLocation
: InvocationLocation
= "\"workspace\"",
159 /// Specifies the invocation strategy to use when running the checkOnSave command.
160 /// If `per_workspace` is set, the command will be executed for each workspace.
161 /// If `once` is set, the command will be executed once.
162 /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
164 check_invocationStrategy
| checkOnSave_invocationStrategy
: InvocationStrategy
= "\"per_workspace\"",
165 /// Whether to pass `--no-default-features` to Cargo. Defaults to
166 /// `#rust-analyzer.cargo.noDefaultFeatures#`.
167 check_noDefaultFeatures
| checkOnSave_noDefaultFeatures
: Option
<bool
> = "null",
168 /// Override the command rust-analyzer uses instead of `cargo check` for
169 /// diagnostics on save. The command is required to output json and
170 /// should therefore include `--message-format=json` or a similar option
171 /// (if your client supports the `colorDiagnosticOutput` experimental
172 /// capability, you can use `--message-format=json-diagnostic-rendered-ansi`).
174 /// If you're changing this because you're using some tool wrapping
175 /// Cargo, you might also want to change
176 /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`.
178 /// If there are multiple linked projects, this command is invoked for
179 /// each of them, with the working directory being the project root
180 /// (i.e., the folder containing the `Cargo.toml`).
182 /// An example command would be:
185 /// cargo check --workspace --message-format=json --all-targets
188 check_overrideCommand
| checkOnSave_overrideCommand
: Option
<Vec
<String
>> = "null",
189 /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.
191 /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g.
192 /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`.
194 /// Aliased as `"checkOnSave.targets"`.
195 check_targets
| checkOnSave_targets
| checkOnSave_target
: Option
<CheckOnSaveTargets
> = "null",
197 /// Toggles the additional completions that automatically add imports when completed.
198 /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
199 completion_autoimport_enable
: bool
= "true",
200 /// Toggles the additional completions that automatically show method calls and field accesses
201 /// with `self` prefixed to them when inside a method.
202 completion_autoself_enable
: bool
= "true",
203 /// Whether to add parenthesis and argument snippets when completing function.
204 completion_callable_snippets
: CallableCompletionDef
= "\"fill_arguments\"",
205 /// Maximum number of completions to return. If `None`, the limit is infinite.
206 completion_limit
: Option
<usize> = "null",
207 /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
208 completion_postfix_enable
: bool
= "true",
209 /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
210 completion_privateEditable_enable
: bool
= "false",
211 /// Custom completion snippets.
212 // NOTE: Keep this list in sync with the feature docs of user snippets.
213 completion_snippets_custom
: FxHashMap
<String
, SnippetDef
> = r
#"{
216 "body": "Arc::new(${receiver})",
217 "requires": "std::sync::Arc",
218 "description": "Put the expression into an `Arc`",
223 "body": "Rc::new(${receiver})",
224 "requires": "std::rc::Rc",
225 "description": "Put the expression into an `Rc`",
230 "body": "Box::pin(${receiver})",
231 "requires": "std::boxed::Box",
232 "description": "Put the expression into a pinned `Box`",
237 "body": "Ok(${receiver})",
238 "description": "Wrap the expression in a `Result::Ok`",
243 "body": "Err(${receiver})",
244 "description": "Wrap the expression in a `Result::Err`",
249 "body": "Some(${receiver})",
250 "description": "Wrap the expression in an `Option::Some`",
255 /// List of rust-analyzer diagnostics to disable.
256 diagnostics_disabled
: FxHashSet
<String
> = "[]",
257 /// Whether to show native rust-analyzer diagnostics.
258 diagnostics_enable
: bool
= "true",
259 /// Whether to show experimental rust-analyzer diagnostics that might
260 /// have more false positives than usual.
261 diagnostics_experimental_enable
: bool
= "false",
262 /// Map of prefixes to be substituted when parsing diagnostic file paths.
263 /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.
264 diagnostics_remapPrefix
: FxHashMap
<String
, String
> = "{}",
265 /// List of warnings that should be displayed with hint severity.
267 /// The warnings will be indicated by faded text or three dots in code
268 /// and will not show up in the `Problems Panel`.
269 diagnostics_warningsAsHint
: Vec
<String
> = "[]",
270 /// List of warnings that should be displayed with info severity.
272 /// The warnings will be indicated by a blue squiggly underline in code
273 /// and a blue icon in the `Problems Panel`.
274 diagnostics_warningsAsInfo
: Vec
<String
> = "[]",
275 /// These directories will be ignored by rust-analyzer. They are
276 /// relative to the workspace root, and globs are not supported. You may
277 /// also need to add the folders to Code's `files.watcherExclude`.
278 files_excludeDirs
: Vec
<PathBuf
> = "[]",
279 /// Controls file watching implementation.
280 files_watcher
: FilesWatcherDef
= "\"client\"",
282 /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
283 highlightRelated_breakPoints_enable
: bool
= "true",
284 /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
285 highlightRelated_exitPoints_enable
: bool
= "true",
286 /// Enables highlighting of related references while the cursor is on any identifier.
287 highlightRelated_references_enable
: bool
= "true",
288 /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
289 highlightRelated_yieldPoints_enable
: bool
= "true",
291 /// Whether to show `Debug` action. Only applies when
292 /// `#rust-analyzer.hover.actions.enable#` is set.
293 hover_actions_debug_enable
: bool
= "true",
294 /// Whether to show HoverActions in Rust files.
295 hover_actions_enable
: bool
= "true",
296 /// Whether to show `Go to Type Definition` action. Only applies when
297 /// `#rust-analyzer.hover.actions.enable#` is set.
298 hover_actions_gotoTypeDef_enable
: bool
= "true",
299 /// Whether to show `Implementations` action. Only applies when
300 /// `#rust-analyzer.hover.actions.enable#` is set.
301 hover_actions_implementations_enable
: bool
= "true",
302 /// Whether to show `References` action. Only applies when
303 /// `#rust-analyzer.hover.actions.enable#` is set.
304 hover_actions_references_enable
: bool
= "false",
305 /// Whether to show `Run` action. Only applies when
306 /// `#rust-analyzer.hover.actions.enable#` is set.
307 hover_actions_run_enable
: bool
= "true",
309 /// Whether to show documentation on hover.
310 hover_documentation_enable
: bool
= "true",
311 /// Whether to show keyword hover popups. Only applies when
312 /// `#rust-analyzer.hover.documentation.enable#` is set.
313 hover_documentation_keywords_enable
: bool
= "true",
314 /// Use markdown syntax for links in hover.
315 hover_links_enable
: bool
= "true",
317 /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
318 imports_granularity_enforce
: bool
= "false",
319 /// How imports should be grouped into use statements.
320 imports_granularity_group
: ImportGranularityDef
= "\"crate\"",
321 /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
322 imports_group_enable
: bool
= "true",
323 /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
324 imports_merge_glob
: bool
= "true",
325 /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
326 imports_prefer_no_std
: bool
= "false",
327 /// The path structure for newly inserted paths to use.
328 imports_prefix
: ImportPrefixDef
= "\"plain\"",
330 /// Whether to show inlay type hints for binding modes.
331 inlayHints_bindingModeHints_enable
: bool
= "false",
332 /// Whether to show inlay type hints for method chains.
333 inlayHints_chainingHints_enable
: bool
= "true",
334 /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
335 inlayHints_closingBraceHints_enable
: bool
= "true",
336 /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
337 /// to always show them).
338 inlayHints_closingBraceHints_minLines
: usize = "25",
339 /// Whether to show inlay type hints for return types of closures.
340 inlayHints_closureReturnTypeHints_enable
: ClosureReturnTypeHintsDef
= "\"never\"",
341 /// Whether to show enum variant discriminant hints.
342 inlayHints_discriminantHints_enable
: DiscriminantHintsDef
= "\"never\"",
343 /// Whether to show inlay hints for type adjustments.
344 inlayHints_expressionAdjustmentHints_enable
: AdjustmentHintsDef
= "\"never\"",
345 /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
346 inlayHints_expressionAdjustmentHints_hideOutsideUnsafe
: bool
= "false",
347 /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
348 inlayHints_expressionAdjustmentHints_mode
: AdjustmentHintsModeDef
= "\"prefix\"",
349 /// Whether to show inlay type hints for elided lifetimes in function signatures.
350 inlayHints_lifetimeElisionHints_enable
: LifetimeElisionDef
= "\"never\"",
351 /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
352 inlayHints_lifetimeElisionHints_useParameterNames
: bool
= "false",
353 /// Maximum length for inlay hints. Set to null to have an unlimited length.
354 inlayHints_maxLength
: Option
<usize> = "25",
355 /// Whether to show function parameter name inlay hints at the call
357 inlayHints_parameterHints_enable
: bool
= "true",
358 /// Whether to show inlay hints for compiler inserted reborrows.
359 /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
360 inlayHints_reborrowHints_enable
: ReborrowHintsDef
= "\"never\"",
361 /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
362 inlayHints_renderColons
: bool
= "true",
363 /// Whether to show inlay type hints for variables.
364 inlayHints_typeHints_enable
: bool
= "true",
365 /// Whether to hide inlay type hints for `let` statements that initialize to a closure.
366 /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
367 inlayHints_typeHints_hideClosureInitialization
: bool
= "false",
368 /// Whether to hide inlay type hints for constructors.
369 inlayHints_typeHints_hideNamedConstructor
: bool
= "false",
370 /// Enables the experimental support for interpreting tests.
371 interpret_tests
: bool
= "false",
373 /// Join lines merges consecutive declaration and initialization of an assignment.
374 joinLines_joinAssignments
: bool
= "true",
375 /// Join lines inserts else between consecutive ifs.
376 joinLines_joinElseIf
: bool
= "true",
377 /// Join lines removes trailing commas.
378 joinLines_removeTrailingComma
: bool
= "true",
379 /// Join lines unwraps trivial blocks.
380 joinLines_unwrapTrivialBlock
: bool
= "true",
383 /// Whether to show `Debug` lens. Only applies when
384 /// `#rust-analyzer.lens.enable#` is set.
385 lens_debug_enable
: bool
= "true",
386 /// Whether to show CodeLens in Rust files.
387 lens_enable
: bool
= "true",
388 /// Internal config: use custom client-side commands even when the
389 /// client doesn't set the corresponding capability.
390 lens_forceCustomCommands
: bool
= "true",
391 /// Whether to show `Implementations` lens. Only applies when
392 /// `#rust-analyzer.lens.enable#` is set.
393 lens_implementations_enable
: bool
= "true",
394 /// Where to render annotations.
395 lens_location
: AnnotationLocation
= "\"above_name\"",
396 /// Whether to show `References` lens for Struct, Enum, and Union.
397 /// Only applies when `#rust-analyzer.lens.enable#` is set.
398 lens_references_adt_enable
: bool
= "false",
399 /// Whether to show `References` lens for Enum Variants.
400 /// Only applies when `#rust-analyzer.lens.enable#` is set.
401 lens_references_enumVariant_enable
: bool
= "false",
402 /// Whether to show `Method References` lens. Only applies when
403 /// `#rust-analyzer.lens.enable#` is set.
404 lens_references_method_enable
: bool
= "false",
405 /// Whether to show `References` lens for Trait.
406 /// Only applies when `#rust-analyzer.lens.enable#` is set.
407 lens_references_trait_enable
: bool
= "false",
408 /// Whether to show `Run` lens. Only applies when
409 /// `#rust-analyzer.lens.enable#` is set.
410 lens_run_enable
: bool
= "true",
412 /// Disable project auto-discovery in favor of explicitly specified set
415 /// Elements must be paths pointing to `Cargo.toml`,
416 /// `rust-project.json`, or JSON objects in `rust-project.json` format.
417 linkedProjects
: Vec
<ManifestOrProjectJson
> = "[]",
419 /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
420 lru_capacity
: Option
<usize> = "null",
422 /// Whether to show `can't find Cargo.toml` error message.
423 notifications_cargoTomlNotFound
: bool
= "true",
425 /// How many worker threads in the main loop. The default `null` means to pick automatically.
426 numThreads
: Option
<usize> = "null",
428 /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
429 procMacro_attributes_enable
: bool
= "true",
430 /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
431 procMacro_enable
: bool
= "true",
432 /// These proc-macros will be ignored when trying to expand them.
434 /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
435 procMacro_ignored
: FxHashMap
<Box
<str>, Box
<[Box
<str>]>> = "{}",
436 /// Internal config, path to proc-macro server executable (typically,
437 /// this is rust-analyzer itself, but we override this in tests).
438 procMacro_server
: Option
<PathBuf
> = "null",
440 /// Exclude imports from find-all-references.
441 references_excludeImports
: bool
= "false",
443 /// Command to be executed instead of 'cargo' for runnables.
444 runnables_command
: Option
<String
> = "null",
445 /// Additional arguments to be passed to cargo for runnables such as
446 /// tests or binaries. For example, it may be `--release`.
447 runnables_extraArgs
: Vec
<String
> = "[]",
449 /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
450 /// projects, or "discover" to try to automatically find it if the `rustc-dev` component
453 /// Any project which uses rust-analyzer with the rustcPrivate
454 /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
456 /// This option does not take effect until rust-analyzer is restarted.
457 rustc_source
: Option
<String
> = "null",
459 /// Additional arguments to `rustfmt`.
460 rustfmt_extraArgs
: Vec
<String
> = "[]",
461 /// Advanced option, fully override the command rust-analyzer uses for
462 /// formatting. This should be the equivalent of `rustfmt` here, and
463 /// not that of `cargo fmt`. The file contents will be passed on the
464 /// standard input and the formatted result will be read from the
466 rustfmt_overrideCommand
: Option
<Vec
<String
>> = "null",
467 /// Enables the use of rustfmt's unstable range formatting command for the
468 /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only
469 /// available on a nightly build.
470 rustfmt_rangeFormatting_enable
: bool
= "false",
472 /// Inject additional highlighting into doc comments.
474 /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
476 semanticHighlighting_doc_comment_inject_enable
: bool
= "true",
477 /// Use semantic tokens for operators.
479 /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
480 /// they are tagged with modifiers.
481 semanticHighlighting_operator_enable
: bool
= "true",
482 /// Use specialized semantic tokens for operators.
484 /// When enabled, rust-analyzer will emit special token types for operator tokens instead
485 /// of the generic `operator` token type.
486 semanticHighlighting_operator_specialization_enable
: bool
= "false",
487 /// Use semantic tokens for punctuations.
489 /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
490 /// they are tagged with modifiers or have a special role.
491 semanticHighlighting_punctuation_enable
: bool
= "false",
492 /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
494 semanticHighlighting_punctuation_separate_macro_bang
: bool
= "false",
495 /// Use specialized semantic tokens for punctuations.
497 /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead
498 /// of the generic `punctuation` token type.
499 semanticHighlighting_punctuation_specialization_enable
: bool
= "false",
500 /// Use semantic tokens for strings.
502 /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
503 /// By disabling semantic tokens for strings, other grammars can be used to highlight
505 semanticHighlighting_strings_enable
: bool
= "true",
507 /// Show full signature of the callable. Only shows parameters if disabled.
508 signatureInfo_detail
: SignatureDetail
= "\"full\"",
509 /// Show documentation.
510 signatureInfo_documentation_enable
: bool
= "true",
512 /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
513 typing_autoClosingAngleBrackets_enable
: bool
= "false",
515 /// Workspace symbol search kind.
516 workspace_symbol_search_kind
: WorkspaceSymbolSearchKindDef
= "\"only_types\"",
517 /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
518 /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
519 /// Other clients requires all results upfront and might require a higher limit.
520 workspace_symbol_search_limit
: usize = "128",
521 /// Workspace symbol search scope.
522 workspace_symbol_search_scope
: WorkspaceSymbolSearchScopeDef
= "\"workspace\"",
526 impl Default
for ConfigData
{
527 fn default() -> Self {
528 ConfigData
::from_json(serde_json
::Value
::Null
, &mut Vec
::new())
532 #[derive(Debug, Clone)]
534 pub discovered_projects
: Option
<Vec
<ProjectManifest
>>,
535 pub workspace_roots
: Vec
<AbsPathBuf
>,
536 caps
: lsp_types
::ClientCapabilities
,
537 root_path
: AbsPathBuf
,
539 detached_files
: Vec
<AbsPathBuf
>,
540 snippets
: Vec
<Snippet
>,
543 type ParallelCachePrimingNumThreads
= u8;
545 #[derive(Debug, Clone, Eq, PartialEq)]
546 pub enum LinkedProject
{
547 ProjectManifest(ProjectManifest
),
548 InlineJsonProject(ProjectJson
),
551 impl From
<ProjectManifest
> for LinkedProject
{
552 fn from(v
: ProjectManifest
) -> Self {
553 LinkedProject
::ProjectManifest(v
)
557 impl From
<ProjectJson
> for LinkedProject
{
558 fn from(v
: ProjectJson
) -> Self {
559 LinkedProject
::InlineJsonProject(v
)
563 pub struct CallInfoConfig
{
564 pub params_only
: bool
,
568 #[derive(Clone, Debug, PartialEq, Eq)]
569 pub struct LensConfig
{
575 pub implementations
: bool
,
578 pub method_refs
: bool
,
579 pub refs_adt
: bool
, // for Struct, Enum, Union and Trait
580 pub refs_trait
: bool
, // for Struct, Enum, Union and Trait
581 pub enum_variant_refs
: bool
,
584 pub location
: AnnotationLocation
,
587 #[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
588 #[serde(rename_all = "snake_case")]
589 pub enum AnnotationLocation
{
594 impl From
<AnnotationLocation
> for ide
::AnnotationLocation
{
595 fn from(location
: AnnotationLocation
) -> Self {
597 AnnotationLocation
::AboveName
=> ide
::AnnotationLocation
::AboveName
,
598 AnnotationLocation
::AboveWholeItem
=> ide
::AnnotationLocation
::AboveWholeItem
,
604 pub fn any(&self) -> bool
{
607 || self.implementations
611 || self.enum_variant_refs
614 pub fn none(&self) -> bool
{
618 pub fn runnable(&self) -> bool
{
619 self.run
|| self.debug
622 pub fn references(&self) -> bool
{
623 self.method_refs
|| self.refs_adt
|| self.refs_trait
|| self.enum_variant_refs
627 #[derive(Clone, Debug, PartialEq, Eq)]
628 pub struct HoverActionsConfig
{
629 pub implementations
: bool
,
630 pub references
: bool
,
633 pub goto_type_def
: bool
,
636 impl HoverActionsConfig
{
637 pub const NO_ACTIONS
: Self = Self {
638 implementations
: false,
642 goto_type_def
: false,
645 pub fn any(&self) -> bool
{
646 self.implementations
|| self.references
|| self.runnable() || self.goto_type_def
649 pub fn none(&self) -> bool
{
653 pub fn runnable(&self) -> bool
{
654 self.run
|| self.debug
658 #[derive(Debug, Clone)]
659 pub struct FilesConfig
{
660 pub watcher
: FilesWatcher
,
661 pub exclude
: Vec
<AbsPathBuf
>,
664 #[derive(Debug, Clone)]
665 pub enum FilesWatcher
{
670 #[derive(Debug, Clone)]
671 pub struct NotificationsConfig
{
672 pub cargo_toml_not_found
: bool
,
675 #[derive(Debug, Clone)]
676 pub enum RustfmtConfig
{
677 Rustfmt { extra_args: Vec<String>, enable_range_formatting: bool }
,
678 CustomCommand { command: String, args: Vec<String> }
,
681 /// Configuration for runnable items, such as `main` function or tests.
682 #[derive(Debug, Clone)]
683 pub struct RunnablesConfig
{
684 /// Custom command to be executed instead of `cargo` for runnables.
685 pub override_cargo
: Option
<String
>,
686 /// Additional arguments for the `cargo`, e.g. `--release`.
687 pub cargo_extra_args
: Vec
<String
>,
690 /// Configuration for workspace symbol search requests.
691 #[derive(Debug, Clone)]
692 pub struct WorkspaceSymbolConfig
{
693 /// In what scope should the symbol be searched in.
694 pub search_scope
: WorkspaceSymbolSearchScope
,
695 /// What kind of symbol is being searched for.
696 pub search_kind
: WorkspaceSymbolSearchKind
,
697 /// How many items are returned at most.
698 pub search_limit
: usize,
701 pub struct ClientCommandsConfig
{
702 pub run_single
: bool
,
703 pub debug_single
: bool
,
704 pub show_reference
: bool
,
705 pub goto_location
: bool
,
706 pub trigger_parameter_hints
: bool
,
710 pub struct ConfigUpdateError
{
711 errors
: Vec
<(String
, serde_json
::Error
)>,
714 impl fmt
::Display
for ConfigUpdateError
{
715 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
716 let errors
= self.errors
.iter().format_with("\n", |(key
, e
), f
| {
723 "rust-analyzer found {} invalid config value{}:\n{}",
725 if self.errors
.len() == 1 { "" }
else { "s" }
,
733 root_path
: AbsPathBuf
,
734 caps
: ClientCapabilities
,
735 workspace_roots
: Vec
<AbsPathBuf
>,
739 data
: ConfigData
::default(),
740 detached_files
: Vec
::new(),
741 discovered_projects
: None
,
743 snippets
: Default
::default(),
748 pub fn rediscover_workspaces(&mut self) {
749 let discovered
= ProjectManifest
::discover_all(&self.workspace_roots
);
750 tracing
::info
!("discovered projects: {:?}", discovered
);
751 if discovered
.is_empty() {
752 tracing
::error
!("failed to find any projects in {:?}", &self.workspace_roots
);
754 self.discovered_projects
= Some(discovered
);
757 pub fn update(&mut self, mut json
: serde_json
::Value
) -> Result
<(), ConfigUpdateError
> {
758 tracing
::info
!("updating config from JSON: {:#}", json
);
759 if json
.is_null() || json
.as_object().map_or(false, |it
| it
.is_empty()) {
762 let mut errors
= Vec
::new();
763 self.detached_files
=
764 get_field
::<Vec
<PathBuf
>>(&mut json
, &mut errors
, "detachedFiles", None
, "[]")
766 .map(AbsPathBuf
::assert
)
768 patch_old_style
::patch_json_for_outdated_configs(&mut json
);
769 self.data
= ConfigData
::from_json(json
, &mut errors
);
770 tracing
::debug
!("deserialized config data: {:#?}", self.data
);
771 self.snippets
.clear();
772 for (name
, def
) in self.data
.completion_snippets_custom
.iter() {
773 if def
.prefix
.is_empty() && def
.postfix
.is_empty() {
776 let scope
= match def
.scope
{
777 SnippetScopeDef
::Expr
=> SnippetScope
::Expr
,
778 SnippetScopeDef
::Type
=> SnippetScope
::Type
,
779 SnippetScopeDef
::Item
=> SnippetScope
::Item
,
785 def
.description
.as_ref().unwrap_or(name
),
789 Some(snippet
) => self.snippets
.push(snippet
),
790 None
=> errors
.push((
791 format
!("snippet {name} is invalid"),
792 <serde_json
::Error
as serde
::de
::Error
>::custom(
793 "snippet path is invalid or triggers are missing",
799 self.validate(&mut errors
);
801 if errors
.is_empty() {
804 Err(ConfigUpdateError { errors }
)
808 fn validate(&self, error_sink
: &mut Vec
<(String
, serde_json
::Error
)>) {
809 use serde
::de
::Error
;
810 if self.data
.check_command
.is_empty() {
812 "/check/command".to_string(),
813 serde_json
::Error
::custom("expected a non-empty string"),
818 pub fn json_schema() -> serde_json
::Value
{
819 ConfigData
::json_schema()
822 pub fn root_path(&self) -> &AbsPathBuf
{
826 pub fn caps(&self) -> &lsp_types
::ClientCapabilities
{
830 pub fn detached_files(&self) -> &[AbsPathBuf
] {
837 || -> _ { Some($expr) }
()
840 macro_rules
! try_or
{
841 ($expr
:expr
, $or
:expr
) => {
842 try_
!($expr
).unwrap_or($or
)
846 macro_rules
! try_or_def
{
848 try_
!($expr
).unwrap_or_default()
853 pub fn has_linked_projects(&self) -> bool
{
854 !self.data
.linkedProjects
.is_empty()
856 pub fn linked_projects(&self) -> Vec
<LinkedProject
> {
857 match self.data
.linkedProjects
.as_slice() {
859 match self.discovered_projects
.as_ref() {
860 Some(discovered_projects
) => {
861 let exclude_dirs
: Vec
<_
> = self
865 .map(|p
| self.root_path
.join(p
))
869 .filter(|(ProjectManifest
::ProjectJson(path
) | ProjectManifest
::CargoToml(path
))| {
870 !exclude_dirs
.iter().any(|p
| path
.starts_with(p
))
873 .map(LinkedProject
::from
)
879 linked_projects
=> linked_projects
881 .filter_map(|linked_project
| match linked_project
{
882 ManifestOrProjectJson
::Manifest(it
) => {
883 let path
= self.root_path
.join(it
);
884 ProjectManifest
::from_manifest_file(path
)
885 .map_err(|e
| tracing
::error
!("failed to load linked project: {}", e
))
889 ManifestOrProjectJson
::ProjectJson(it
) => {
890 Some(ProjectJson
::new(&self.root_path
, it
.clone()).into())
897 pub fn add_linked_projects(&mut self, linked_projects
: Vec
<ProjectJsonData
>) {
898 let mut linked_projects
= linked_projects
900 .map(ManifestOrProjectJson
::ProjectJson
)
901 .collect
::<Vec
<ManifestOrProjectJson
>>();
903 self.data
.linkedProjects
.append(&mut linked_projects
);
906 pub fn did_save_text_document_dynamic_registration(&self) -> bool
{
907 let caps
= try_or_def
!(self.caps
.text_document
.as_ref()?
.synchronization
.clone()?
);
908 caps
.did_save
== Some(true) && caps
.dynamic_registration
== Some(true)
911 pub fn did_change_watched_files_dynamic_registration(&self) -> bool
{
913 self.caps
.workspace
.as_ref()?
.did_change_watched_files
.as_ref()?
.dynamic_registration?
917 pub fn prefill_caches(&self) -> bool
{
918 self.data
.cachePriming_enable
921 pub fn location_link(&self) -> bool
{
922 try_or_def
!(self.caps
.text_document
.as_ref()?
.definition?
.link_support?
)
925 pub fn line_folding_only(&self) -> bool
{
926 try_or_def
!(self.caps
.text_document
.as_ref()?
.folding_range
.as_ref()?
.line_folding_only?
)
929 pub fn hierarchical_symbols(&self) -> bool
{
936 .hierarchical_document_symbol_support?
940 pub fn code_action_literals(&self) -> bool
{
947 .code_action_literal_support
952 pub fn work_done_progress(&self) -> bool
{
953 try_or_def
!(self.caps
.window
.as_ref()?
.work_done_progress?
)
956 pub fn will_rename(&self) -> bool
{
957 try_or_def
!(self.caps
.workspace
.as_ref()?
.file_operations
.as_ref()?
.will_rename?
)
960 pub fn change_annotation_support(&self) -> bool
{
967 .change_annotation_support
972 pub fn code_action_resolve(&self) -> bool
{
984 .any(|it
| it
== "edit")
987 pub fn signature_help_label_offsets(&self) -> bool
{
994 .signature_information
996 .parameter_information
998 .label_offset_support?
1002 pub fn completion_label_details_support(&self) -> bool
{
1011 .label_details_support
1016 pub fn position_encoding(&self) -> PositionEncoding
{
1017 negotiated_encoding(&self.caps
)
1020 fn experimental(&self, index
: &'
static str) -> bool
{
1021 try_or_def
!(self.caps
.experimental
.as_ref()?
.get(index
)?
.as_bool()?
)
1024 pub fn code_action_group(&self) -> bool
{
1025 self.experimental("codeActionGroup")
1028 pub fn open_server_logs(&self) -> bool
{
1029 self.experimental("openServerLogs")
1032 pub fn server_status_notification(&self) -> bool
{
1033 self.experimental("serverStatusNotification")
1036 /// Whether the client supports colored output for full diagnostics from `checkOnSave`.
1037 pub fn color_diagnostic_output(&self) -> bool
{
1038 self.experimental("colorDiagnosticOutput")
1041 pub fn publish_diagnostics(&self) -> bool
{
1042 self.data
.diagnostics_enable
1045 pub fn diagnostics(&self) -> DiagnosticsConfig
{
1047 proc_attr_macros_enabled
: self.expand_proc_attr_macros(),
1048 proc_macros_enabled
: self.data
.procMacro_enable
,
1049 disable_experimental
: !self.data
.diagnostics_experimental_enable
,
1050 disabled
: self.data
.diagnostics_disabled
.clone(),
1051 expr_fill_default
: match self.data
.assist_expressionFillDefault
{
1052 ExprFillDefaultDef
::Todo
=> ExprFillDefaultMode
::Todo
,
1053 ExprFillDefaultDef
::Default
=> ExprFillDefaultMode
::Default
,
1055 insert_use
: self.insert_use_config(),
1056 prefer_no_std
: self.data
.imports_prefer_no_std
,
1060 pub fn diagnostics_map(&self) -> DiagnosticsMapConfig
{
1061 DiagnosticsMapConfig
{
1062 remap_prefix
: self.data
.diagnostics_remapPrefix
.clone(),
1063 warnings_as_info
: self.data
.diagnostics_warningsAsInfo
.clone(),
1064 warnings_as_hint
: self.data
.diagnostics_warningsAsHint
.clone(),
1068 pub fn extra_args(&self) -> &Vec
<String
> {
1069 &self.data
.cargo_extraArgs
1072 pub fn extra_env(&self) -> &FxHashMap
<String
, String
> {
1073 &self.data
.cargo_extraEnv
1076 pub fn check_extra_args(&self) -> Vec
<String
> {
1077 let mut extra_args
= self.extra_args().clone();
1078 extra_args
.extend_from_slice(&self.data
.check_extraArgs
);
1082 pub fn check_extra_env(&self) -> FxHashMap
<String
, String
> {
1083 let mut extra_env
= self.data
.cargo_extraEnv
.clone();
1084 extra_env
.extend(self.data
.check_extraEnv
.clone());
1088 pub fn lru_capacity(&self) -> Option
<usize> {
1089 self.data
.lru_capacity
1092 pub fn proc_macro_srv(&self) -> Option
<(AbsPathBuf
, /* is path explicitly set */ bool
)> {
1093 if !self.data
.procMacro_enable
{
1096 Some(match &self.data
.procMacro_server
{
1098 AbsPathBuf
::try_from(it
.clone()).unwrap_or_else(|path
| self.root_path
.join(path
)),
1101 None
=> (AbsPathBuf
::assert(std
::env
::current_exe().ok()?
), false),
1105 pub fn dummy_replacements(&self) -> &FxHashMap
<Box
<str>, Box
<[Box
<str>]>> {
1106 &self.data
.procMacro_ignored
1109 pub fn expand_proc_attr_macros(&self) -> bool
{
1110 self.data
.procMacro_enable
&& self.data
.procMacro_attributes_enable
1113 pub fn files(&self) -> FilesConfig
{
1115 watcher
: match self.data
.files_watcher
{
1116 FilesWatcherDef
::Client
if self.did_change_watched_files_dynamic_registration() => {
1117 FilesWatcher
::Client
1119 _
=> FilesWatcher
::Server
,
1121 exclude
: self.data
.files_excludeDirs
.iter().map(|it
| self.root_path
.join(it
)).collect(),
1125 pub fn notifications(&self) -> NotificationsConfig
{
1126 NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound }
1129 pub fn cargo_autoreload(&self) -> bool
{
1130 self.data
.cargo_autoreload
1133 pub fn run_build_scripts(&self) -> bool
{
1134 self.data
.cargo_buildScripts_enable
|| self.data
.procMacro_enable
1137 pub fn cargo(&self) -> CargoConfig
{
1138 let rustc_source
= self.data
.rustc_source
.as_ref().map(|rustc_src
| {
1139 if rustc_src
== "discover" {
1140 RustLibSource
::Discover
1142 RustLibSource
::Path(self.root_path
.join(rustc_src
))
1145 let sysroot
= self.data
.cargo_sysroot
.as_ref().map(|sysroot
| {
1146 if sysroot
== "discover" {
1147 RustLibSource
::Discover
1149 RustLibSource
::Path(self.root_path
.join(sysroot
))
1153 self.data
.cargo_sysrootSrc
.as_ref().map(|sysroot
| self.root_path
.join(sysroot
));
1156 features
: match &self.data
.cargo_features
{
1157 CargoFeaturesDef
::All
=> CargoFeatures
::All
,
1158 CargoFeaturesDef
::Selected(features
) => CargoFeatures
::Selected
{
1159 features
: features
.clone(),
1160 no_default_features
: self.data
.cargo_noDefaultFeatures
,
1163 target
: self.data
.cargo_target
.clone(),
1167 unset_test_crates
: UnsetTestCrates
::Only(self.data
.cargo_unsetTest
.clone()),
1168 wrap_rustc_in_build_scripts
: self.data
.cargo_buildScripts_useRustcWrapper
,
1169 invocation_strategy
: match self.data
.cargo_buildScripts_invocationStrategy
{
1170 InvocationStrategy
::Once
=> project_model
::InvocationStrategy
::Once
,
1171 InvocationStrategy
::PerWorkspace
=> project_model
::InvocationStrategy
::PerWorkspace
,
1173 invocation_location
: match self.data
.cargo_buildScripts_invocationLocation
{
1174 InvocationLocation
::Root
=> {
1175 project_model
::InvocationLocation
::Root(self.root_path
.clone())
1177 InvocationLocation
::Workspace
=> project_model
::InvocationLocation
::Workspace
,
1179 run_build_script_command
: self.data
.cargo_buildScripts_overrideCommand
.clone(),
1180 extra_args
: self.data
.cargo_extraArgs
.clone(),
1181 extra_env
: self.data
.cargo_extraEnv
.clone(),
1185 pub fn rustfmt(&self) -> RustfmtConfig
{
1186 match &self.data
.rustfmt_overrideCommand
{
1187 Some(args
) if !args
.is_empty() => {
1188 let mut args
= args
.clone();
1189 let command
= args
.remove(0);
1190 RustfmtConfig
::CustomCommand { command, args }
1192 Some(_
) | None
=> RustfmtConfig
::Rustfmt
{
1193 extra_args
: self.data
.rustfmt_extraArgs
.clone(),
1194 enable_range_formatting
: self.data
.rustfmt_rangeFormatting_enable
,
1199 pub fn flycheck(&self) -> FlycheckConfig
{
1200 match &self.data
.check_overrideCommand
{
1201 Some(args
) if !args
.is_empty() => {
1202 let mut args
= args
.clone();
1203 let command
= args
.remove(0);
1204 FlycheckConfig
::CustomCommand
{
1207 extra_env
: self.check_extra_env(),
1208 invocation_strategy
: match self.data
.check_invocationStrategy
{
1209 InvocationStrategy
::Once
=> flycheck
::InvocationStrategy
::Once
,
1210 InvocationStrategy
::PerWorkspace
=> {
1211 flycheck
::InvocationStrategy
::PerWorkspace
1214 invocation_location
: match self.data
.check_invocationLocation
{
1215 InvocationLocation
::Root
=> {
1216 flycheck
::InvocationLocation
::Root(self.root_path
.clone())
1218 InvocationLocation
::Workspace
=> flycheck
::InvocationLocation
::Workspace
,
1222 Some(_
) | None
=> FlycheckConfig
::CargoCommand
{
1223 command
: self.data
.check_command
.clone(),
1224 target_triples
: self
1228 .and_then(|targets
| match &targets
.0[..] {
1230 targets
=> Some(targets
.into()),
1232 .unwrap_or_else(|| self.data
.cargo_target
.clone().into_iter().collect()),
1233 all_targets
: self.data
.check_allTargets
,
1234 no_default_features
: self
1236 .check_noDefaultFeatures
1237 .unwrap_or(self.data
.cargo_noDefaultFeatures
),
1238 all_features
: matches
!(
1239 self.data
.check_features
.as_ref().unwrap_or(&self.data
.cargo_features
),
1240 CargoFeaturesDef
::All
1242 features
: match self
1246 .unwrap_or_else(|| self.data
.cargo_features
.clone())
1248 CargoFeaturesDef
::All
=> vec
![],
1249 CargoFeaturesDef
::Selected(it
) => it
,
1251 extra_args
: self.check_extra_args(),
1252 extra_env
: self.check_extra_env(),
1253 ansi_color_output
: self.color_diagnostic_output(),
1258 pub fn check_on_save(&self) -> bool
{
1259 self.data
.checkOnSave
1262 pub fn runnables(&self) -> RunnablesConfig
{
1264 override_cargo
: self.data
.runnables_command
.clone(),
1265 cargo_extra_args
: self.data
.runnables_extraArgs
.clone(),
1269 pub fn inlay_hints(&self) -> InlayHintsConfig
{
1271 render_colons
: self.data
.inlayHints_renderColons
,
1272 type_hints
: self.data
.inlayHints_typeHints_enable
,
1273 parameter_hints
: self.data
.inlayHints_parameterHints_enable
,
1274 chaining_hints
: self.data
.inlayHints_chainingHints_enable
,
1275 discriminant_hints
: match self.data
.inlayHints_discriminantHints_enable
{
1276 DiscriminantHintsDef
::Always
=> ide
::DiscriminantHints
::Always
,
1277 DiscriminantHintsDef
::Never
=> ide
::DiscriminantHints
::Never
,
1278 DiscriminantHintsDef
::Fieldless
=> ide
::DiscriminantHints
::Fieldless
,
1280 closure_return_type_hints
: match self.data
.inlayHints_closureReturnTypeHints_enable
{
1281 ClosureReturnTypeHintsDef
::Always
=> ide
::ClosureReturnTypeHints
::Always
,
1282 ClosureReturnTypeHintsDef
::Never
=> ide
::ClosureReturnTypeHints
::Never
,
1283 ClosureReturnTypeHintsDef
::WithBlock
=> ide
::ClosureReturnTypeHints
::WithBlock
,
1285 lifetime_elision_hints
: match self.data
.inlayHints_lifetimeElisionHints_enable
{
1286 LifetimeElisionDef
::Always
=> ide
::LifetimeElisionHints
::Always
,
1287 LifetimeElisionDef
::Never
=> ide
::LifetimeElisionHints
::Never
,
1288 LifetimeElisionDef
::SkipTrivial
=> ide
::LifetimeElisionHints
::SkipTrivial
,
1290 hide_named_constructor_hints
: self.data
.inlayHints_typeHints_hideNamedConstructor
,
1291 hide_closure_initialization_hints
: self
1293 .inlayHints_typeHints_hideClosureInitialization
,
1294 adjustment_hints
: match self.data
.inlayHints_expressionAdjustmentHints_enable
{
1295 AdjustmentHintsDef
::Always
=> ide
::AdjustmentHints
::Always
,
1296 AdjustmentHintsDef
::Never
=> match self.data
.inlayHints_reborrowHints_enable
{
1297 ReborrowHintsDef
::Always
| ReborrowHintsDef
::Mutable
=> {
1298 ide
::AdjustmentHints
::ReborrowOnly
1300 ReborrowHintsDef
::Never
=> ide
::AdjustmentHints
::Never
,
1302 AdjustmentHintsDef
::Reborrow
=> ide
::AdjustmentHints
::ReborrowOnly
,
1304 adjustment_hints_mode
: match self.data
.inlayHints_expressionAdjustmentHints_mode
{
1305 AdjustmentHintsModeDef
::Prefix
=> ide
::AdjustmentHintsMode
::Prefix
,
1306 AdjustmentHintsModeDef
::Postfix
=> ide
::AdjustmentHintsMode
::Postfix
,
1307 AdjustmentHintsModeDef
::PreferPrefix
=> ide
::AdjustmentHintsMode
::PreferPrefix
,
1308 AdjustmentHintsModeDef
::PreferPostfix
=> ide
::AdjustmentHintsMode
::PreferPostfix
,
1310 adjustment_hints_hide_outside_unsafe
: self
1312 .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe
,
1313 binding_mode_hints
: self.data
.inlayHints_bindingModeHints_enable
,
1314 param_names_for_lifetime_elision_hints
: self
1316 .inlayHints_lifetimeElisionHints_useParameterNames
,
1317 max_length
: self.data
.inlayHints_maxLength
,
1318 closing_brace_hints_min_lines
: if self.data
.inlayHints_closingBraceHints_enable
{
1319 Some(self.data
.inlayHints_closingBraceHints_minLines
)
1326 fn insert_use_config(&self) -> InsertUseConfig
{
1328 granularity
: match self.data
.imports_granularity_group
{
1329 ImportGranularityDef
::Preserve
=> ImportGranularity
::Preserve
,
1330 ImportGranularityDef
::Item
=> ImportGranularity
::Item
,
1331 ImportGranularityDef
::Crate
=> ImportGranularity
::Crate
,
1332 ImportGranularityDef
::Module
=> ImportGranularity
::Module
,
1334 enforce_granularity
: self.data
.imports_granularity_enforce
,
1335 prefix_kind
: match self.data
.imports_prefix
{
1336 ImportPrefixDef
::Plain
=> PrefixKind
::Plain
,
1337 ImportPrefixDef
::ByCrate
=> PrefixKind
::ByCrate
,
1338 ImportPrefixDef
::BySelf
=> PrefixKind
::BySelf
,
1340 group
: self.data
.imports_group_enable
,
1341 skip_glob_imports
: !self.data
.imports_merge_glob
,
1345 pub fn completion(&self) -> CompletionConfig
{
1347 enable_postfix_completions
: self.data
.completion_postfix_enable
,
1348 enable_imports_on_the_fly
: self.data
.completion_autoimport_enable
1349 && completion_item_edit_resolve(&self.caps
),
1350 enable_self_on_the_fly
: self.data
.completion_autoself_enable
,
1351 enable_private_editable
: self.data
.completion_privateEditable_enable
,
1352 callable
: match self.data
.completion_callable_snippets
{
1353 CallableCompletionDef
::FillArguments
=> Some(CallableSnippets
::FillArguments
),
1354 CallableCompletionDef
::AddParentheses
=> Some(CallableSnippets
::AddParentheses
),
1355 CallableCompletionDef
::None
=> None
,
1357 insert_use
: self.insert_use_config(),
1358 prefer_no_std
: self.data
.imports_prefer_no_std
,
1359 snippet_cap
: SnippetCap
::new(try_or_def
!(
1369 snippets
: self.snippets
.clone(),
1370 limit
: self.data
.completion_limit
,
1374 pub fn find_all_refs_exclude_imports(&self) -> bool
{
1375 self.data
.references_excludeImports
1378 pub fn snippet_cap(&self) -> bool
{
1379 self.experimental("snippetTextEdit")
1382 pub fn assist(&self) -> AssistConfig
{
1384 snippet_cap
: SnippetCap
::new(self.experimental("snippetTextEdit")),
1386 insert_use
: self.insert_use_config(),
1387 prefer_no_std
: self.data
.imports_prefer_no_std
,
1388 assist_emit_must_use
: self.data
.assist_emitMustUse
,
1392 pub fn join_lines(&self) -> JoinLinesConfig
{
1394 join_else_if
: self.data
.joinLines_joinElseIf
,
1395 remove_trailing_comma
: self.data
.joinLines_removeTrailingComma
,
1396 unwrap_trivial_blocks
: self.data
.joinLines_unwrapTrivialBlock
,
1397 join_assignments
: self.data
.joinLines_joinAssignments
,
1401 pub fn call_info(&self) -> CallInfoConfig
{
1403 params_only
: matches
!(self.data
.signatureInfo_detail
, SignatureDetail
::Parameters
),
1404 docs
: self.data
.signatureInfo_documentation_enable
,
1408 pub fn lens(&self) -> LensConfig
{
1410 run
: self.data
.lens_enable
&& self.data
.lens_run_enable
,
1411 debug
: self.data
.lens_enable
&& self.data
.lens_debug_enable
,
1412 implementations
: self.data
.lens_enable
&& self.data
.lens_implementations_enable
,
1413 method_refs
: self.data
.lens_enable
&& self.data
.lens_references_method_enable
,
1414 refs_adt
: self.data
.lens_enable
&& self.data
.lens_references_adt_enable
,
1415 refs_trait
: self.data
.lens_enable
&& self.data
.lens_references_trait_enable
,
1416 enum_variant_refs
: self.data
.lens_enable
1417 && self.data
.lens_references_enumVariant_enable
,
1418 location
: self.data
.lens_location
,
1422 pub fn hover_actions(&self) -> HoverActionsConfig
{
1423 let enable
= self.experimental("hoverActions") && self.data
.hover_actions_enable
;
1424 HoverActionsConfig
{
1425 implementations
: enable
&& self.data
.hover_actions_implementations_enable
,
1426 references
: enable
&& self.data
.hover_actions_references_enable
,
1427 run
: enable
&& self.data
.hover_actions_run_enable
,
1428 debug
: enable
&& self.data
.hover_actions_debug_enable
,
1429 goto_type_def
: enable
&& self.data
.hover_actions_gotoTypeDef_enable
,
1433 pub fn highlighting_config(&self) -> HighlightConfig
{
1435 strings
: self.data
.semanticHighlighting_strings_enable
,
1436 punctuation
: self.data
.semanticHighlighting_punctuation_enable
,
1437 specialize_punctuation
: self
1439 .semanticHighlighting_punctuation_specialization_enable
,
1440 macro_bang
: self.data
.semanticHighlighting_punctuation_separate_macro_bang
,
1441 operator
: self.data
.semanticHighlighting_operator_enable
,
1442 specialize_operator
: self.data
.semanticHighlighting_operator_specialization_enable
,
1443 inject_doc_comment
: self.data
.semanticHighlighting_doc_comment_inject_enable
,
1444 syntactic_name_ref_highlighting
: false,
1448 pub fn hover(&self) -> HoverConfig
{
1450 links_in_hover
: self.data
.hover_links_enable
,
1451 documentation
: self.data
.hover_documentation_enable
,
1453 let is_markdown
= try_or_def
!(self
1462 .contains(&MarkupKind
::Markdown
);
1464 HoverDocFormat
::Markdown
1466 HoverDocFormat
::PlainText
1469 keywords
: self.data
.hover_documentation_keywords_enable
,
1470 interpret_tests
: self.data
.interpret_tests
,
1474 pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig
{
1475 WorkspaceSymbolConfig
{
1476 search_scope
: match self.data
.workspace_symbol_search_scope
{
1477 WorkspaceSymbolSearchScopeDef
::Workspace
=> WorkspaceSymbolSearchScope
::Workspace
,
1478 WorkspaceSymbolSearchScopeDef
::WorkspaceAndDependencies
=> {
1479 WorkspaceSymbolSearchScope
::WorkspaceAndDependencies
1482 search_kind
: match self.data
.workspace_symbol_search_kind
{
1483 WorkspaceSymbolSearchKindDef
::OnlyTypes
=> WorkspaceSymbolSearchKind
::OnlyTypes
,
1484 WorkspaceSymbolSearchKindDef
::AllSymbols
=> WorkspaceSymbolSearchKind
::AllSymbols
,
1486 search_limit
: self.data
.workspace_symbol_search_limit
,
1490 pub fn semantic_tokens_refresh(&self) -> bool
{
1491 try_or_def
!(self.caps
.workspace
.as_ref()?
.semantic_tokens
.as_ref()?
.refresh_support?
)
1494 pub fn code_lens_refresh(&self) -> bool
{
1495 try_or_def
!(self.caps
.workspace
.as_ref()?
.code_lens
.as_ref()?
.refresh_support?
)
1498 pub fn inlay_hints_refresh(&self) -> bool
{
1499 try_or_def
!(self.caps
.workspace
.as_ref()?
.inlay_hint
.as_ref()?
.refresh_support?
)
1502 pub fn insert_replace_support(&self) -> bool
{
1511 .insert_replace_support?
1515 pub fn client_commands(&self) -> ClientCommandsConfig
{
1517 try_or
!(self.caps
.experimental
.as_ref()?
.get("commands")?
, &serde_json
::Value
::Null
);
1518 let commands
: Option
<lsp_ext
::ClientCommandOptions
> =
1519 serde_json
::from_value(commands
.clone()).ok();
1520 let force
= commands
.is_none() && self.data
.lens_forceCustomCommands
;
1521 let commands
= commands
.map(|it
| it
.commands
).unwrap_or_default();
1523 let get
= |name
: &str| commands
.iter().any(|it
| it
== name
) || force
;
1525 ClientCommandsConfig
{
1526 run_single
: get("rust-analyzer.runSingle"),
1527 debug_single
: get("rust-analyzer.debugSingle"),
1528 show_reference
: get("rust-analyzer.showReferences"),
1529 goto_location
: get("rust-analyzer.gotoLocation"),
1530 trigger_parameter_hints
: get("editor.action.triggerParameterHints"),
1534 pub fn highlight_related(&self) -> HighlightRelatedConfig
{
1535 HighlightRelatedConfig
{
1536 references
: self.data
.highlightRelated_references_enable
,
1537 break_points
: self.data
.highlightRelated_breakPoints_enable
,
1538 exit_points
: self.data
.highlightRelated_exitPoints_enable
,
1539 yield_points
: self.data
.highlightRelated_yieldPoints_enable
,
1543 pub fn prime_caches_num_threads(&self) -> u8 {
1544 match self.data
.cachePriming_numThreads
{
1545 0 => num_cpus
::get_physical().try_into().unwrap_or(u8::MAX
),
1550 pub fn main_loop_num_threads(&self) -> usize {
1551 self.data
.numThreads
.unwrap_or(num_cpus
::get_physical().try_into().unwrap_or(1))
1554 pub fn typing_autoclose_angle(&self) -> bool
{
1555 self.data
.typing_autoClosingAngleBrackets_enable
1558 // Deserialization definitions
1560 macro_rules
! create_bool_or_string_de
{
1561 ($ident
:ident
<$bool
:literal
, $string
:literal
>) => {
1562 fn $ident
<'de
, D
>(d
: D
) -> Result
<(), D
::Error
>
1564 D
: serde
::Deserializer
<'de
>,
1567 impl<'de
> serde
::de
::Visitor
<'de
> for V
{
1570 fn expecting(&self, formatter
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1571 formatter
.write_str(concat
!(
1574 stringify
!($string
),
1579 fn visit_bool
<E
>(self, v
: bool
) -> Result
<Self::Value
, E
>
1581 E
: serde
::de
::Error
,
1585 _
=> Err(serde
::de
::Error
::invalid_value(
1586 serde
::de
::Unexpected
::Bool(v
),
1592 fn visit_str
<E
>(self, v
: &str) -> Result
<Self::Value
, E
>
1594 E
: serde
::de
::Error
,
1598 _
=> Err(serde
::de
::Error
::invalid_value(
1599 serde
::de
::Unexpected
::Str(v
),
1605 fn visit_enum
<A
>(self, a
: A
) -> Result
<Self::Value
, A
::Error
>
1607 A
: serde
::de
::EnumAccess
<'de
>,
1609 use serde
::de
::VariantAccess
;
1610 let (variant
, va
) = a
.variant
::<&'de
str>()?
;
1614 _
=> Err(serde
::de
::Error
::invalid_value(
1615 serde
::de
::Unexpected
::Str(variant
),
1621 d
.deserialize_any(V
)
1625 create_bool_or_string_de
!(true_or_always
<true, "always">);
1626 create_bool_or_string_de
!(false_or_never
<false, "never">);
1628 macro_rules
! named_unit_variant
{
1629 ($variant
:ident
) => {
1630 pub(super) fn $variant
<'de
, D
>(deserializer
: D
) -> Result
<(), D
::Error
>
1632 D
: serde
::Deserializer
<'de
>,
1635 impl<'de
> serde
::de
::Visitor
<'de
> for V
{
1637 fn expecting(&self, f
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
1638 f
.write_str(concat
!("\"", stringify
!($variant
), "\""))
1640 fn visit_str
<E
: serde
::de
::Error
>(self, value
: &str) -> Result
<Self::Value
, E
> {
1641 if value
== stringify
!($variant
) {
1644 Err(E
::invalid_value(serde
::de
::Unexpected
::Str(value
), &self))
1648 deserializer
.deserialize_str(V
)
1654 named_unit_variant
!(all
);
1655 named_unit_variant
!(skip_trivial
);
1656 named_unit_variant
!(mutable
);
1657 named_unit_variant
!(reborrow
);
1658 named_unit_variant
!(fieldless
);
1659 named_unit_variant
!(with_block
);
1662 #[derive(Deserialize, Debug, Clone, Copy)]
1663 #[serde(rename_all = "snake_case")]
1664 enum SnippetScopeDef
{
1670 impl Default
for SnippetScopeDef
{
1671 fn default() -> Self {
1672 SnippetScopeDef
::Expr
1676 #[derive(Deserialize, Debug, Clone, Default)]
1679 #[serde(deserialize_with = "single_or_array")]
1680 prefix
: Vec
<String
>,
1681 #[serde(deserialize_with = "single_or_array")]
1682 postfix
: Vec
<String
>,
1683 description
: Option
<String
>,
1684 #[serde(deserialize_with = "single_or_array")]
1686 #[serde(deserialize_with = "single_or_array")]
1687 requires
: Vec
<String
>,
1688 scope
: SnippetScopeDef
,
1691 fn single_or_array
<'de
, D
>(deserializer
: D
) -> Result
<Vec
<String
>, D
::Error
>
1693 D
: serde
::Deserializer
<'de
>,
1697 impl<'de
> serde
::de
::Visitor
<'de
> for SingleOrVec
{
1698 type Value
= Vec
<String
>;
1700 fn expecting(&self, formatter
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
1701 formatter
.write_str("string or array of strings")
1704 fn visit_str
<E
>(self, value
: &str) -> Result
<Self::Value
, E
>
1706 E
: serde
::de
::Error
,
1708 Ok(vec
![value
.to_owned()])
1711 fn visit_seq
<A
>(self, seq
: A
) -> Result
<Self::Value
, A
::Error
>
1713 A
: serde
::de
::SeqAccess
<'de
>,
1715 Deserialize
::deserialize(serde
::de
::value
::SeqAccessDeserializer
::new(seq
))
1719 deserializer
.deserialize_any(SingleOrVec
)
1722 #[derive(Deserialize, Debug, Clone)]
1724 enum ManifestOrProjectJson
{
1726 ProjectJson(ProjectJsonData
),
1729 #[derive(Deserialize, Debug, Clone)]
1730 #[serde(rename_all = "snake_case")]
1731 enum ExprFillDefaultDef
{
1736 #[derive(Deserialize, Debug, Clone)]
1737 #[serde(rename_all = "snake_case")]
1738 enum ImportGranularityDef
{
1745 #[derive(Deserialize, Debug, Copy, Clone)]
1746 #[serde(rename_all = "snake_case")]
1747 enum CallableCompletionDef
{
1753 #[derive(Deserialize, Debug, Clone)]
1755 enum CargoFeaturesDef
{
1756 #[serde(deserialize_with = "de_unit_v::all")]
1758 Selected(Vec
<String
>),
1761 #[derive(Deserialize, Debug, Clone)]
1762 #[serde(rename_all = "snake_case")]
1763 enum InvocationStrategy
{
1768 #[derive(Deserialize, Debug, Clone)]
1769 struct CheckOnSaveTargets(#[serde(deserialize_with = "single_or_array")] Vec<String>);
1771 #[derive(Deserialize, Debug, Clone)]
1772 #[serde(rename_all = "snake_case")]
1773 enum InvocationLocation
{
1778 #[derive(Deserialize, Debug, Clone)]
1780 enum LifetimeElisionDef
{
1781 #[serde(deserialize_with = "true_or_always")]
1783 #[serde(deserialize_with = "false_or_never")]
1785 #[serde(deserialize_with = "de_unit_v::skip_trivial")]
1789 #[derive(Deserialize, Debug, Clone)]
1791 enum ClosureReturnTypeHintsDef
{
1792 #[serde(deserialize_with = "true_or_always")]
1794 #[serde(deserialize_with = "false_or_never")]
1796 #[serde(deserialize_with = "de_unit_v::with_block")]
1800 #[derive(Deserialize, Debug, Clone)]
1802 enum ReborrowHintsDef
{
1803 #[serde(deserialize_with = "true_or_always")]
1805 #[serde(deserialize_with = "false_or_never")]
1807 #[serde(deserialize_with = "de_unit_v::mutable")]
1811 #[derive(Deserialize, Debug, Clone)]
1813 enum AdjustmentHintsDef
{
1814 #[serde(deserialize_with = "true_or_always")]
1816 #[serde(deserialize_with = "false_or_never")]
1818 #[serde(deserialize_with = "de_unit_v::reborrow")]
1822 #[derive(Deserialize, Debug, Clone)]
1824 enum DiscriminantHintsDef
{
1825 #[serde(deserialize_with = "true_or_always")]
1827 #[serde(deserialize_with = "false_or_never")]
1829 #[serde(deserialize_with = "de_unit_v::fieldless")]
1833 #[derive(Deserialize, Debug, Clone)]
1834 #[serde(rename_all = "snake_case")]
1835 enum AdjustmentHintsModeDef
{
1842 #[derive(Deserialize, Debug, Clone)]
1843 #[serde(rename_all = "snake_case")]
1844 enum FilesWatcherDef
{
1850 #[derive(Deserialize, Debug, Clone)]
1851 #[serde(rename_all = "snake_case")]
1852 enum ImportPrefixDef
{
1854 #[serde(alias = "self")]
1856 #[serde(alias = "crate")]
1860 #[derive(Deserialize, Debug, Clone)]
1861 #[serde(rename_all = "snake_case")]
1862 enum WorkspaceSymbolSearchScopeDef
{
1864 WorkspaceAndDependencies
,
1867 #[derive(Deserialize, Debug, Clone)]
1868 #[serde(rename_all = "snake_case")]
1869 enum SignatureDetail
{
1874 #[derive(Deserialize, Debug, Clone)]
1875 #[serde(rename_all = "snake_case")]
1876 enum WorkspaceSymbolSearchKindDef
{
1881 macro_rules
! _config_data
{
1882 (struct $name
:ident
{
1884 $
(#[doc=$doc:literal])*
1885 $field
:ident $
(| $alias
:ident
)*: $ty
:ty
= $
default:expr
,
1888 #[allow(non_snake_case)]
1889 #[derive(Debug, Clone)]
1890 struct $name { $($field: $ty,)* }
1892 fn from_json(mut json
: serde_json
::Value
, error_sink
: &mut Vec
<(String
, serde_json
::Error
)>) -> $name
{
1898 None$
(.or(Some(stringify
!($alias
))))*,
1904 fn json_schema() -> serde_json
::Value
{
1907 let field
= stringify
!($field
);
1908 let ty
= stringify
!($ty
);
1910 (field
, ty
, &[$
($doc
),*], $
default)
1916 fn manual() -> String
{
1919 let field
= stringify
!($field
);
1920 let ty
= stringify
!($ty
);
1922 (field
, ty
, &[$
($doc
),*], $
default)
1929 fn fields_are_sorted() {
1930 [$
(stringify
!($field
)),*].windows(2).for_each(|w
| assert
!(w
[0] <= w
[1], "{} <= {} does not hold", w
[0], w
[1]));
1934 use _config_data
as config_data
;
1936 fn get_field
<T
: DeserializeOwned
>(
1937 json
: &mut serde_json
::Value
,
1938 error_sink
: &mut Vec
<(String
, serde_json
::Error
)>,
1939 field
: &'
static str,
1940 alias
: Option
<&'
static str>,
1943 // XXX: check alias first, to work-around the VS Code where it pre-fills the
1944 // defaults instead of sending an empty object.
1947 .chain(iter
::once(field
))
1948 .filter_map(move |field
| {
1949 let mut pointer
= field
.replace('_'
, "/");
1950 pointer
.insert(0, '
/'
);
1951 json
.pointer_mut(&pointer
)
1952 .map(|it
| serde_json
::from_value(it
.take()).map_err(|e
| (e
, pointer
)))
1954 .find(Result
::is_ok
)
1955 .and_then(|res
| match res
{
1957 Err((e
, pointer
)) => {
1958 tracing
::warn
!("Failed to deserialize config field at {}: {:?}", pointer
, e
);
1959 error_sink
.push((pointer
, e
));
1963 .unwrap_or_else(|| serde_json
::from_str(default).unwrap())
1966 fn schema(fields
: &[(&'
static str, &'
static str, &[&str], &str)]) -> serde_json
::Value
{
1969 .map(|(field
, ty
, doc
, default)| {
1970 let name
= field
.replace('_'
, ".");
1971 let name
= format
!("rust-analyzer.{name}");
1972 let props
= field_props(field
, ty
, doc
, default);
1975 .collect
::<serde_json
::Map
<_
, _
>>();
1979 fn field_props(field
: &str, ty
: &str, doc
: &[&str], default: &str) -> serde_json
::Value
{
1980 let doc
= doc_comment_to_string(doc
);
1981 let doc
= doc
.trim_end_matches('
\n'
);
1983 doc
.ends_with('
.'
) && doc
.starts_with(char::is_uppercase
),
1984 "bad docs for {field}: {doc:?}"
1986 let default = default.parse
::<serde_json
::Value
>().unwrap();
1988 let mut map
= serde_json
::Map
::default();
1990 ($
($key
:literal
: $value
:tt
),*$
(,)?
) => {{$
(
1991 map
.insert($key
.into(), serde_json
::json
!($value
));
1994 set
!("markdownDescription": doc
);
1995 set
!("default": default);
1998 "bool" => set
!("type": "boolean"),
1999 "usize" => set
!("type": "integer", "minimum": 0),
2000 "String" => set
!("type": "string"),
2001 "Vec<String>" => set
! {
2003 "items": { "type": "string" }
,
2005 "Vec<PathBuf>" => set
! {
2007 "items": { "type": "string" }
,
2009 "FxHashSet<String>" => set
! {
2011 "items": { "type": "string" }
,
2012 "uniqueItems": true,
2014 "FxHashMap<Box<str>, Box<[Box<str>]>>" => set
! {
2017 "FxHashMap<String, SnippetDef>" => set
! {
2020 "FxHashMap<String, String>" => set
! {
2023 "Option<usize>" => set
! {
2024 "type": ["null", "integer"],
2027 "Option<String>" => set
! {
2028 "type": ["null", "string"],
2030 "Option<PathBuf>" => set
! {
2031 "type": ["null", "string"],
2033 "Option<bool>" => set
! {
2034 "type": ["null", "boolean"],
2036 "Option<Vec<String>>" => set
! {
2037 "type": ["null", "array"],
2038 "items": { "type": "string" }
,
2040 "ExprFillDefaultDef" => set
! {
2042 "enum": ["todo", "default"],
2043 "enumDescriptions": [
2044 "Fill missing expressions with the `todo` macro",
2045 "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
2048 "ImportGranularityDef" => set
! {
2050 "enum": ["preserve", "crate", "module", "item"],
2051 "enumDescriptions": [
2052 "Do not change the granularity of any imports and preserve the original structure written by the developer.",
2053 "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
2054 "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
2055 "Flatten imports so that each has its own use statement."
2058 "ImportPrefixDef" => set
! {
2065 "enumDescriptions": [
2066 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
2067 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
2068 "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
2071 "Vec<ManifestOrProjectJson>" => set
! {
2073 "items": { "type": ["string", "object"] }
,
2075 "WorkspaceSymbolSearchScopeDef" => set
! {
2077 "enum": ["workspace", "workspace_and_dependencies"],
2078 "enumDescriptions": [
2079 "Search in current workspace only.",
2080 "Search in current workspace and dependencies."
2083 "WorkspaceSymbolSearchKindDef" => set
! {
2085 "enum": ["only_types", "all_symbols"],
2086 "enumDescriptions": [
2087 "Search for types only.",
2088 "Search for all symbols kinds."
2091 "ParallelCachePrimingNumThreads" => set
! {
2096 "LifetimeElisionDef" => set
! {
2103 "enumDescriptions": [
2104 "Always show lifetime elision hints.",
2105 "Never show lifetime elision hints.",
2106 "Only show lifetime elision hints if a return type is involved."
2109 "ClosureReturnTypeHintsDef" => set
! {
2116 "enumDescriptions": [
2117 "Always show type hints for return types of closures.",
2118 "Never show type hints for return types of closures.",
2119 "Only show type hints for return types of closures with blocks."
2122 "ReborrowHintsDef" => set
! {
2129 "enumDescriptions": [
2130 "Always show reborrow hints.",
2131 "Never show reborrow hints.",
2132 "Only show mutable reborrow hints."
2135 "AdjustmentHintsDef" => set
! {
2142 "enumDescriptions": [
2143 "Always show all adjustment hints.",
2144 "Never show adjustment hints.",
2145 "Only show auto borrow and dereference adjustment hints."
2148 "DiscriminantHintsDef" => set
! {
2155 "enumDescriptions": [
2156 "Always show all discriminant hints.",
2157 "Never show discriminant hints.",
2158 "Only show discriminant hints on fieldless enum variants."
2161 "AdjustmentHintsModeDef" => set
! {
2169 "enumDescriptions": [
2170 "Always show adjustment hints as prefix (`*expr`).",
2171 "Always show adjustment hints as postfix (`expr.*`).",
2172 "Show prefix or postfix depending on which uses less parenthesis, prefering prefix.",
2173 "Show prefix or postfix depending on which uses less parenthesis, prefering postfix.",
2176 "CargoFeaturesDef" => set
! {
2183 "enumDescriptions": [
2184 "Pass `--all-features` to cargo",
2189 "items": { "type": "string" }
2193 "Option<CargoFeaturesDef>" => set
! {
2200 "enumDescriptions": [
2201 "Pass `--all-features` to cargo",
2206 "items": { "type": "string" }
2211 "CallableCompletionDef" => set
! {
2218 "enumDescriptions": [
2219 "Add call parentheses and pre-fill arguments.",
2220 "Add call parentheses.",
2221 "Do no snippet completions for callables."
2224 "SignatureDetail" => set
! {
2226 "enum": ["full", "parameters"],
2227 "enumDescriptions": [
2228 "Show the entire signature.",
2229 "Show only the parameters."
2232 "FilesWatcherDef" => set
! {
2234 "enum": ["client", "server"],
2235 "enumDescriptions": [
2236 "Use the client (editor) to watch files for changes",
2237 "Use server-side file watching",
2240 "AnnotationLocation" => set
! {
2242 "enum": ["above_name", "above_whole_item"],
2243 "enumDescriptions": [
2244 "Render annotations above the name of the item.",
2245 "Render annotations above the whole item, including documentation comments and attributes."
2248 "InvocationStrategy" => set
! {
2250 "enum": ["per_workspace", "once"],
2251 "enumDescriptions": [
2252 "The command will be executed for each workspace.",
2253 "The command will be executed once."
2256 "InvocationLocation" => set
! {
2258 "enum": ["workspace", "root"],
2259 "enumDescriptions": [
2260 "The command will be executed in the corresponding workspace root.",
2261 "The command will be executed in the project root."
2264 "Option<CheckOnSaveTargets>" => set
! {
2274 "items": { "type": "string" }
2278 _
=> panic
!("missing entry for {ty}: {default}"),
2285 fn manual(fields
: &[(&'
static str, &'
static str, &[&str], &str)]) -> String
{
2288 .map(|(field
, _ty
, doc
, default)| {
2289 let name
= format
!("rust-analyzer.{}", field
.replace('_'
, "."));
2290 let doc
= doc_comment_to_string(doc
);
2291 if default.contains('
\n'
) {
2293 r
#"[[{name}]]{name}::
2305 format
!("[[{name}]]{name} (default: `{default}`)::\n+\n--\n{doc}--\n")
2308 .collect
::<String
>()
2311 fn doc_comment_to_string(doc
: &[&str]) -> String
{
2312 doc
.iter().map(|it
| it
.strip_prefix(' '
).unwrap_or(it
)).map(|it
| format
!("{it}\n")).collect()
2319 use test_utils
::{ensure_file_contents, project_root}
;
2324 fn generate_package_json_config() {
2325 let s
= Config
::json_schema();
2326 let schema
= format
!("{s:#}");
2327 let mut schema
= schema
2328 .trim_start_matches('
{'
)
2329 .trim_end_matches('
}'
)
2331 .replace('
\n'
, "\n ")
2332 .trim_start_matches('
\n'
)
2335 schema
.push_str(",\n");
2337 // Transform the asciidoc form link to markdown style.
2339 // https://link[text] => [text](https://link)
2340 let url_matches
= schema
.match_indices("https://");
2341 let mut url_offsets
= url_matches
.map(|(idx
, _
)| idx
).collect
::<Vec
<usize>>();
2342 url_offsets
.reverse();
2343 for idx
in url_offsets
{
2344 let link
= &schema
[idx
..];
2345 // matching on whitespace to ignore normal links
2346 if let Some(link_end
) = link
.find(|c
| c
== ' '
|| c
== '
['
) {
2347 if link
.chars().nth(link_end
) == Some('
['
) {
2348 if let Some(link_text_end
) = link
.find('
]'
) {
2349 let link_text
= link
[link_end
..(link_text_end
+ 1)].to_string();
2351 schema
.replace_range((idx
+ link_end
)..(idx
+ link_text_end
+ 1), "");
2352 schema
.insert(idx
, '
('
);
2353 schema
.insert(idx
+ link_end
+ 1, '
)'
);
2354 schema
.insert_str(idx
, &link_text
);
2360 let package_json_path
= project_root().join("editors/code/package.json");
2361 let mut package_json
= fs
::read_to_string(&package_json_path
).unwrap();
2363 let start_marker
= " \"$generated-start\": {},\n";
2364 let end_marker
= " \"$generated-end\": {}\n";
2366 let start
= package_json
.find(start_marker
).unwrap() + start_marker
.len();
2367 let end
= package_json
.find(end_marker
).unwrap();
2369 let p
= remove_ws(&package_json
[start
..end
]);
2370 let s
= remove_ws(&schema
);
2371 if !p
.contains(&s
) {
2372 package_json
.replace_range(start
..end
, &schema
);
2373 ensure_file_contents(&package_json_path
, &package_json
)
2378 fn generate_config_documentation() {
2379 let docs_path
= project_root().join("docs/user/generated_config.adoc");
2380 let expected
= ConfigData
::manual();
2381 ensure_file_contents(&docs_path
, &expected
);
2384 fn remove_ws(text
: &str) -> String
{
2385 text
.replace(char::is_whitespace
, "")