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
, RustcSource
,
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, supports_utf8, 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 environment variables that will be set when running cargo, rustc
105 /// or other commands within the workspace. Useful for setting RUSTFLAGS.
106 cargo_extraEnv
: FxHashMap
<String
, String
> = "{}",
107 /// List of features to activate.
109 /// Set this to `"all"` to pass `--all-features` to cargo.
110 cargo_features
: CargoFeaturesDef
= "[]",
111 /// Whether to pass `--no-default-features` to cargo.
112 cargo_noDefaultFeatures
: bool
= "false",
113 /// Relative path to the sysroot, or "discover" to try to automatically find it via
114 /// "rustc --print sysroot".
116 /// Unsetting this disables sysroot loading.
118 /// This option does not take effect until rust-analyzer is restarted.
119 cargo_sysroot
: Option
<String
> = "\"discover\"",
120 /// Compilation target override (target triple).
121 // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
122 // than `checkOnSave_target`
123 cargo_target
: Option
<String
> = "null",
124 /// Unsets `#[cfg(test)]` for the specified crates.
125 cargo_unsetTest
: Vec
<String
> = "[\"core\"]",
127 /// Check all targets and tests (`--all-targets`).
128 checkOnSave_allTargets
: bool
= "true",
129 /// Cargo command to use for `cargo check`.
130 checkOnSave_command
: String
= "\"check\"",
131 /// Run specified `cargo check` command for diagnostics on save.
132 checkOnSave_enable
: bool
= "true",
133 /// Extra arguments for `cargo check`.
134 checkOnSave_extraArgs
: Vec
<String
> = "[]",
135 /// Extra environment variables that will be set when running `cargo check`.
136 /// Extends `#rust-analyzer.cargo.extraEnv#`.
137 checkOnSave_extraEnv
: FxHashMap
<String
, String
> = "{}",
138 /// List of features to activate. Defaults to
139 /// `#rust-analyzer.cargo.features#`.
141 /// Set to `"all"` to pass `--all-features` to Cargo.
142 checkOnSave_features
: Option
<CargoFeaturesDef
> = "null",
143 /// Specifies the working directory for running checks.
144 /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories.
145 // FIXME: Ideally we would support this in some way
146 /// This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
147 /// - "root": run checks in the project's root directory.
148 /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
150 checkOnSave_invocationLocation
: InvocationLocation
= "\"workspace\"",
151 /// Specifies the invocation strategy to use when running the checkOnSave command.
152 /// If `per_workspace` is set, the command will be executed for each workspace.
153 /// If `once` is set, the command will be executed once.
154 /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
156 checkOnSave_invocationStrategy
: InvocationStrategy
= "\"per_workspace\"",
157 /// Whether to pass `--no-default-features` to Cargo. Defaults to
158 /// `#rust-analyzer.cargo.noDefaultFeatures#`.
159 checkOnSave_noDefaultFeatures
: Option
<bool
> = "null",
160 /// Override the command rust-analyzer uses instead of `cargo check` for
161 /// diagnostics on save. The command is required to output json and
162 /// should therefore include `--message-format=json` or a similar option.
164 /// If you're changing this because you're using some tool wrapping
165 /// Cargo, you might also want to change
166 /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`.
168 /// If there are multiple linked projects, this command is invoked for
169 /// each of them, with the working directory being the project root
170 /// (i.e., the folder containing the `Cargo.toml`).
172 /// An example command would be:
175 /// cargo check --workspace --message-format=json --all-targets
178 checkOnSave_overrideCommand
: Option
<Vec
<String
>> = "null",
179 /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.
181 /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g.
182 /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`.
184 /// Aliased as `"checkOnSave.targets"`.
185 checkOnSave_target
| checkOnSave_targets
: CheckOnSaveTargets
= "[]",
187 /// Toggles the additional completions that automatically add imports when completed.
188 /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
189 completion_autoimport_enable
: bool
= "true",
190 /// Toggles the additional completions that automatically show method calls and field accesses
191 /// with `self` prefixed to them when inside a method.
192 completion_autoself_enable
: bool
= "true",
193 /// Whether to add parenthesis and argument snippets when completing function.
194 completion_callable_snippets
: CallableCompletionDef
= "\"fill_arguments\"",
195 /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
196 completion_postfix_enable
: bool
= "true",
197 /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
198 completion_privateEditable_enable
: bool
= "false",
199 /// Custom completion snippets.
200 // NOTE: Keep this list in sync with the feature docs of user snippets.
201 completion_snippets_custom
: FxHashMap
<String
, SnippetDef
> = r
#"{
204 "body": "Arc::new(${receiver})",
205 "requires": "std::sync::Arc",
206 "description": "Put the expression into an `Arc`",
211 "body": "Rc::new(${receiver})",
212 "requires": "std::rc::Rc",
213 "description": "Put the expression into an `Rc`",
218 "body": "Box::pin(${receiver})",
219 "requires": "std::boxed::Box",
220 "description": "Put the expression into a pinned `Box`",
225 "body": "Ok(${receiver})",
226 "description": "Wrap the expression in a `Result::Ok`",
231 "body": "Err(${receiver})",
232 "description": "Wrap the expression in a `Result::Err`",
237 "body": "Some(${receiver})",
238 "description": "Wrap the expression in an `Option::Some`",
243 /// List of rust-analyzer diagnostics to disable.
244 diagnostics_disabled
: FxHashSet
<String
> = "[]",
245 /// Whether to show native rust-analyzer diagnostics.
246 diagnostics_enable
: bool
= "true",
247 /// Whether to show experimental rust-analyzer diagnostics that might
248 /// have more false positives than usual.
249 diagnostics_experimental_enable
: bool
= "false",
250 /// Map of prefixes to be substituted when parsing diagnostic file paths.
251 /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.
252 diagnostics_remapPrefix
: FxHashMap
<String
, String
> = "{}",
253 /// List of warnings that should be displayed with hint severity.
255 /// The warnings will be indicated by faded text or three dots in code
256 /// and will not show up in the `Problems Panel`.
257 diagnostics_warningsAsHint
: Vec
<String
> = "[]",
258 /// List of warnings that should be displayed with info severity.
260 /// The warnings will be indicated by a blue squiggly underline in code
261 /// and a blue icon in the `Problems Panel`.
262 diagnostics_warningsAsInfo
: Vec
<String
> = "[]",
264 /// These directories will be ignored by rust-analyzer. They are
265 /// relative to the workspace root, and globs are not supported. You may
266 /// also need to add the folders to Code's `files.watcherExclude`.
267 files_excludeDirs
: Vec
<PathBuf
> = "[]",
268 /// Controls file watching implementation.
269 files_watcher
: FilesWatcherDef
= "\"client\"",
271 /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
272 highlightRelated_breakPoints_enable
: bool
= "true",
273 /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
274 highlightRelated_exitPoints_enable
: bool
= "true",
275 /// Enables highlighting of related references while the cursor is on any identifier.
276 highlightRelated_references_enable
: bool
= "true",
277 /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
278 highlightRelated_yieldPoints_enable
: bool
= "true",
280 /// Whether to show `Debug` action. Only applies when
281 /// `#rust-analyzer.hover.actions.enable#` is set.
282 hover_actions_debug_enable
: bool
= "true",
283 /// Whether to show HoverActions in Rust files.
284 hover_actions_enable
: bool
= "true",
285 /// Whether to show `Go to Type Definition` action. Only applies when
286 /// `#rust-analyzer.hover.actions.enable#` is set.
287 hover_actions_gotoTypeDef_enable
: bool
= "true",
288 /// Whether to show `Implementations` action. Only applies when
289 /// `#rust-analyzer.hover.actions.enable#` is set.
290 hover_actions_implementations_enable
: bool
= "true",
291 /// Whether to show `References` action. Only applies when
292 /// `#rust-analyzer.hover.actions.enable#` is set.
293 hover_actions_references_enable
: bool
= "false",
294 /// Whether to show `Run` action. Only applies when
295 /// `#rust-analyzer.hover.actions.enable#` is set.
296 hover_actions_run_enable
: bool
= "true",
298 /// Whether to show documentation on hover.
299 hover_documentation_enable
: bool
= "true",
300 /// Whether to show keyword hover popups. Only applies when
301 /// `#rust-analyzer.hover.documentation.enable#` is set.
302 hover_documentation_keywords_enable
: bool
= "true",
303 /// Use markdown syntax for links in hover.
304 hover_links_enable
: bool
= "true",
306 /// 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.
307 imports_granularity_enforce
: bool
= "false",
308 /// How imports should be grouped into use statements.
309 imports_granularity_group
: ImportGranularityDef
= "\"crate\"",
310 /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
311 imports_group_enable
: bool
= "true",
312 /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
313 imports_merge_glob
: bool
= "true",
314 /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
315 imports_prefer_no_std
: bool
= "false",
316 /// The path structure for newly inserted paths to use.
317 imports_prefix
: ImportPrefixDef
= "\"plain\"",
319 /// Whether to show inlay type hints for binding modes.
320 inlayHints_bindingModeHints_enable
: bool
= "false",
321 /// Whether to show inlay type hints for method chains.
322 inlayHints_chainingHints_enable
: bool
= "true",
323 /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
324 inlayHints_closingBraceHints_enable
: bool
= "true",
325 /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
326 /// to always show them).
327 inlayHints_closingBraceHints_minLines
: usize = "25",
328 /// Whether to show inlay type hints for return types of closures.
329 inlayHints_closureReturnTypeHints_enable
: ClosureReturnTypeHintsDef
= "\"never\"",
330 /// Whether to show inlay hints for type adjustments.
331 inlayHints_expressionAdjustmentHints_enable
: AdjustmentHintsDef
= "\"never\"",
332 /// Whether to show inlay type hints for elided lifetimes in function signatures.
333 inlayHints_lifetimeElisionHints_enable
: LifetimeElisionDef
= "\"never\"",
334 /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
335 inlayHints_lifetimeElisionHints_useParameterNames
: bool
= "false",
336 /// Maximum length for inlay hints. Set to null to have an unlimited length.
337 inlayHints_maxLength
: Option
<usize> = "25",
338 /// Whether to show function parameter name inlay hints at the call
340 inlayHints_parameterHints_enable
: bool
= "true",
341 /// Whether to show inlay hints for compiler inserted reborrows.
342 /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
343 inlayHints_reborrowHints_enable
: ReborrowHintsDef
= "\"never\"",
344 /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
345 inlayHints_renderColons
: bool
= "true",
346 /// Whether to show inlay type hints for variables.
347 inlayHints_typeHints_enable
: bool
= "true",
348 /// Whether to hide inlay type hints for `let` statements that initialize to a closure.
349 /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
350 inlayHints_typeHints_hideClosureInitialization
: bool
= "false",
351 /// Whether to hide inlay type hints for constructors.
352 inlayHints_typeHints_hideNamedConstructor
: bool
= "false",
354 /// Join lines merges consecutive declaration and initialization of an assignment.
355 joinLines_joinAssignments
: bool
= "true",
356 /// Join lines inserts else between consecutive ifs.
357 joinLines_joinElseIf
: bool
= "true",
358 /// Join lines removes trailing commas.
359 joinLines_removeTrailingComma
: bool
= "true",
360 /// Join lines unwraps trivial blocks.
361 joinLines_unwrapTrivialBlock
: bool
= "true",
364 /// Whether to show `Debug` lens. Only applies when
365 /// `#rust-analyzer.lens.enable#` is set.
366 lens_debug_enable
: bool
= "true",
367 /// Whether to show CodeLens in Rust files.
368 lens_enable
: bool
= "true",
369 /// Internal config: use custom client-side commands even when the
370 /// client doesn't set the corresponding capability.
371 lens_forceCustomCommands
: bool
= "true",
372 /// Whether to show `Implementations` lens. Only applies when
373 /// `#rust-analyzer.lens.enable#` is set.
374 lens_implementations_enable
: bool
= "true",
375 /// Where to render annotations.
376 lens_location
: AnnotationLocation
= "\"above_name\"",
377 /// Whether to show `References` lens for Struct, Enum, and Union.
378 /// Only applies when `#rust-analyzer.lens.enable#` is set.
379 lens_references_adt_enable
: bool
= "false",
380 /// Whether to show `References` lens for Enum Variants.
381 /// Only applies when `#rust-analyzer.lens.enable#` is set.
382 lens_references_enumVariant_enable
: bool
= "false",
383 /// Whether to show `Method References` lens. Only applies when
384 /// `#rust-analyzer.lens.enable#` is set.
385 lens_references_method_enable
: bool
= "false",
386 /// Whether to show `References` lens for Trait.
387 /// Only applies when `#rust-analyzer.lens.enable#` is set.
388 lens_references_trait_enable
: bool
= "false",
389 /// Whether to show `Run` lens. Only applies when
390 /// `#rust-analyzer.lens.enable#` is set.
391 lens_run_enable
: bool
= "true",
393 /// Disable project auto-discovery in favor of explicitly specified set
396 /// Elements must be paths pointing to `Cargo.toml`,
397 /// `rust-project.json`, or JSON objects in `rust-project.json` format.
398 linkedProjects
: Vec
<ManifestOrProjectJson
> = "[]",
400 /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
401 lru_capacity
: Option
<usize> = "null",
403 /// Whether to show `can't find Cargo.toml` error message.
404 notifications_cargoTomlNotFound
: bool
= "true",
406 /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
407 procMacro_attributes_enable
: bool
= "true",
408 /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
409 procMacro_enable
: bool
= "true",
410 /// These proc-macros will be ignored when trying to expand them.
412 /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
413 procMacro_ignored
: FxHashMap
<Box
<str>, Box
<[Box
<str>]>> = "{}",
414 /// Internal config, path to proc-macro server executable (typically,
415 /// this is rust-analyzer itself, but we override this in tests).
416 procMacro_server
: Option
<PathBuf
> = "null",
418 /// Exclude imports from find-all-references.
419 references_excludeImports
: bool
= "false",
421 /// Command to be executed instead of 'cargo' for runnables.
422 runnables_command
: Option
<String
> = "null",
423 /// Additional arguments to be passed to cargo for runnables such as
424 /// tests or binaries. For example, it may be `--release`.
425 runnables_extraArgs
: Vec
<String
> = "[]",
427 /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
428 /// projects, or "discover" to try to automatically find it if the `rustc-dev` component
431 /// Any project which uses rust-analyzer with the rustcPrivate
432 /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
434 /// This option does not take effect until rust-analyzer is restarted.
435 rustc_source
: Option
<String
> = "null",
437 /// Additional arguments to `rustfmt`.
438 rustfmt_extraArgs
: Vec
<String
> = "[]",
439 /// Advanced option, fully override the command rust-analyzer uses for
441 rustfmt_overrideCommand
: Option
<Vec
<String
>> = "null",
442 /// Enables the use of rustfmt's unstable range formatting command for the
443 /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only
444 /// available on a nightly build.
445 rustfmt_rangeFormatting_enable
: bool
= "false",
447 /// Inject additional highlighting into doc comments.
449 /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
451 semanticHighlighting_doc_comment_inject_enable
: bool
= "true",
452 /// Use semantic tokens for operators.
454 /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
455 /// they are tagged with modifiers.
456 semanticHighlighting_operator_enable
: bool
= "true",
457 /// Use specialized semantic tokens for operators.
459 /// When enabled, rust-analyzer will emit special token types for operator tokens instead
460 /// of the generic `operator` token type.
461 semanticHighlighting_operator_specialization_enable
: bool
= "false",
462 /// Use semantic tokens for punctuations.
464 /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
465 /// they are tagged with modifiers or have a special role.
466 semanticHighlighting_punctuation_enable
: bool
= "false",
467 /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
469 semanticHighlighting_punctuation_separate_macro_bang
: bool
= "false",
470 /// Use specialized semantic tokens for punctuations.
472 /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead
473 /// of the generic `punctuation` token type.
474 semanticHighlighting_punctuation_specialization_enable
: bool
= "false",
475 /// Use semantic tokens for strings.
477 /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
478 /// By disabling semantic tokens for strings, other grammars can be used to highlight
480 semanticHighlighting_strings_enable
: bool
= "true",
482 /// Show full signature of the callable. Only shows parameters if disabled.
483 signatureInfo_detail
: SignatureDetail
= "\"full\"",
484 /// Show documentation.
485 signatureInfo_documentation_enable
: bool
= "true",
487 /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
488 typing_autoClosingAngleBrackets_enable
: bool
= "false",
490 /// Workspace symbol search kind.
491 workspace_symbol_search_kind
: WorkspaceSymbolSearchKindDef
= "\"only_types\"",
492 /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
493 /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
494 /// Other clients requires all results upfront and might require a higher limit.
495 workspace_symbol_search_limit
: usize = "128",
496 /// Workspace symbol search scope.
497 workspace_symbol_search_scope
: WorkspaceSymbolSearchScopeDef
= "\"workspace\"",
501 impl Default
for ConfigData
{
502 fn default() -> Self {
503 ConfigData
::from_json(serde_json
::Value
::Null
, &mut Vec
::new())
507 #[derive(Debug, Clone)]
509 pub discovered_projects
: Option
<Vec
<ProjectManifest
>>,
510 caps
: lsp_types
::ClientCapabilities
,
511 root_path
: AbsPathBuf
,
513 detached_files
: Vec
<AbsPathBuf
>,
514 snippets
: Vec
<Snippet
>,
517 type ParallelCachePrimingNumThreads
= u8;
519 #[derive(Debug, Clone, Eq, PartialEq)]
520 pub enum LinkedProject
{
521 ProjectManifest(ProjectManifest
),
522 InlineJsonProject(ProjectJson
),
525 impl From
<ProjectManifest
> for LinkedProject
{
526 fn from(v
: ProjectManifest
) -> Self {
527 LinkedProject
::ProjectManifest(v
)
531 impl From
<ProjectJson
> for LinkedProject
{
532 fn from(v
: ProjectJson
) -> Self {
533 LinkedProject
::InlineJsonProject(v
)
537 pub struct CallInfoConfig
{
538 pub params_only
: bool
,
542 #[derive(Clone, Debug, PartialEq, Eq)]
543 pub struct LensConfig
{
549 pub implementations
: bool
,
552 pub method_refs
: bool
,
553 pub refs_adt
: bool
, // for Struct, Enum, Union and Trait
554 pub refs_trait
: bool
, // for Struct, Enum, Union and Trait
555 pub enum_variant_refs
: bool
,
558 pub location
: AnnotationLocation
,
561 #[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
562 #[serde(rename_all = "snake_case")]
563 pub enum AnnotationLocation
{
568 impl From
<AnnotationLocation
> for ide
::AnnotationLocation
{
569 fn from(location
: AnnotationLocation
) -> Self {
571 AnnotationLocation
::AboveName
=> ide
::AnnotationLocation
::AboveName
,
572 AnnotationLocation
::AboveWholeItem
=> ide
::AnnotationLocation
::AboveWholeItem
,
578 pub fn any(&self) -> bool
{
581 || self.implementations
585 || self.enum_variant_refs
588 pub fn none(&self) -> bool
{
592 pub fn runnable(&self) -> bool
{
593 self.run
|| self.debug
596 pub fn references(&self) -> bool
{
597 self.method_refs
|| self.refs_adt
|| self.refs_trait
|| self.enum_variant_refs
601 #[derive(Clone, Debug, PartialEq, Eq)]
602 pub struct HoverActionsConfig
{
603 pub implementations
: bool
,
604 pub references
: bool
,
607 pub goto_type_def
: bool
,
610 impl HoverActionsConfig
{
611 pub const NO_ACTIONS
: Self = Self {
612 implementations
: false,
616 goto_type_def
: false,
619 pub fn any(&self) -> bool
{
620 self.implementations
|| self.references
|| self.runnable() || self.goto_type_def
623 pub fn none(&self) -> bool
{
627 pub fn runnable(&self) -> bool
{
628 self.run
|| self.debug
632 #[derive(Debug, Clone)]
633 pub struct FilesConfig
{
634 pub watcher
: FilesWatcher
,
635 pub exclude
: Vec
<AbsPathBuf
>,
638 #[derive(Debug, Clone)]
639 pub enum FilesWatcher
{
644 #[derive(Debug, Clone)]
645 pub struct NotificationsConfig
{
646 pub cargo_toml_not_found
: bool
,
649 #[derive(Debug, Clone)]
650 pub enum RustfmtConfig
{
651 Rustfmt { extra_args: Vec<String>, enable_range_formatting: bool }
,
652 CustomCommand { command: String, args: Vec<String> }
,
655 /// Configuration for runnable items, such as `main` function or tests.
656 #[derive(Debug, Clone)]
657 pub struct RunnablesConfig
{
658 /// Custom command to be executed instead of `cargo` for runnables.
659 pub override_cargo
: Option
<String
>,
660 /// Additional arguments for the `cargo`, e.g. `--release`.
661 pub cargo_extra_args
: Vec
<String
>,
664 /// Configuration for workspace symbol search requests.
665 #[derive(Debug, Clone)]
666 pub struct WorkspaceSymbolConfig
{
667 /// In what scope should the symbol be searched in.
668 pub search_scope
: WorkspaceSymbolSearchScope
,
669 /// What kind of symbol is being searched for.
670 pub search_kind
: WorkspaceSymbolSearchKind
,
671 /// How many items are returned at most.
672 pub search_limit
: usize,
675 pub struct ClientCommandsConfig
{
676 pub run_single
: bool
,
677 pub debug_single
: bool
,
678 pub show_reference
: bool
,
679 pub goto_location
: bool
,
680 pub trigger_parameter_hints
: bool
,
684 pub struct ConfigUpdateError
{
685 errors
: Vec
<(String
, serde_json
::Error
)>,
688 impl fmt
::Display
for ConfigUpdateError
{
689 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
690 let errors
= self.errors
.iter().format_with("\n", |(key
, e
), f
| {
697 "rust-analyzer found {} invalid config value{}:\n{}",
699 if self.errors
.len() == 1 { "" }
else { "s" }
,
706 pub fn new(root_path
: AbsPathBuf
, caps
: ClientCapabilities
) -> Self {
709 data
: ConfigData
::default(),
710 detached_files
: Vec
::new(),
711 discovered_projects
: None
,
713 snippets
: Default
::default(),
717 pub fn update(&mut self, mut json
: serde_json
::Value
) -> Result
<(), ConfigUpdateError
> {
718 tracing
::info
!("updating config from JSON: {:#}", json
);
719 if json
.is_null() || json
.as_object().map_or(false, |it
| it
.is_empty()) {
722 let mut errors
= Vec
::new();
723 self.detached_files
=
724 get_field
::<Vec
<PathBuf
>>(&mut json
, &mut errors
, "detachedFiles", None
, "[]")
726 .map(AbsPathBuf
::assert
)
728 patch_old_style
::patch_json_for_outdated_configs(&mut json
);
729 self.data
= ConfigData
::from_json(json
, &mut errors
);
730 tracing
::debug
!("deserialized config data: {:#?}", self.data
);
731 self.snippets
.clear();
732 for (name
, def
) in self.data
.completion_snippets_custom
.iter() {
733 if def
.prefix
.is_empty() && def
.postfix
.is_empty() {
736 let scope
= match def
.scope
{
737 SnippetScopeDef
::Expr
=> SnippetScope
::Expr
,
738 SnippetScopeDef
::Type
=> SnippetScope
::Type
,
739 SnippetScopeDef
::Item
=> SnippetScope
::Item
,
745 def
.description
.as_ref().unwrap_or(name
),
749 Some(snippet
) => self.snippets
.push(snippet
),
750 None
=> errors
.push((
751 format
!("snippet {name} is invalid"),
752 <serde_json
::Error
as serde
::de
::Error
>::custom(
753 "snippet path is invalid or triggers are missing",
759 self.validate(&mut errors
);
761 if errors
.is_empty() {
764 Err(ConfigUpdateError { errors }
)
768 fn validate(&self, error_sink
: &mut Vec
<(String
, serde_json
::Error
)>) {
769 use serde
::de
::Error
;
770 if self.data
.checkOnSave_command
.is_empty() {
772 "/checkOnSave/command".to_string(),
773 serde_json
::Error
::custom("expected a non-empty string"),
778 pub fn json_schema() -> serde_json
::Value
{
779 ConfigData
::json_schema()
782 pub fn root_path(&self) -> &AbsPathBuf
{
786 pub fn caps(&self) -> &lsp_types
::ClientCapabilities
{
790 pub fn detached_files(&self) -> &[AbsPathBuf
] {
797 || -> _ { Some($expr) }
()
800 macro_rules
! try_or
{
801 ($expr
:expr
, $or
:expr
) => {
802 try_
!($expr
).unwrap_or($or
)
806 macro_rules
! try_or_def
{
808 try_
!($expr
).unwrap_or_default()
813 pub fn linked_projects(&self) -> Vec
<LinkedProject
> {
814 match self.data
.linkedProjects
.as_slice() {
815 [] => match self.discovered_projects
.as_ref() {
816 Some(discovered_projects
) => {
817 let exclude_dirs
: Vec
<_
> = self
821 .map(|p
| self.root_path
.join(p
))
826 let (ProjectManifest
::ProjectJson(path
)
827 | ProjectManifest
::CargoToml(path
)) = p
;
828 !exclude_dirs
.iter().any(|p
| path
.starts_with(p
))
831 .map(LinkedProject
::from
)
836 linked_projects
=> linked_projects
838 .filter_map(|linked_project
| match linked_project
{
839 ManifestOrProjectJson
::Manifest(it
) => {
840 let path
= self.root_path
.join(it
);
841 ProjectManifest
::from_manifest_file(path
)
842 .map_err(|e
| tracing
::error
!("failed to load linked project: {}", e
))
846 ManifestOrProjectJson
::ProjectJson(it
) => {
847 Some(ProjectJson
::new(&self.root_path
, it
.clone()).into())
854 pub fn did_save_text_document_dynamic_registration(&self) -> bool
{
855 let caps
= try_or_def
!(self.caps
.text_document
.as_ref()?
.synchronization
.clone()?
);
856 caps
.did_save
== Some(true) && caps
.dynamic_registration
== Some(true)
859 pub fn did_change_watched_files_dynamic_registration(&self) -> bool
{
861 self.caps
.workspace
.as_ref()?
.did_change_watched_files
.as_ref()?
.dynamic_registration?
865 pub fn prefill_caches(&self) -> bool
{
866 self.data
.cachePriming_enable
869 pub fn location_link(&self) -> bool
{
870 try_or_def
!(self.caps
.text_document
.as_ref()?
.definition?
.link_support?
)
873 pub fn line_folding_only(&self) -> bool
{
874 try_or_def
!(self.caps
.text_document
.as_ref()?
.folding_range
.as_ref()?
.line_folding_only?
)
877 pub fn hierarchical_symbols(&self) -> bool
{
884 .hierarchical_document_symbol_support?
888 pub fn code_action_literals(&self) -> bool
{
895 .code_action_literal_support
900 pub fn work_done_progress(&self) -> bool
{
901 try_or_def
!(self.caps
.window
.as_ref()?
.work_done_progress?
)
904 pub fn will_rename(&self) -> bool
{
905 try_or_def
!(self.caps
.workspace
.as_ref()?
.file_operations
.as_ref()?
.will_rename?
)
908 pub fn change_annotation_support(&self) -> bool
{
915 .change_annotation_support
920 pub fn code_action_resolve(&self) -> bool
{
932 .any(|it
| it
== "edit")
935 pub fn signature_help_label_offsets(&self) -> bool
{
942 .signature_information
944 .parameter_information
946 .label_offset_support?
950 pub fn completion_label_details_support(&self) -> bool
{
959 .label_details_support
964 pub fn position_encoding(&self) -> PositionEncoding
{
965 if supports_utf8(&self.caps
) {
966 PositionEncoding
::Utf8
968 PositionEncoding
::Utf16
972 fn experimental(&self, index
: &'
static str) -> bool
{
973 try_or_def
!(self.caps
.experimental
.as_ref()?
.get(index
)?
.as_bool()?
)
976 pub fn code_action_group(&self) -> bool
{
977 self.experimental("codeActionGroup")
980 pub fn server_status_notification(&self) -> bool
{
981 self.experimental("serverStatusNotification")
984 pub fn publish_diagnostics(&self) -> bool
{
985 self.data
.diagnostics_enable
988 pub fn diagnostics(&self) -> DiagnosticsConfig
{
990 proc_attr_macros_enabled
: self.expand_proc_attr_macros(),
991 proc_macros_enabled
: self.data
.procMacro_enable
,
992 disable_experimental
: !self.data
.diagnostics_experimental_enable
,
993 disabled
: self.data
.diagnostics_disabled
.clone(),
994 expr_fill_default
: match self.data
.assist_expressionFillDefault
{
995 ExprFillDefaultDef
::Todo
=> ExprFillDefaultMode
::Todo
,
996 ExprFillDefaultDef
::Default
=> ExprFillDefaultMode
::Default
,
998 insert_use
: self.insert_use_config(),
999 prefer_no_std
: self.data
.imports_prefer_no_std
,
1003 pub fn diagnostics_map(&self) -> DiagnosticsMapConfig
{
1004 DiagnosticsMapConfig
{
1005 remap_prefix
: self.data
.diagnostics_remapPrefix
.clone(),
1006 warnings_as_info
: self.data
.diagnostics_warningsAsInfo
.clone(),
1007 warnings_as_hint
: self.data
.diagnostics_warningsAsHint
.clone(),
1011 pub fn extra_env(&self) -> &FxHashMap
<String
, String
> {
1012 &self.data
.cargo_extraEnv
1015 pub fn check_on_save_extra_env(&self) -> FxHashMap
<String
, String
> {
1016 let mut extra_env
= self.data
.cargo_extraEnv
.clone();
1017 extra_env
.extend(self.data
.checkOnSave_extraEnv
.clone());
1021 pub fn lru_capacity(&self) -> Option
<usize> {
1022 self.data
.lru_capacity
1025 pub fn proc_macro_srv(&self) -> Option
<(AbsPathBuf
, /* is path explicitly set */ bool
)> {
1026 if !self.data
.procMacro_enable
{
1029 Some(match &self.data
.procMacro_server
{
1031 AbsPathBuf
::try_from(it
.clone()).unwrap_or_else(|path
| self.root_path
.join(path
)),
1034 None
=> (AbsPathBuf
::assert(std
::env
::current_exe().ok()?
), false),
1038 pub fn dummy_replacements(&self) -> &FxHashMap
<Box
<str>, Box
<[Box
<str>]>> {
1039 &self.data
.procMacro_ignored
1042 pub fn expand_proc_attr_macros(&self) -> bool
{
1043 self.data
.procMacro_enable
&& self.data
.procMacro_attributes_enable
1046 pub fn files(&self) -> FilesConfig
{
1048 watcher
: match self.data
.files_watcher
{
1049 FilesWatcherDef
::Client
if self.did_change_watched_files_dynamic_registration() => {
1050 FilesWatcher
::Client
1052 _
=> FilesWatcher
::Server
,
1054 exclude
: self.data
.files_excludeDirs
.iter().map(|it
| self.root_path
.join(it
)).collect(),
1058 pub fn notifications(&self) -> NotificationsConfig
{
1059 NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound }
1062 pub fn cargo_autoreload(&self) -> bool
{
1063 self.data
.cargo_autoreload
1066 pub fn run_build_scripts(&self) -> bool
{
1067 self.data
.cargo_buildScripts_enable
|| self.data
.procMacro_enable
1070 pub fn cargo(&self) -> CargoConfig
{
1071 let rustc_source
= self.data
.rustc_source
.as_ref().map(|rustc_src
| {
1072 if rustc_src
== "discover" {
1073 RustcSource
::Discover
1075 RustcSource
::Path(self.root_path
.join(rustc_src
))
1078 let sysroot
= self.data
.cargo_sysroot
.as_ref().map(|sysroot
| {
1079 if sysroot
== "discover" {
1080 RustcSource
::Discover
1082 RustcSource
::Path(self.root_path
.join(sysroot
))
1087 features
: match &self.data
.cargo_features
{
1088 CargoFeaturesDef
::All
=> CargoFeatures
::All
,
1089 CargoFeaturesDef
::Selected(features
) => CargoFeatures
::Selected
{
1090 features
: features
.clone(),
1091 no_default_features
: self.data
.cargo_noDefaultFeatures
,
1094 target
: self.data
.cargo_target
.clone(),
1097 unset_test_crates
: UnsetTestCrates
::Only(self.data
.cargo_unsetTest
.clone()),
1098 wrap_rustc_in_build_scripts
: self.data
.cargo_buildScripts_useRustcWrapper
,
1099 invocation_strategy
: match self.data
.cargo_buildScripts_invocationStrategy
{
1100 InvocationStrategy
::Once
=> project_model
::InvocationStrategy
::Once
,
1101 InvocationStrategy
::PerWorkspace
=> project_model
::InvocationStrategy
::PerWorkspace
,
1103 invocation_location
: match self.data
.cargo_buildScripts_invocationLocation
{
1104 InvocationLocation
::Root
=> {
1105 project_model
::InvocationLocation
::Root(self.root_path
.clone())
1107 InvocationLocation
::Workspace
=> project_model
::InvocationLocation
::Workspace
,
1109 run_build_script_command
: self.data
.cargo_buildScripts_overrideCommand
.clone(),
1110 extra_env
: self.data
.cargo_extraEnv
.clone(),
1114 pub fn rustfmt(&self) -> RustfmtConfig
{
1115 match &self.data
.rustfmt_overrideCommand
{
1116 Some(args
) if !args
.is_empty() => {
1117 let mut args
= args
.clone();
1118 let command
= args
.remove(0);
1119 RustfmtConfig
::CustomCommand { command, args }
1121 Some(_
) | None
=> RustfmtConfig
::Rustfmt
{
1122 extra_args
: self.data
.rustfmt_extraArgs
.clone(),
1123 enable_range_formatting
: self.data
.rustfmt_rangeFormatting_enable
,
1128 pub fn flycheck(&self) -> Option
<FlycheckConfig
> {
1129 if !self.data
.checkOnSave_enable
{
1132 let flycheck_config
= match &self.data
.checkOnSave_overrideCommand
{
1133 Some(args
) if !args
.is_empty() => {
1134 let mut args
= args
.clone();
1135 let command
= args
.remove(0);
1136 FlycheckConfig
::CustomCommand
{
1139 extra_env
: self.check_on_save_extra_env(),
1140 invocation_strategy
: match self.data
.checkOnSave_invocationStrategy
{
1141 InvocationStrategy
::Once
=> flycheck
::InvocationStrategy
::Once
,
1142 InvocationStrategy
::PerWorkspace
=> {
1143 flycheck
::InvocationStrategy
::PerWorkspace
1146 invocation_location
: match self.data
.checkOnSave_invocationLocation
{
1147 InvocationLocation
::Root
=> {
1148 flycheck
::InvocationLocation
::Root(self.root_path
.clone())
1150 InvocationLocation
::Workspace
=> flycheck
::InvocationLocation
::Workspace
,
1154 Some(_
) | None
=> FlycheckConfig
::CargoCommand
{
1155 command
: self.data
.checkOnSave_command
.clone(),
1156 target_triples
: match &self.data
.checkOnSave_target
.0[..] {
1157 [] => self.data
.cargo_target
.clone().into_iter().collect(),
1158 targets
=> targets
.into(),
1160 all_targets
: self.data
.checkOnSave_allTargets
,
1161 no_default_features
: self
1163 .checkOnSave_noDefaultFeatures
1164 .unwrap_or(self.data
.cargo_noDefaultFeatures
),
1165 all_features
: matches
!(
1166 self.data
.checkOnSave_features
.as_ref().unwrap_or(&self.data
.cargo_features
),
1167 CargoFeaturesDef
::All
1169 features
: match self
1171 .checkOnSave_features
1173 .unwrap_or_else(|| self.data
.cargo_features
.clone())
1175 CargoFeaturesDef
::All
=> vec
![],
1176 CargoFeaturesDef
::Selected(it
) => it
,
1178 extra_args
: self.data
.checkOnSave_extraArgs
.clone(),
1179 extra_env
: self.check_on_save_extra_env(),
1182 Some(flycheck_config
)
1185 pub fn runnables(&self) -> RunnablesConfig
{
1187 override_cargo
: self.data
.runnables_command
.clone(),
1188 cargo_extra_args
: self.data
.runnables_extraArgs
.clone(),
1192 pub fn inlay_hints(&self) -> InlayHintsConfig
{
1194 render_colons
: self.data
.inlayHints_renderColons
,
1195 type_hints
: self.data
.inlayHints_typeHints_enable
,
1196 parameter_hints
: self.data
.inlayHints_parameterHints_enable
,
1197 chaining_hints
: self.data
.inlayHints_chainingHints_enable
,
1198 closure_return_type_hints
: match self.data
.inlayHints_closureReturnTypeHints_enable
{
1199 ClosureReturnTypeHintsDef
::Always
=> ide
::ClosureReturnTypeHints
::Always
,
1200 ClosureReturnTypeHintsDef
::Never
=> ide
::ClosureReturnTypeHints
::Never
,
1201 ClosureReturnTypeHintsDef
::WithBlock
=> ide
::ClosureReturnTypeHints
::WithBlock
,
1203 lifetime_elision_hints
: match self.data
.inlayHints_lifetimeElisionHints_enable
{
1204 LifetimeElisionDef
::Always
=> ide
::LifetimeElisionHints
::Always
,
1205 LifetimeElisionDef
::Never
=> ide
::LifetimeElisionHints
::Never
,
1206 LifetimeElisionDef
::SkipTrivial
=> ide
::LifetimeElisionHints
::SkipTrivial
,
1208 hide_named_constructor_hints
: self.data
.inlayHints_typeHints_hideNamedConstructor
,
1209 hide_closure_initialization_hints
: self
1211 .inlayHints_typeHints_hideClosureInitialization
,
1212 adjustment_hints
: match self.data
.inlayHints_expressionAdjustmentHints_enable
{
1213 AdjustmentHintsDef
::Always
=> ide
::AdjustmentHints
::Always
,
1214 AdjustmentHintsDef
::Never
=> match self.data
.inlayHints_reborrowHints_enable
{
1215 ReborrowHintsDef
::Always
| ReborrowHintsDef
::Mutable
=> {
1216 ide
::AdjustmentHints
::ReborrowOnly
1218 ReborrowHintsDef
::Never
=> ide
::AdjustmentHints
::Never
,
1220 AdjustmentHintsDef
::Reborrow
=> ide
::AdjustmentHints
::ReborrowOnly
,
1222 binding_mode_hints
: self.data
.inlayHints_bindingModeHints_enable
,
1223 param_names_for_lifetime_elision_hints
: self
1225 .inlayHints_lifetimeElisionHints_useParameterNames
,
1226 max_length
: self.data
.inlayHints_maxLength
,
1227 closing_brace_hints_min_lines
: if self.data
.inlayHints_closingBraceHints_enable
{
1228 Some(self.data
.inlayHints_closingBraceHints_minLines
)
1235 fn insert_use_config(&self) -> InsertUseConfig
{
1237 granularity
: match self.data
.imports_granularity_group
{
1238 ImportGranularityDef
::Preserve
=> ImportGranularity
::Preserve
,
1239 ImportGranularityDef
::Item
=> ImportGranularity
::Item
,
1240 ImportGranularityDef
::Crate
=> ImportGranularity
::Crate
,
1241 ImportGranularityDef
::Module
=> ImportGranularity
::Module
,
1243 enforce_granularity
: self.data
.imports_granularity_enforce
,
1244 prefix_kind
: match self.data
.imports_prefix
{
1245 ImportPrefixDef
::Plain
=> PrefixKind
::Plain
,
1246 ImportPrefixDef
::ByCrate
=> PrefixKind
::ByCrate
,
1247 ImportPrefixDef
::BySelf
=> PrefixKind
::BySelf
,
1249 group
: self.data
.imports_group_enable
,
1250 skip_glob_imports
: !self.data
.imports_merge_glob
,
1254 pub fn completion(&self) -> CompletionConfig
{
1256 enable_postfix_completions
: self.data
.completion_postfix_enable
,
1257 enable_imports_on_the_fly
: self.data
.completion_autoimport_enable
1258 && completion_item_edit_resolve(&self.caps
),
1259 enable_self_on_the_fly
: self.data
.completion_autoself_enable
,
1260 enable_private_editable
: self.data
.completion_privateEditable_enable
,
1261 callable
: match self.data
.completion_callable_snippets
{
1262 CallableCompletionDef
::FillArguments
=> Some(CallableSnippets
::FillArguments
),
1263 CallableCompletionDef
::AddParentheses
=> Some(CallableSnippets
::AddParentheses
),
1264 CallableCompletionDef
::None
=> None
,
1266 insert_use
: self.insert_use_config(),
1267 prefer_no_std
: self.data
.imports_prefer_no_std
,
1268 snippet_cap
: SnippetCap
::new(try_or_def
!(
1278 snippets
: self.snippets
.clone(),
1282 pub fn find_all_refs_exclude_imports(&self) -> bool
{
1283 self.data
.references_excludeImports
1286 pub fn snippet_cap(&self) -> bool
{
1287 self.experimental("snippetTextEdit")
1290 pub fn assist(&self) -> AssistConfig
{
1292 snippet_cap
: SnippetCap
::new(self.experimental("snippetTextEdit")),
1294 insert_use
: self.insert_use_config(),
1295 prefer_no_std
: self.data
.imports_prefer_no_std
,
1296 assist_emit_must_use
: self.data
.assist_emitMustUse
,
1300 pub fn join_lines(&self) -> JoinLinesConfig
{
1302 join_else_if
: self.data
.joinLines_joinElseIf
,
1303 remove_trailing_comma
: self.data
.joinLines_removeTrailingComma
,
1304 unwrap_trivial_blocks
: self.data
.joinLines_unwrapTrivialBlock
,
1305 join_assignments
: self.data
.joinLines_joinAssignments
,
1309 pub fn call_info(&self) -> CallInfoConfig
{
1311 params_only
: matches
!(self.data
.signatureInfo_detail
, SignatureDetail
::Parameters
),
1312 docs
: self.data
.signatureInfo_documentation_enable
,
1316 pub fn lens(&self) -> LensConfig
{
1318 run
: self.data
.lens_enable
&& self.data
.lens_run_enable
,
1319 debug
: self.data
.lens_enable
&& self.data
.lens_debug_enable
,
1320 implementations
: self.data
.lens_enable
&& self.data
.lens_implementations_enable
,
1321 method_refs
: self.data
.lens_enable
&& self.data
.lens_references_method_enable
,
1322 refs_adt
: self.data
.lens_enable
&& self.data
.lens_references_adt_enable
,
1323 refs_trait
: self.data
.lens_enable
&& self.data
.lens_references_trait_enable
,
1324 enum_variant_refs
: self.data
.lens_enable
1325 && self.data
.lens_references_enumVariant_enable
,
1326 location
: self.data
.lens_location
,
1330 pub fn hover_actions(&self) -> HoverActionsConfig
{
1331 let enable
= self.experimental("hoverActions") && self.data
.hover_actions_enable
;
1332 HoverActionsConfig
{
1333 implementations
: enable
&& self.data
.hover_actions_implementations_enable
,
1334 references
: enable
&& self.data
.hover_actions_references_enable
,
1335 run
: enable
&& self.data
.hover_actions_run_enable
,
1336 debug
: enable
&& self.data
.hover_actions_debug_enable
,
1337 goto_type_def
: enable
&& self.data
.hover_actions_gotoTypeDef_enable
,
1341 pub fn highlighting_config(&self) -> HighlightConfig
{
1343 strings
: self.data
.semanticHighlighting_strings_enable
,
1344 punctuation
: self.data
.semanticHighlighting_punctuation_enable
,
1345 specialize_punctuation
: self
1347 .semanticHighlighting_punctuation_specialization_enable
,
1348 macro_bang
: self.data
.semanticHighlighting_punctuation_separate_macro_bang
,
1349 operator
: self.data
.semanticHighlighting_operator_enable
,
1350 specialize_operator
: self.data
.semanticHighlighting_operator_specialization_enable
,
1351 inject_doc_comment
: self.data
.semanticHighlighting_doc_comment_inject_enable
,
1352 syntactic_name_ref_highlighting
: false,
1356 pub fn hover(&self) -> HoverConfig
{
1358 links_in_hover
: self.data
.hover_links_enable
,
1359 documentation
: self.data
.hover_documentation_enable
.then(|| {
1360 let is_markdown
= try_or_def
!(self
1369 .contains(&MarkupKind
::Markdown
);
1371 HoverDocFormat
::Markdown
1373 HoverDocFormat
::PlainText
1376 keywords
: self.data
.hover_documentation_keywords_enable
,
1380 pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig
{
1381 WorkspaceSymbolConfig
{
1382 search_scope
: match self.data
.workspace_symbol_search_scope
{
1383 WorkspaceSymbolSearchScopeDef
::Workspace
=> WorkspaceSymbolSearchScope
::Workspace
,
1384 WorkspaceSymbolSearchScopeDef
::WorkspaceAndDependencies
=> {
1385 WorkspaceSymbolSearchScope
::WorkspaceAndDependencies
1388 search_kind
: match self.data
.workspace_symbol_search_kind
{
1389 WorkspaceSymbolSearchKindDef
::OnlyTypes
=> WorkspaceSymbolSearchKind
::OnlyTypes
,
1390 WorkspaceSymbolSearchKindDef
::AllSymbols
=> WorkspaceSymbolSearchKind
::AllSymbols
,
1392 search_limit
: self.data
.workspace_symbol_search_limit
,
1396 pub fn semantic_tokens_refresh(&self) -> bool
{
1397 try_or_def
!(self.caps
.workspace
.as_ref()?
.semantic_tokens
.as_ref()?
.refresh_support?
)
1400 pub fn code_lens_refresh(&self) -> bool
{
1401 try_or_def
!(self.caps
.workspace
.as_ref()?
.code_lens
.as_ref()?
.refresh_support?
)
1404 pub fn insert_replace_support(&self) -> bool
{
1413 .insert_replace_support?
1417 pub fn client_commands(&self) -> ClientCommandsConfig
{
1419 try_or
!(self.caps
.experimental
.as_ref()?
.get("commands")?
, &serde_json
::Value
::Null
);
1420 let commands
: Option
<lsp_ext
::ClientCommandOptions
> =
1421 serde_json
::from_value(commands
.clone()).ok();
1422 let force
= commands
.is_none() && self.data
.lens_forceCustomCommands
;
1423 let commands
= commands
.map(|it
| it
.commands
).unwrap_or_default();
1425 let get
= |name
: &str| commands
.iter().any(|it
| it
== name
) || force
;
1427 ClientCommandsConfig
{
1428 run_single
: get("rust-analyzer.runSingle"),
1429 debug_single
: get("rust-analyzer.debugSingle"),
1430 show_reference
: get("rust-analyzer.showReferences"),
1431 goto_location
: get("rust-analyzer.gotoLocation"),
1432 trigger_parameter_hints
: get("editor.action.triggerParameterHints"),
1436 pub fn highlight_related(&self) -> HighlightRelatedConfig
{
1437 HighlightRelatedConfig
{
1438 references
: self.data
.highlightRelated_references_enable
,
1439 break_points
: self.data
.highlightRelated_breakPoints_enable
,
1440 exit_points
: self.data
.highlightRelated_exitPoints_enable
,
1441 yield_points
: self.data
.highlightRelated_yieldPoints_enable
,
1445 pub fn prime_caches_num_threads(&self) -> u8 {
1446 match self.data
.cachePriming_numThreads
{
1447 0 => num_cpus
::get_physical().try_into().unwrap_or(u8::MAX
),
1452 pub fn typing_autoclose_angle(&self) -> bool
{
1453 self.data
.typing_autoClosingAngleBrackets_enable
1456 // Deserialization definitions
1458 macro_rules
! create_bool_or_string_de
{
1459 ($ident
:ident
<$bool
:literal
, $string
:literal
>) => {
1460 fn $ident
<'de
, D
>(d
: D
) -> Result
<(), D
::Error
>
1462 D
: serde
::Deserializer
<'de
>,
1465 impl<'de
> serde
::de
::Visitor
<'de
> for V
{
1468 fn expecting(&self, formatter
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1469 formatter
.write_str(concat
!(
1472 stringify
!($string
),
1477 fn visit_bool
<E
>(self, v
: bool
) -> Result
<Self::Value
, E
>
1479 E
: serde
::de
::Error
,
1483 _
=> Err(serde
::de
::Error
::invalid_value(
1484 serde
::de
::Unexpected
::Bool(v
),
1490 fn visit_str
<E
>(self, v
: &str) -> Result
<Self::Value
, E
>
1492 E
: serde
::de
::Error
,
1496 _
=> Err(serde
::de
::Error
::invalid_value(
1497 serde
::de
::Unexpected
::Str(v
),
1503 fn visit_enum
<A
>(self, a
: A
) -> Result
<Self::Value
, A
::Error
>
1505 A
: serde
::de
::EnumAccess
<'de
>,
1507 use serde
::de
::VariantAccess
;
1508 let (variant
, va
) = a
.variant
::<&'de
str>()?
;
1512 _
=> Err(serde
::de
::Error
::invalid_value(
1513 serde
::de
::Unexpected
::Str(variant
),
1519 d
.deserialize_any(V
)
1523 create_bool_or_string_de
!(true_or_always
<true, "always">);
1524 create_bool_or_string_de
!(false_or_never
<false, "never">);
1526 macro_rules
! named_unit_variant
{
1527 ($variant
:ident
) => {
1528 pub(super) fn $variant
<'de
, D
>(deserializer
: D
) -> Result
<(), D
::Error
>
1530 D
: serde
::Deserializer
<'de
>,
1533 impl<'de
> serde
::de
::Visitor
<'de
> for V
{
1535 fn expecting(&self, f
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
1536 f
.write_str(concat
!("\"", stringify
!($variant
), "\""))
1538 fn visit_str
<E
: serde
::de
::Error
>(self, value
: &str) -> Result
<Self::Value
, E
> {
1539 if value
== stringify
!($variant
) {
1542 Err(E
::invalid_value(serde
::de
::Unexpected
::Str(value
), &self))
1546 deserializer
.deserialize_str(V
)
1552 named_unit_variant
!(all
);
1553 named_unit_variant
!(skip_trivial
);
1554 named_unit_variant
!(mutable
);
1555 named_unit_variant
!(reborrow
);
1556 named_unit_variant
!(with_block
);
1559 #[derive(Deserialize, Debug, Clone, Copy)]
1560 #[serde(rename_all = "snake_case")]
1561 enum SnippetScopeDef
{
1567 impl Default
for SnippetScopeDef
{
1568 fn default() -> Self {
1569 SnippetScopeDef
::Expr
1573 #[derive(Deserialize, Debug, Clone, Default)]
1576 #[serde(deserialize_with = "single_or_array")]
1577 prefix
: Vec
<String
>,
1578 #[serde(deserialize_with = "single_or_array")]
1579 postfix
: Vec
<String
>,
1580 description
: Option
<String
>,
1581 #[serde(deserialize_with = "single_or_array")]
1583 #[serde(deserialize_with = "single_or_array")]
1584 requires
: Vec
<String
>,
1585 scope
: SnippetScopeDef
,
1588 fn single_or_array
<'de
, D
>(deserializer
: D
) -> Result
<Vec
<String
>, D
::Error
>
1590 D
: serde
::Deserializer
<'de
>,
1594 impl<'de
> serde
::de
::Visitor
<'de
> for SingleOrVec
{
1595 type Value
= Vec
<String
>;
1597 fn expecting(&self, formatter
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
1598 formatter
.write_str("string or array of strings")
1601 fn visit_str
<E
>(self, value
: &str) -> Result
<Self::Value
, E
>
1603 E
: serde
::de
::Error
,
1605 Ok(vec
![value
.to_owned()])
1608 fn visit_seq
<A
>(self, seq
: A
) -> Result
<Self::Value
, A
::Error
>
1610 A
: serde
::de
::SeqAccess
<'de
>,
1612 Deserialize
::deserialize(serde
::de
::value
::SeqAccessDeserializer
::new(seq
))
1616 deserializer
.deserialize_any(SingleOrVec
)
1619 #[derive(Deserialize, Debug, Clone)]
1621 enum ManifestOrProjectJson
{
1623 ProjectJson(ProjectJsonData
),
1626 #[derive(Deserialize, Debug, Clone)]
1627 #[serde(rename_all = "snake_case")]
1628 enum ExprFillDefaultDef
{
1633 #[derive(Deserialize, Debug, Clone)]
1634 #[serde(rename_all = "snake_case")]
1635 enum ImportGranularityDef
{
1642 #[derive(Deserialize, Debug, Copy, Clone)]
1643 #[serde(rename_all = "snake_case")]
1644 enum CallableCompletionDef
{
1650 #[derive(Deserialize, Debug, Clone)]
1652 enum CargoFeaturesDef
{
1653 #[serde(deserialize_with = "de_unit_v::all")]
1655 Selected(Vec
<String
>),
1658 #[derive(Deserialize, Debug, Clone)]
1659 #[serde(rename_all = "snake_case")]
1660 enum InvocationStrategy
{
1665 #[derive(Deserialize, Debug, Clone)]
1666 struct CheckOnSaveTargets(#[serde(deserialize_with = "single_or_array")] Vec<String>);
1668 #[derive(Deserialize, Debug, Clone)]
1669 #[serde(rename_all = "snake_case")]
1670 enum InvocationLocation
{
1675 #[derive(Deserialize, Debug, Clone)]
1677 enum LifetimeElisionDef
{
1678 #[serde(deserialize_with = "true_or_always")]
1680 #[serde(deserialize_with = "false_or_never")]
1682 #[serde(deserialize_with = "de_unit_v::skip_trivial")]
1686 #[derive(Deserialize, Debug, Clone)]
1688 enum ClosureReturnTypeHintsDef
{
1689 #[serde(deserialize_with = "true_or_always")]
1691 #[serde(deserialize_with = "false_or_never")]
1693 #[serde(deserialize_with = "de_unit_v::with_block")]
1697 #[derive(Deserialize, Debug, Clone)]
1699 enum ReborrowHintsDef
{
1700 #[serde(deserialize_with = "true_or_always")]
1702 #[serde(deserialize_with = "false_or_never")]
1704 #[serde(deserialize_with = "de_unit_v::mutable")]
1708 #[derive(Deserialize, Debug, Clone)]
1710 enum AdjustmentHintsDef
{
1711 #[serde(deserialize_with = "true_or_always")]
1713 #[serde(deserialize_with = "false_or_never")]
1715 #[serde(deserialize_with = "de_unit_v::reborrow")]
1719 #[derive(Deserialize, Debug, Clone)]
1720 #[serde(rename_all = "snake_case")]
1721 enum FilesWatcherDef
{
1727 #[derive(Deserialize, Debug, Clone)]
1728 #[serde(rename_all = "snake_case")]
1729 enum ImportPrefixDef
{
1731 #[serde(alias = "self")]
1733 #[serde(alias = "crate")]
1737 #[derive(Deserialize, Debug, Clone)]
1738 #[serde(rename_all = "snake_case")]
1739 enum WorkspaceSymbolSearchScopeDef
{
1741 WorkspaceAndDependencies
,
1744 #[derive(Deserialize, Debug, Clone)]
1745 #[serde(rename_all = "snake_case")]
1746 enum SignatureDetail
{
1751 #[derive(Deserialize, Debug, Clone)]
1752 #[serde(rename_all = "snake_case")]
1753 enum WorkspaceSymbolSearchKindDef
{
1758 macro_rules
! _config_data
{
1759 (struct $name
:ident
{
1761 $
(#[doc=$doc:literal])*
1762 $field
:ident $
(| $alias
:ident
)*: $ty
:ty
= $
default:expr
,
1765 #[allow(non_snake_case)]
1766 #[derive(Debug, Clone)]
1767 struct $name { $($field: $ty,)* }
1769 fn from_json(mut json
: serde_json
::Value
, error_sink
: &mut Vec
<(String
, serde_json
::Error
)>) -> $name
{
1775 None$
(.or(Some(stringify
!($alias
))))*,
1781 fn json_schema() -> serde_json
::Value
{
1784 let field
= stringify
!($field
);
1785 let ty
= stringify
!($ty
);
1787 (field
, ty
, &[$
($doc
),*], $
default)
1793 fn manual() -> String
{
1796 let field
= stringify
!($field
);
1797 let ty
= stringify
!($ty
);
1799 (field
, ty
, &[$
($doc
),*], $
default)
1806 fn fields_are_sorted() {
1807 [$
(stringify
!($field
)),*].windows(2).for_each(|w
| assert
!(w
[0] <= w
[1], "{} <= {} does not hold", w
[0], w
[1]));
1811 use _config_data
as config_data
;
1813 fn get_field
<T
: DeserializeOwned
>(
1814 json
: &mut serde_json
::Value
,
1815 error_sink
: &mut Vec
<(String
, serde_json
::Error
)>,
1816 field
: &'
static str,
1817 alias
: Option
<&'
static str>,
1820 let default = serde_json
::from_str(default).unwrap();
1821 // XXX: check alias first, to work-around the VS Code where it pre-fills the
1822 // defaults instead of sending an empty object.
1825 .chain(iter
::once(field
))
1826 .find_map(move |field
| {
1827 let mut pointer
= field
.replace('_'
, "/");
1828 pointer
.insert(0, '
/'
);
1829 json
.pointer_mut(&pointer
).and_then(|it
| match serde_json
::from_value(it
.take()) {
1832 tracing
::warn
!("Failed to deserialize config field at {}: {:?}", pointer
, e
);
1833 error_sink
.push((pointer
, e
));
1841 fn schema(fields
: &[(&'
static str, &'
static str, &[&str], &str)]) -> serde_json
::Value
{
1842 for ((f1
, ..), (f2
, ..)) in fields
.iter().zip(&fields
[1..]) {
1843 fn key(f
: &str) -> &str {
1844 f
.splitn(2, '_'
).next().unwrap()
1846 assert
!(key(f1
) <= key(f2
), "wrong field order: {:?} {:?}", f1
, f2
);
1851 .map(|(field
, ty
, doc
, default)| {
1852 let name
= field
.replace('_'
, ".");
1853 let name
= format
!("rust-analyzer.{}", name
);
1854 let props
= field_props(field
, ty
, doc
, default);
1857 .collect
::<serde_json
::Map
<_
, _
>>();
1861 fn field_props(field
: &str, ty
: &str, doc
: &[&str], default: &str) -> serde_json
::Value
{
1862 let doc
= doc_comment_to_string(doc
);
1863 let doc
= doc
.trim_end_matches('
\n'
);
1865 doc
.ends_with('
.'
) && doc
.starts_with(char::is_uppercase
),
1866 "bad docs for {}: {:?}",
1870 let default = default.parse
::<serde_json
::Value
>().unwrap();
1872 let mut map
= serde_json
::Map
::default();
1874 ($
($key
:literal
: $value
:tt
),*$
(,)?
) => {{$
(
1875 map
.insert($key
.into(), serde_json
::json
!($value
));
1878 set
!("markdownDescription": doc
);
1879 set
!("default": default);
1882 "bool" => set
!("type": "boolean"),
1883 "usize" => set
!("type": "integer", "minimum": 0),
1884 "String" => set
!("type": "string"),
1885 "Vec<String>" => set
! {
1887 "items": { "type": "string" }
,
1889 "Vec<PathBuf>" => set
! {
1891 "items": { "type": "string" }
,
1893 "FxHashSet<String>" => set
! {
1895 "items": { "type": "string" }
,
1896 "uniqueItems": true,
1898 "FxHashMap<Box<str>, Box<[Box<str>]>>" => set
! {
1901 "FxHashMap<String, SnippetDef>" => set
! {
1904 "FxHashMap<String, String>" => set
! {
1907 "Option<usize>" => set
! {
1908 "type": ["null", "integer"],
1911 "Option<String>" => set
! {
1912 "type": ["null", "string"],
1914 "Option<PathBuf>" => set
! {
1915 "type": ["null", "string"],
1917 "Option<bool>" => set
! {
1918 "type": ["null", "boolean"],
1920 "Option<Vec<String>>" => set
! {
1921 "type": ["null", "array"],
1922 "items": { "type": "string" }
,
1924 "MergeBehaviorDef" => set
! {
1926 "enum": ["none", "crate", "module"],
1927 "enumDescriptions": [
1928 "Do not merge imports at all.",
1929 "Merge imports from the same crate into a single `use` statement.",
1930 "Merge imports from the same module into a single `use` statement."
1933 "ExprFillDefaultDef" => set
! {
1935 "enum": ["todo", "default"],
1936 "enumDescriptions": [
1937 "Fill missing expressions with the `todo` macro",
1938 "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
1941 "ImportGranularityDef" => set
! {
1943 "enum": ["preserve", "crate", "module", "item"],
1944 "enumDescriptions": [
1945 "Do not change the granularity of any imports and preserve the original structure written by the developer.",
1946 "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
1947 "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
1948 "Flatten imports so that each has its own use statement."
1951 "ImportPrefixDef" => set
! {
1958 "enumDescriptions": [
1959 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
1960 "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.",
1961 "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
1964 "Vec<ManifestOrProjectJson>" => set
! {
1966 "items": { "type": ["string", "object"] }
,
1968 "WorkspaceSymbolSearchScopeDef" => set
! {
1970 "enum": ["workspace", "workspace_and_dependencies"],
1971 "enumDescriptions": [
1972 "Search in current workspace only.",
1973 "Search in current workspace and dependencies."
1976 "WorkspaceSymbolSearchKindDef" => set
! {
1978 "enum": ["only_types", "all_symbols"],
1979 "enumDescriptions": [
1980 "Search for types only.",
1981 "Search for all symbols kinds."
1984 "ParallelCachePrimingNumThreads" => set
! {
1989 "LifetimeElisionDef" => set
! {
1996 "enumDescriptions": [
1997 "Always show lifetime elision hints.",
1998 "Never show lifetime elision hints.",
1999 "Only show lifetime elision hints if a return type is involved."
2002 "ClosureReturnTypeHintsDef" => set
! {
2009 "enumDescriptions": [
2010 "Always show type hints for return types of closures.",
2011 "Never show type hints for return types of closures.",
2012 "Only show type hints for return types of closures with blocks."
2015 "ReborrowHintsDef" => set
! {
2022 "enumDescriptions": [
2023 "Always show reborrow hints.",
2024 "Never show reborrow hints.",
2025 "Only show mutable reborrow hints."
2028 "AdjustmentHintsDef" => set
! {
2035 "enumDescriptions": [
2036 "Always show all adjustment hints.",
2037 "Never show adjustment hints.",
2038 "Only show auto borrow and dereference adjustment hints."
2041 "CargoFeaturesDef" => set
! {
2048 "enumDescriptions": [
2049 "Pass `--all-features` to cargo",
2054 "items": { "type": "string" }
2058 "Option<CargoFeaturesDef>" => set
! {
2065 "enumDescriptions": [
2066 "Pass `--all-features` to cargo",
2071 "items": { "type": "string" }
2076 "CallableCompletionDef" => set
! {
2083 "enumDescriptions": [
2084 "Add call parentheses and pre-fill arguments.",
2085 "Add call parentheses.",
2086 "Do no snippet completions for callables."
2089 "SignatureDetail" => set
! {
2091 "enum": ["full", "parameters"],
2092 "enumDescriptions": [
2093 "Show the entire signature.",
2094 "Show only the parameters."
2097 "FilesWatcherDef" => set
! {
2099 "enum": ["client", "server"],
2100 "enumDescriptions": [
2101 "Use the client (editor) to watch files for changes",
2102 "Use server-side file watching",
2105 "AnnotationLocation" => set
! {
2107 "enum": ["above_name", "above_whole_item"],
2108 "enumDescriptions": [
2109 "Render annotations above the name of the item.",
2110 "Render annotations above the whole item, including documentation comments and attributes."
2113 "InvocationStrategy" => set
! {
2115 "enum": ["per_workspace", "once"],
2116 "enumDescriptions": [
2117 "The command will be executed for each workspace.",
2118 "The command will be executed once."
2121 "InvocationLocation" => set
! {
2123 "enum": ["workspace", "root"],
2124 "enumDescriptions": [
2125 "The command will be executed in the corresponding workspace root.",
2126 "The command will be executed in the project root."
2129 "CheckOnSaveTargets" => set
! {
2136 "items": { "type": "string" }
2140 _
=> panic
!("missing entry for {}: {}", ty
, default),
2147 fn manual(fields
: &[(&'
static str, &'
static str, &[&str], &str)]) -> String
{
2150 .map(|(field
, _ty
, doc
, default)| {
2151 let name
= format
!("rust-analyzer.{}", field
.replace('_'
, "."));
2152 let doc
= doc_comment_to_string(*doc
);
2153 if default.contains('
\n'
) {
2165 name
, name
, default, doc
2168 format
!("[[{}]]{} (default: `{}`)::\n+\n--\n{}--\n", name
, name
, default, doc
)
2171 .collect
::<String
>()
2174 fn doc_comment_to_string(doc
: &[&str]) -> String
{
2175 doc
.iter().map(|it
| it
.strip_prefix(' '
).unwrap_or(it
)).map(|it
| format
!("{}\n", it
)).collect()
2182 use test_utils
::{ensure_file_contents, project_root}
;
2187 fn generate_package_json_config() {
2188 let s
= Config
::json_schema();
2189 let schema
= format
!("{:#}", s
);
2190 let mut schema
= schema
2191 .trim_start_matches('
{'
)
2192 .trim_end_matches('
}'
)
2194 .replace('
\n'
, "\n ")
2195 .trim_start_matches('
\n'
)
2198 schema
.push_str(",\n");
2200 // Transform the asciidoc form link to markdown style.
2202 // https://link[text] => [text](https://link)
2203 let url_matches
= schema
.match_indices("https://");
2204 let mut url_offsets
= url_matches
.map(|(idx
, _
)| idx
).collect
::<Vec
<usize>>();
2205 url_offsets
.reverse();
2206 for idx
in url_offsets
{
2207 let link
= &schema
[idx
..];
2208 // matching on whitespace to ignore normal links
2209 if let Some(link_end
) = link
.find(|c
| c
== ' '
|| c
== '
['
) {
2210 if link
.chars().nth(link_end
) == Some('
['
) {
2211 if let Some(link_text_end
) = link
.find('
]'
) {
2212 let link_text
= link
[link_end
..(link_text_end
+ 1)].to_string();
2214 schema
.replace_range((idx
+ link_end
)..(idx
+ link_text_end
+ 1), "");
2215 schema
.insert(idx
, '
('
);
2216 schema
.insert(idx
+ link_end
+ 1, '
)'
);
2217 schema
.insert_str(idx
, &link_text
);
2223 let package_json_path
= project_root().join("editors/code/package.json");
2224 let mut package_json
= fs
::read_to_string(&package_json_path
).unwrap();
2226 let start_marker
= " \"$generated-start\": {},\n";
2227 let end_marker
= " \"$generated-end\": {}\n";
2229 let start
= package_json
.find(start_marker
).unwrap() + start_marker
.len();
2230 let end
= package_json
.find(end_marker
).unwrap();
2232 let p
= remove_ws(&package_json
[start
..end
]);
2233 let s
= remove_ws(&schema
);
2234 if !p
.contains(&s
) {
2235 package_json
.replace_range(start
..end
, &schema
);
2236 ensure_file_contents(&package_json_path
, &package_json
)
2241 fn generate_config_documentation() {
2242 let docs_path
= project_root().join("docs/user/generated_config.adoc");
2243 let expected
= ConfigData
::manual();
2244 ensure_file_contents(&docs_path
, &expected
);
2247 fn remove_ws(text
: &str) -> String
{
2248 text
.replace(char::is_whitespace
, "")