diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 210c5c7facd2..bfbe0db6e4b8 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -41,6 +41,12 @@ pub struct AnnotationConfig { pub annotate_references: bool, pub annotate_method_references: bool, pub annotate_enum_variant_references: bool, + pub location: AnnotationLocation, +} + +pub enum AnnotationLocation { + AboveName, + AboveWholeItem, } pub(crate) fn annotations( @@ -65,10 +71,10 @@ pub(crate) fn annotations( visit_file_defs(&Semantics::new(db), file_id, &mut |def| { let range = match def { Definition::Const(konst) if config.annotate_references => { - konst.source(db).and_then(|node| name_range(db, node, file_id)) + konst.source(db).and_then(|node| name_range(db, config, node, file_id)) } Definition::Trait(trait_) if config.annotate_references || config.annotate_impls => { - trait_.source(db).and_then(|node| name_range(db, node, file_id)) + trait_.source(db).and_then(|node| name_range(db, config, node, file_id)) } Definition::Adt(adt) => match adt { hir::Adt::Enum(enum_) => { @@ -77,7 +83,9 @@ pub(crate) fn annotations( .variants(db) .into_iter() .map(|variant| { - variant.source(db).and_then(|node| name_range(db, node, file_id)) + variant + .source(db) + .and_then(|node| name_range(db, config, node, file_id)) }) .flatten() .for_each(|range| { @@ -88,14 +96,14 @@ pub(crate) fn annotations( }) } if config.annotate_references || config.annotate_impls { - enum_.source(db).and_then(|node| name_range(db, node, file_id)) + enum_.source(db).and_then(|node| name_range(db, config, node, file_id)) } else { None } } _ => { if config.annotate_references || config.annotate_impls { - adt.source(db).and_then(|node| name_range(db, node, file_id)) + adt.source(db).and_then(|node| name_range(db, config, node, file_id)) } else { None } @@ -113,6 +121,7 @@ pub(crate) fn annotations( annotations .push(Annotation { range, kind: AnnotationKind::HasImpls { file_id, data: None } }); } + if config.annotate_references { annotations.push(Annotation { range, @@ -122,12 +131,18 @@ pub(crate) fn annotations( fn name_range( db: &RootDatabase, + config: &AnnotationConfig, node: InFile, source_file_id: FileId, ) -> Option { if let Some(InFile { file_id, value }) = node.original_ast_node(db) { if file_id == source_file_id.into() { - return value.name().map(|it| it.syntax().text_range()); + return match config.location { + AnnotationLocation::AboveName => { + value.name().map(|name| name.syntax().text_range()) + } + AnnotationLocation::AboveWholeItem => Some(value.syntax().text_range()), + }; } } None @@ -188,21 +203,23 @@ mod tests { use crate::{fixture, Annotation, AnnotationConfig}; - fn check(ra_fixture: &str, expect: Expect) { + use super::AnnotationLocation; + + const DEFAULT_CONFIG: AnnotationConfig = AnnotationConfig { + binary_target: true, + annotate_runnables: true, + annotate_impls: true, + annotate_references: true, + annotate_method_references: true, + annotate_enum_variant_references: true, + location: AnnotationLocation::AboveName, + }; + + fn check_with_config(ra_fixture: &str, expect: Expect, config: &AnnotationConfig) { let (analysis, file_id) = fixture::file(ra_fixture); let annotations: Vec = analysis - .annotations( - &AnnotationConfig { - binary_target: true, - annotate_runnables: true, - annotate_impls: true, - annotate_references: true, - annotate_method_references: true, - annotate_enum_variant_references: true, - }, - file_id, - ) + .annotations(config, file_id) .unwrap() .into_iter() .map(|annotation| analysis.resolve_annotation(annotation).unwrap()) @@ -211,6 +228,10 @@ mod tests { expect.assert_debug_eq(&annotations); } + fn check(ra_fixture: &str, expect: Expect) { + check_with_config(ra_fixture, expect, &DEFAULT_CONFIG); + } + #[test] fn const_annotations() { check( @@ -786,4 +807,40 @@ m!(); "#]], ); } + + #[test] + fn test_annotations_appear_above_whole_item_when_configured_to_do_so() { + check_with_config( + r#" +/// This is a struct named Foo, obviously. +#[derive(Clone)] +struct Foo; +"#, + expect![[r#" + [ + Annotation { + range: 0..71, + kind: HasImpls { + file_id: FileId( + 0, + ), + data: Some( + [], + ), + }, + }, + Annotation { + range: 0..71, + kind: HasReferences { + file_id: FileId( + 0, + ), + data: None, + }, + }, + ] + "#]], + &AnnotationConfig { location: AnnotationLocation::AboveWholeItem, ..DEFAULT_CONFIG }, + ); + } } diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 0552330814aa..c1ef25b592b1 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -74,7 +74,7 @@ use syntax::SourceFile; use crate::navigation_target::{ToNav, TryToNav}; pub use crate::{ - annotations::{Annotation, AnnotationConfig, AnnotationKind}, + annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation}, call_hierarchy::CallItem, expand_macro::ExpandedMacro, file_structure::{StructureNode, StructureNodeKind}, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8504712c4bd5..3cafbc743351 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -308,6 +308,7 @@ config_data! { /// Join lines unwraps trivial blocks. joinLines_unwrapTrivialBlock: bool = "true", + /// Whether to show `Debug` lens. Only applies when /// `#rust-analyzer.lens.enable#` is set. lens_debug_enable: bool = "true", @@ -319,6 +320,8 @@ config_data! { /// Whether to show `Implementations` lens. Only applies when /// `#rust-analyzer.lens.enable#` is set. lens_implementations_enable: bool = "true", + /// Where to render annotations. + lens_location: AnnotationLocation = "\"above_name\"", /// Whether to show `References` lens for Struct, Enum, and Union. /// Only applies when `#rust-analyzer.lens.enable#` is set. lens_references_adt_enable: bool = "false", @@ -498,6 +501,25 @@ pub struct LensConfig { pub refs_adt: bool, // for Struct, Enum, Union and Trait pub refs_trait: bool, // for Struct, Enum, Union and Trait pub enum_variant_refs: bool, + + // annotations + pub location: AnnotationLocation, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum AnnotationLocation { + AboveName, + AboveWholeItem, +} + +impl From for ide::AnnotationLocation { + fn from(location: AnnotationLocation) -> Self { + match location { + AnnotationLocation::AboveName => ide::AnnotationLocation::AboveName, + AnnotationLocation::AboveWholeItem => ide::AnnotationLocation::AboveWholeItem, + } + } } impl LensConfig { @@ -1196,6 +1218,7 @@ impl Config { refs_trait: self.data.lens_enable && self.data.lens_references_trait_enable, enum_variant_refs: self.data.lens_enable && self.data.lens_references_enumVariant_enable, + location: self.data.lens_location, } } @@ -1932,6 +1955,14 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "Use server-side file watching", ], }, + "AnnotationLocation" => set! { + "type": "string", + "enum": ["above_name", "above_whole_item"], + "enumDescriptions": [ + "Render annotations above the name of the item.", + "Render annotations above the whole item, including documentation comments and attributes." + ], + }, _ => panic!("missing entry for {}: {}", ty, default), } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index baf6dd7488bc..7dfa32cf3743 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1240,6 +1240,7 @@ pub(crate) fn handle_code_lens( annotate_references: lens_config.refs_adt, annotate_method_references: lens_config.method_refs, annotate_enum_variant_references: lens_config.enum_variant_refs, + location: lens_config.location.into(), }, file_id, )?; diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index e596e08f2cd3..62671459d7ba 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -479,6 +479,11 @@ client doesn't set the corresponding capability. Whether to show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set. -- +[[rust-analyzer.lens.location]]rust-analyzer.lens.location (default: `"above_name"`):: ++ +-- +Where to render annotations. +-- [[rust-analyzer.lens.references.adt.enable]]rust-analyzer.lens.references.adt.enable (default: `false`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 6aa74ce92afb..e2cc2c16c926 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -963,6 +963,19 @@ "default": true, "type": "boolean" }, + "rust-analyzer.lens.location": { + "markdownDescription": "Where to render annotations.", + "default": "above_name", + "type": "string", + "enum": [ + "above_name", + "above_whole_item" + ], + "enumDescriptions": [ + "Render annotations above the name of the item.", + "Render annotations above the whole item, including documentation comments and attributes." + ] + }, "rust-analyzer.lens.references.adt.enable": { "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", "default": false,