X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=crates%2Frust-analyzer%2Fsrc%2Fconfig.rs;h=5826b6b114c2b455e68eab0d2a08e4b5eacf5f74;hb=a68ce62f6a33d3e5777c1d64c946e0f1d9c7f457;hp=6c0983336837017e401d29cd07cec3f38abe799f;hpb=81891f7abecbcdd8d97bf878dd1dbce595755d6a;p=rust.git diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 6c098333683..5826b6b114c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -12,7 +12,7 @@ use flycheck::FlycheckConfig; use ide::{ AssistConfig, CompletionConfig, DiagnosticsConfig, HighlightRelatedConfig, HoverConfig, - HoverDocFormat, InlayHintsConfig, JoinLinesConfig, + HoverDocFormat, InlayHintsConfig, JoinLinesConfig, Snippet, SnippetScope, }; use ide_db::helpers::{ insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, @@ -58,6 +58,9 @@ struct ConfigData { /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. assist_allowMergingIntoGlobImports: bool = "true", + /// Warm up caches on project load. + cache_warmup: bool = "true", + /// Show function name and docs in parameter hints. callInfo_full: bool = "true", @@ -112,6 +115,8 @@ struct ConfigData { completion_addCallArgumentSnippets: bool = "true", /// Whether to add parenthesis when completing functions. completion_addCallParenthesis: bool = "true", + /// Custom completion snippets. + completion_snippets: FxHashMap = "{}", /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. completion_postfix_enable: bool = "true", /// Toggles the additional completions that automatically add imports when completed. @@ -193,14 +198,16 @@ struct ConfigData { hoverActions_run: bool = "true", /// Whether to show inlay type hints for method chains. - inlayHints_chainingHints: bool = "true", + inlayHints_chainingHints: bool = "true", /// Maximum length for inlay hints. Set to null to have an unlimited length. - inlayHints_maxLength: Option = "25", + inlayHints_maxLength: Option = "25", /// Whether to show function parameter name inlay hints at the call /// site. - inlayHints_parameterHints: bool = "true", + inlayHints_parameterHints: bool = "true", /// Whether to show inlay type hints for variables. - inlayHints_typeHints: bool = "true", + inlayHints_typeHints: bool = "true", + /// Whether to hide inlay hints for constructors. + inlayHints_hideNamedConstructorHints: bool = "false", /// Join lines inserts else between consecutive ifs. joinLines_joinElseIf: bool = "true", @@ -225,9 +232,12 @@ struct ConfigData { /// Whether to show `Method References` lens. Only applies when /// `#rust-analyzer.lens.enable#` is set. lens_methodReferences: bool = "false", - /// Whether to show `References` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. + /// Whether to show `References` lens for Struct, Enum, Union and Trait. + /// Only applies when `#rust-analyzer.lens.enable#` is set. lens_references: bool = "false", + /// Whether to show `References` lens for Enum Variants. + /// Only applies when `#rust-analyzer.lens.enable#` is set. + lens_enumVariantReferences: bool = "false", /// Internal config: use custom client-side commands even when the /// client doesn't set the corresponding capability. lens_forceCustomCommands: bool = "true", @@ -258,12 +268,13 @@ struct ConfigData { runnables_cargoExtraArgs: Vec = "[]", /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private - /// projects, or "discover" to try to automatically find it. + /// projects, or "discover" to try to automatically find it if the `rustc-dev` component + /// is installed. /// /// Any project which uses rust-analyzer with the rustcPrivate /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it. /// - /// This option is not reloaded automatically; you must restart rust-analyzer for it to take effect. + /// This option does not take effect until rust-analyzer is restarted. rustcSource: Option = "null", /// Additional arguments to `rustfmt`. @@ -277,9 +288,9 @@ struct ConfigData { rustfmt_enableRangeFormatting: bool = "false", /// Workspace symbol search scope. - workspace_symbol_search_scope: WorskpaceSymbolSearchScopeDef = "\"workspace\"", + workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = "\"workspace\"", /// Workspace symbol search kind. - workspace_symbol_search_kind: WorskpaceSymbolSearchKindDef = "\"only_types\"", + workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = "\"only_types\"", } } @@ -296,6 +307,7 @@ pub struct Config { detached_files: Vec, pub discovered_projects: Option>, pub root_path: AbsPathBuf, + snippets: Vec, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -323,6 +335,7 @@ pub struct LensConfig { pub implementations: bool, pub method_refs: bool, pub refs: bool, // for Struct, Enum, Union and Trait + pub enum_variant_refs: bool, } impl LensConfig { @@ -339,7 +352,7 @@ pub fn runnable(&self) -> bool { } pub fn references(&self) -> bool { - self.method_refs || self.refs + self.method_refs || self.refs || self.enum_variant_refs } } @@ -431,6 +444,7 @@ pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { detached_files: Vec::new(), discovered_projects: None, root_path, + snippets: Default::default(), } } pub fn update(&mut self, mut json: serde_json::Value) { @@ -443,6 +457,28 @@ pub fn update(&mut self, mut json: serde_json::Value) { .map(AbsPathBuf::assert) .collect(); self.data = ConfigData::from_json(json); + self.snippets.clear(); + for (name, def) in self.data.completion_snippets.iter() { + if def.prefix.is_empty() && def.postfix.is_empty() { + continue; + } + let scope = match def.scope { + SnippetScopeDef::Expr => SnippetScope::Expr, + SnippetScopeDef::Type => SnippetScope::Type, + SnippetScopeDef::Item => SnippetScope::Item, + }; + match Snippet::new( + &def.prefix, + &def.postfix, + &def.body, + def.description.as_ref().unwrap_or(name), + &def.requires, + scope, + ) { + Some(snippet) => self.snippets.push(snippet), + None => tracing::info!("Invalid snippet {}", name), + } + } } pub fn json_schema() -> serde_json::Value { @@ -512,6 +548,10 @@ pub fn did_change_watched_files_dynamic_registration(&self) -> bool { ) } + pub fn prefill_caches(&self) -> bool { + self.data.cache_warmup + } + pub fn location_link(&self) -> bool { try_or!(self.caps.text_document.as_ref()?.definition?.link_support?, false) } @@ -737,6 +777,7 @@ pub fn inlay_hints(&self) -> InlayHintsConfig { type_hints: self.data.inlayHints_typeHints, parameter_hints: self.data.inlayHints_parameterHints, chaining_hints: self.data.inlayHints_chainingHints, + hide_named_constructor_hints: self.data.inlayHints_hideNamedConstructorHints, max_length: self.data.inlayHints_maxLength, } } @@ -778,6 +819,7 @@ pub fn completion(&self) -> CompletionConfig { .snippet_support?, false )), + snippets: self.snippets.clone(), } } pub fn assist(&self) -> AssistConfig { @@ -805,6 +847,7 @@ pub fn lens(&self) -> LensConfig { implementations: self.data.lens_enable && self.data.lens_implementations, method_refs: self.data.lens_enable && self.data.lens_methodReferences, refs: self.data.lens_enable && self.data.lens_references, + enum_variant_refs: self.data.lens_enable && self.data.lens_enumVariantReferences, } } pub fn hover_actions(&self) -> HoverActionsConfig { @@ -848,14 +891,14 @@ pub fn hover(&self) -> HoverConfig { pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig { WorkspaceSymbolConfig { search_scope: match self.data.workspace_symbol_search_scope { - WorskpaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace, - WorskpaceSymbolSearchScopeDef::WorkspaceAndDependencies => { + WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace, + WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => { WorkspaceSymbolSearchScope::WorkspaceAndDependencies } }, search_kind: match self.data.workspace_symbol_search_kind { - WorskpaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes, - WorskpaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols, + WorkspaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes, + WorkspaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols, }, } } @@ -908,6 +951,66 @@ pub fn highlight_related(&self) -> HighlightRelatedConfig { } } +#[derive(Deserialize, Debug, Clone, Copy)] +#[serde(rename_all = "snake_case")] +enum SnippetScopeDef { + Expr, + Item, + Type, +} + +impl Default for SnippetScopeDef { + fn default() -> Self { + SnippetScopeDef::Expr + } +} + +#[derive(Deserialize, Debug, Clone, Default)] +#[serde(default)] +struct SnippetDef { + #[serde(deserialize_with = "single_or_array")] + prefix: Vec, + #[serde(deserialize_with = "single_or_array")] + postfix: Vec, + description: Option, + #[serde(deserialize_with = "single_or_array")] + body: Vec, + #[serde(deserialize_with = "single_or_array")] + requires: Vec, + scope: SnippetScopeDef, +} + +fn single_or_array<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + struct SingleOrVec; + + impl<'de> serde::de::Visitor<'de> for SingleOrVec { + type Value = Vec; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("string or array of strings") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + Ok(vec![value.to_owned()]) + } + + fn visit_seq(self, seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(seq)) + } + } + + deserializer.deserialize_any(SingleOrVec) +} + #[derive(Deserialize, Debug, Clone)] #[serde(untagged)] enum ManifestOrProjectJson { @@ -939,14 +1042,14 @@ enum ImportPrefixDef { #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] -enum WorskpaceSymbolSearchScopeDef { +enum WorkspaceSymbolSearchScopeDef { Workspace, WorkspaceAndDependencies, } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] -enum WorskpaceSymbolSearchKindDef { +enum WorkspaceSymbolSearchKindDef { OnlyTypes, AllSymbols, } @@ -1077,6 +1180,9 @@ macro_rules! set { "items": { "type": "string" }, "uniqueItems": true, }, + "FxHashMap" => set! { + "type": "object", + }, "FxHashMap" => set! { "type": "object", }, @@ -1133,7 +1239,7 @@ macro_rules! set { "type": "array", "items": { "type": ["string", "object"] }, }, - "WorskpaceSymbolSearchScopeDef" => set! { + "WorkspaceSymbolSearchScopeDef" => set! { "type": "string", "enum": ["workspace", "workspace_and_dependencies"], "enumDescriptions": [ @@ -1141,7 +1247,7 @@ macro_rules! set { "Search in current workspace and dependencies" ], }, - "WorskpaceSymbolSearchKindDef" => set! { + "WorkspaceSymbolSearchKindDef" => set! { "type": "string", "enum": ["only_types", "all_symbols"], "enumDescriptions": [ @@ -1193,6 +1299,29 @@ fn generate_package_json_config() { .to_string(); schema.push_str(",\n"); + // Transform the asciidoc form link to markdown style. + // + // https://link[text] => [text](https://link) + let url_matches = schema.match_indices("https://"); + let mut url_offsets = url_matches.map(|(idx, _)| idx).collect::>(); + url_offsets.reverse(); + for idx in url_offsets { + let link = &schema[idx..]; + // matching on whitespace to ignore normal links + if let Some(link_end) = link.find(|c| c == ' ' || c == '[') { + if link.chars().nth(link_end) == Some('[') { + if let Some(link_text_end) = link.find(']') { + let link_text = link[link_end..(link_text_end + 1)].to_string(); + + schema.replace_range((idx + link_end)..(idx + link_text_end + 1), ""); + schema.insert(idx, '('); + schema.insert(idx + link_end + 1, ')'); + schema.insert_str(idx, &link_text); + } + } + } + } + let package_json_path = project_root().join("editors/code/package.json"); let mut package_json = fs::read_to_string(&package_json_path).unwrap();