Auto merge of #12844 - Veykril:highlight-attr, r=Veykril
fix: Improve syntax highlighting in attributes Fixes https://github.com/rust-lang/rust-analyzer/issues/12842
This commit is contained in:
commit
7e30ca1f2a
@ -22,7 +22,7 @@
|
|||||||
use syntax::{
|
use syntax::{
|
||||||
algo::skip_trivia_token,
|
algo::skip_trivia_token,
|
||||||
ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody},
|
ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody},
|
||||||
match_ast, AstNode, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
|
match_ast, AstNode, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -217,6 +217,10 @@ pub fn descend_into_macros_with_same_text(
|
|||||||
self.imp.descend_into_macros_with_same_text(token)
|
self.imp.descend_into_macros_with_same_text(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn descend_into_macros_with_kind_preference(&self, token: SyntaxToken) -> SyntaxToken {
|
||||||
|
self.imp.descend_into_macros_with_kind_preference(token)
|
||||||
|
}
|
||||||
|
|
||||||
/// Maps a node down by mapping its first and last token down.
|
/// Maps a node down by mapping its first and last token down.
|
||||||
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
|
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
|
||||||
self.imp.descend_node_into_attributes(node)
|
self.imp.descend_node_into_attributes(node)
|
||||||
@ -680,6 +684,32 @@ fn speculative_expand_derive_as_pseudo_attr_macro(
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn descend_into_macros_with_kind_preference(&self, token: SyntaxToken) -> SyntaxToken {
|
||||||
|
let fetch_kind = |token: &SyntaxToken| match token.parent() {
|
||||||
|
Some(node) => match node.kind() {
|
||||||
|
kind @ (SyntaxKind::NAME | SyntaxKind::NAME_REF) => {
|
||||||
|
node.parent().map_or(kind, |it| it.kind())
|
||||||
|
}
|
||||||
|
_ => token.kind(),
|
||||||
|
},
|
||||||
|
None => token.kind(),
|
||||||
|
};
|
||||||
|
let preferred_kind = fetch_kind(&token);
|
||||||
|
let mut res = None;
|
||||||
|
self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
|
||||||
|
if fetch_kind(&value) == preferred_kind {
|
||||||
|
res = Some(value);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
if let None = res {
|
||||||
|
res = Some(value)
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res.unwrap_or(token)
|
||||||
|
}
|
||||||
|
|
||||||
fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
|
fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
|
||||||
let mut res = token.clone();
|
let mut res = token.clone();
|
||||||
self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
|
self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
|
||||||
|
@ -206,6 +206,19 @@ fn traverse(
|
|||||||
let is_unlinked = sema.to_module_def(file_id).is_none();
|
let is_unlinked = sema.to_module_def(file_id).is_none();
|
||||||
let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
|
let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
|
||||||
|
|
||||||
|
enum AttrOrDerive {
|
||||||
|
Attr(ast::Item),
|
||||||
|
Derive(ast::Item),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttrOrDerive {
|
||||||
|
fn item(&self) -> &ast::Item {
|
||||||
|
match self {
|
||||||
|
AttrOrDerive::Attr(item) | AttrOrDerive::Derive(item) => item,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut tt_level = 0;
|
let mut tt_level = 0;
|
||||||
let mut attr_or_derive_item = None;
|
let mut attr_or_derive_item = None;
|
||||||
let mut current_macro: Option<ast::Macro> = None;
|
let mut current_macro: Option<ast::Macro> = None;
|
||||||
@ -260,7 +273,7 @@ fn traverse(
|
|||||||
|
|
||||||
if attr_or_derive_item.is_none() {
|
if attr_or_derive_item.is_none() {
|
||||||
if sema.is_attr_macro_call(&item) {
|
if sema.is_attr_macro_call(&item) {
|
||||||
attr_or_derive_item = Some(item);
|
attr_or_derive_item = Some(AttrOrDerive::Attr(item));
|
||||||
} else {
|
} else {
|
||||||
let adt = match item {
|
let adt = match item {
|
||||||
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
|
ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
|
||||||
@ -270,7 +283,8 @@ fn traverse(
|
|||||||
};
|
};
|
||||||
match adt {
|
match adt {
|
||||||
Some(adt) if sema.is_derive_annotated(&adt) => {
|
Some(adt) if sema.is_derive_annotated(&adt) => {
|
||||||
attr_or_derive_item = Some(ast::Item::from(adt));
|
attr_or_derive_item =
|
||||||
|
Some(AttrOrDerive::Derive(ast::Item::from(adt)));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -292,7 +306,9 @@ fn traverse(
|
|||||||
current_macro = None;
|
current_macro = None;
|
||||||
macro_highlighter = MacroHighlighter::default();
|
macro_highlighter = MacroHighlighter::default();
|
||||||
}
|
}
|
||||||
Some(item) if attr_or_derive_item.as_ref().map_or(false, |it| *it == item) => {
|
Some(item)
|
||||||
|
if attr_or_derive_item.as_ref().map_or(false, |it| *it.item() == item) =>
|
||||||
|
{
|
||||||
attr_or_derive_item = None;
|
attr_or_derive_item = None;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -330,15 +346,26 @@ fn traverse(
|
|||||||
|
|
||||||
// Descending tokens into macros is expensive even if no descending occurs, so make sure
|
// Descending tokens into macros is expensive even if no descending occurs, so make sure
|
||||||
// that we actually are in a position where descending is possible.
|
// that we actually are in a position where descending is possible.
|
||||||
let in_macro = tt_level > 0 || attr_or_derive_item.is_some();
|
let in_macro = tt_level > 0
|
||||||
|
|| match attr_or_derive_item {
|
||||||
|
Some(AttrOrDerive::Attr(_)) => true,
|
||||||
|
Some(AttrOrDerive::Derive(_)) => inside_attribute,
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
let descended_element = if in_macro {
|
let descended_element = if in_macro {
|
||||||
// Attempt to descend tokens into macro-calls.
|
// Attempt to descend tokens into macro-calls.
|
||||||
match element {
|
match element {
|
||||||
NodeOrToken::Token(token) if token.kind() != COMMENT => {
|
NodeOrToken::Token(token) if token.kind() != COMMENT => {
|
||||||
let token = sema.descend_into_macros_single(token);
|
let token = match attr_or_derive_item {
|
||||||
|
Some(AttrOrDerive::Attr(_)) => {
|
||||||
|
sema.descend_into_macros_with_kind_preference(token)
|
||||||
|
}
|
||||||
|
Some(AttrOrDerive::Derive(_)) | None => {
|
||||||
|
sema.descend_into_macros_single(token)
|
||||||
|
}
|
||||||
|
};
|
||||||
match token.parent().and_then(ast::NameLike::cast) {
|
match token.parent().and_then(ast::NameLike::cast) {
|
||||||
// Remap the token into the wrapping single token nodes
|
// Remap the token into the wrapping single token nodes
|
||||||
// FIXME: if the node doesn't resolve, we also won't do token based highlighting!
|
|
||||||
Some(parent) => match (token.kind(), parent.syntax().kind()) {
|
Some(parent) => match (token.kind(), parent.syntax().kind()) {
|
||||||
(T![self] | T![ident], NAME | NAME_REF) => NodeOrToken::Node(parent),
|
(T![self] | T![ident], NAME | NAME_REF) => NodeOrToken::Node(parent),
|
||||||
(T![self] | T![super] | T![crate] | T![Self], NAME_REF) => {
|
(T![self] | T![super] | T![crate] | T![Self], NAME_REF) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user