diff options
author | Lukas Wirth <[email protected]> | 2021-03-16 17:57:47 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-03-16 17:57:47 +0000 |
commit | 11e9bc60a2d9c22dbf51b7e1aa3d6e30a7006a35 (patch) | |
tree | c45f80a838b17f45ec87282fa4377b35da284096 | |
parent | a69f7ce312ba04acbca970a61d9576d520dacb2e (diff) |
Move doc-comment highlight injection from AST to HIR
-rw-r--r-- | crates/hir/src/attrs.rs | 5 | ||||
-rw-r--r-- | crates/hir/src/semantics.rs | 1 | ||||
-rw-r--r-- | crates/hir/src/semantics/source_to_def.rs | 6 | ||||
-rw-r--r-- | crates/hir_def/src/attr.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/inject.rs | 65 |
6 files changed, 63 insertions, 18 deletions
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 9e6a3e155..505fc05e7 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -11,8 +11,8 @@ use hir_ty::db::HirDatabase; | |||
11 | use syntax::ast; | 11 | use syntax::ast; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | Adt, Const, ConstParam, Enum, Field, Function, GenericParam, LifetimeParam, MacroDef, Module, | 14 | Adt, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam, MacroDef, |
15 | ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, | 15 | Module, ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub trait HasAttrs { | 18 | pub trait HasAttrs { |
@@ -64,6 +64,7 @@ impl_has_attrs![ | |||
64 | (Adt, AdtId), | 64 | (Adt, AdtId), |
65 | (Module, ModuleId), | 65 | (Module, ModuleId), |
66 | (GenericParam, GenericParamId), | 66 | (GenericParam, GenericParamId), |
67 | (Impl, ImplId), | ||
67 | ]; | 68 | ]; |
68 | 69 | ||
69 | macro_rules! impl_has_attrs_enum { | 70 | macro_rules! impl_has_attrs_enum { |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 03c9371b5..c7e0d0be3 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -752,6 +752,7 @@ macro_rules! to_def_impls { | |||
752 | 752 | ||
753 | to_def_impls![ | 753 | to_def_impls![ |
754 | (crate::Module, ast::Module, module_to_def), | 754 | (crate::Module, ast::Module, module_to_def), |
755 | (crate::Module, ast::SourceFile, source_file_to_def), | ||
755 | (crate::Struct, ast::Struct, struct_to_def), | 756 | (crate::Struct, ast::Struct, struct_to_def), |
756 | (crate::Enum, ast::Enum, enum_to_def), | 757 | (crate::Enum, ast::Enum, enum_to_def), |
757 | (crate::Union, ast::Union, union_to_def), | 758 | (crate::Union, ast::Union, union_to_def), |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index e9d820140..c6ad5ecb5 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -71,6 +71,12 @@ impl SourceToDefCtx<'_, '_> { | |||
71 | Some(def_map.module_id(child_id)) | 71 | Some(def_map.module_id(child_id)) |
72 | } | 72 | } |
73 | 73 | ||
74 | pub(super) fn source_file_to_def(&mut self, src: InFile<ast::SourceFile>) -> Option<ModuleId> { | ||
75 | let _p = profile::span("source_file_to_def"); | ||
76 | let file_id = src.file_id.original_file(self.db.upcast()); | ||
77 | self.file_to_def(file_id).get(0).copied() | ||
78 | } | ||
79 | |||
74 | pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> { | 80 | pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> { |
75 | self.to_def(src, keys::TRAIT) | 81 | self.to_def(src, keys::TRAIT) |
76 | } | 82 | } |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 7b41b148c..505c4cd17 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -475,7 +475,7 @@ impl<'a> AttrQuery<'a> { | |||
475 | self.attrs().next().is_some() | 475 | self.attrs().next().is_some() |
476 | } | 476 | } |
477 | 477 | ||
478 | pub(crate) fn attrs(self) -> impl Iterator<Item = &'a Attr> { | 478 | pub fn attrs(self) -> impl Iterator<Item = &'a Attr> { |
479 | let key = self.key; | 479 | let key = self.key; |
480 | self.attrs | 480 | self.attrs |
481 | .iter() | 481 | .iter() |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 870146d24..ba3447b3a 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -150,7 +150,7 @@ fn traverse( | |||
150 | WalkEvent::Enter(it) => it, | 150 | WalkEvent::Enter(it) => it, |
151 | WalkEvent::Leave(it) => { | 151 | WalkEvent::Leave(it) => { |
152 | if let Some(node) = it.as_node() { | 152 | if let Some(node) = it.as_node() { |
153 | inject::doc_comment(hl, node); | 153 | inject::doc_comment(hl, sema, node); |
154 | } | 154 | } |
155 | continue; | 155 | continue; |
156 | } | 156 | } |
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 8cdc3688f..5b065c09f 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -1,8 +1,12 @@ | |||
1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. | 1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. |
2 | 2 | ||
3 | use hir::Semantics; | 3 | use either::Either; |
4 | use hir::{HasAttrs, Semantics}; | ||
4 | use ide_db::call_info::ActiveParameter; | 5 | use ide_db::call_info::ActiveParameter; |
5 | use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | 6 | use syntax::{ |
7 | ast::{self, AstNode, AttrsOwner}, | ||
8 | match_ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize, | ||
9 | }; | ||
6 | 10 | ||
7 | use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; | 11 | use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; |
8 | 12 | ||
@@ -81,16 +85,46 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ | |||
81 | "edition2021", | 85 | "edition2021", |
82 | ]; | 86 | ]; |
83 | 87 | ||
88 | fn doc_attributes<'node>( | ||
89 | sema: &Semantics<RootDatabase>, | ||
90 | node: &'node SyntaxNode, | ||
91 | ) -> Option<(Box<dyn AttrsOwner>, hir::Attrs)> { | ||
92 | match_ast! { | ||
93 | match node { | ||
94 | ast::SourceFile(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
95 | ast::Fn(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
96 | ast::Struct(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
97 | ast::Union(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
98 | ast::RecordField(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
99 | ast::TupleField(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
100 | ast::Enum(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
101 | ast::Variant(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
102 | ast::Trait(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
103 | ast::Module(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
104 | ast::Static(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
105 | ast::Const(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
106 | ast::TypeAlias(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
107 | ast::Impl(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
108 | ast::MacroRules(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
109 | ast::MacroRules(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
110 | // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
111 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
112 | _ => return None | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | |||
84 | /// Injection of syntax highlighting of doctests. | 117 | /// Injection of syntax highlighting of doctests. |
85 | pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | 118 | pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) { |
86 | let doc_comments = node | 119 | let (owner, attributes) = match doc_attributes(sema, node) { |
87 | .children_with_tokens() | 120 | Some(it) => it, |
88 | .filter_map(|it| it.into_token().and_then(ast::Comment::cast)) | 121 | None => return, |
89 | .filter(|it| it.kind().doc.is_some()); | 122 | }; |
90 | 123 | ||
91 | if !doc_comments.clone().any(|it| it.text().contains(RUSTDOC_FENCE)) { | 124 | if attributes.docs().map_or(true, |docs| !String::from(docs).contains(RUSTDOC_FENCE)) { |
92 | return; | 125 | return; |
93 | } | 126 | } |
127 | let doc_comments = attributes.by_key("doc").attrs().map(|attr| attr.to_src(&*owner)); | ||
94 | 128 | ||
95 | let mut inj = Injector::default(); | 129 | let mut inj = Injector::default(); |
96 | inj.add_unmapped("fn doctest() {\n"); | 130 | inj.add_unmapped("fn doctest() {\n"); |
@@ -102,11 +136,17 @@ pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | |||
102 | // spanning comment ranges. | 136 | // spanning comment ranges. |
103 | let mut new_comments = Vec::new(); | 137 | let mut new_comments = Vec::new(); |
104 | for comment in doc_comments { | 138 | for comment in doc_comments { |
105 | match comment.text().find(RUSTDOC_FENCE) { | 139 | let (line, range, prefix) = match &comment { |
140 | Either::Left(_) => continue, // FIXME | ||
141 | Either::Right(comment) => { | ||
142 | (comment.text(), comment.syntax().text_range(), comment.prefix()) | ||
143 | } | ||
144 | }; | ||
145 | match line.find(RUSTDOC_FENCE) { | ||
106 | Some(idx) => { | 146 | Some(idx) => { |
107 | is_codeblock = !is_codeblock; | 147 | is_codeblock = !is_codeblock; |
108 | // Check whether code is rust by inspecting fence guards | 148 | // Check whether code is rust by inspecting fence guards |
109 | let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..]; | 149 | let guards = &line[idx + RUSTDOC_FENCE.len()..]; |
110 | let is_rust = | 150 | let is_rust = |
111 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); | 151 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); |
112 | is_doctest = is_codeblock && is_rust; | 152 | is_doctest = is_codeblock && is_rust; |
@@ -116,10 +156,7 @@ pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | |||
116 | None => (), | 156 | None => (), |
117 | } | 157 | } |
118 | 158 | ||
119 | let line: &str = comment.text(); | 159 | let mut pos = TextSize::of(prefix); |
120 | let range = comment.syntax().text_range(); | ||
121 | |||
122 | let mut pos = TextSize::of(comment.prefix()); | ||
123 | // whitespace after comment is ignored | 160 | // whitespace after comment is ignored |
124 | if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { | 161 | if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { |
125 | pos += TextSize::of(ws); | 162 | pos += TextSize::of(ws); |