Autocomplete rsx (#2421)
* autocomplete rsx * hide the completions module * fix autocomplete for identifiers that start with a raw identifier * add field completion hints for props * remove extra import * Revert "add field completion hints for props" This reverts commit 194899c73783e0f9b5d601d53365746d838f2048. * fix autocomplete inside raw expressions * fix autofmt * feat: just use regular ifmt if it's compatible reuses the tokens for ifmt so RA provides its HIR lowering on simple formatted strings * fix merging ifmt strings * add a better error message for components called like functions --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
245003a5d4
commit
2523581cf4
21 files changed
+788
-217
No files matched your search
@@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
|
||||
use super::*;
|
||||
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::quote;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{parse_quote, spanned::Spanned, Expr, ExprIf, Ident, LitStr};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||
@@ -95,6 +95,9 @@ impl AttributeType {
|
||||
pub struct ElementAttrNamed {
|
||||
pub el_name: ElementName,
|
||||
pub attr: ElementAttr,
|
||||
// If this is the last attribute of an element and it doesn't have a tailing comma,
|
||||
// we add hints so that rust analyzer completes it either as an attribute or element
|
||||
pub(crate) followed_by_comma: bool,
|
||||
}
|
||||
|
||||
impl Hash for ElementAttrNamed {
|
||||
@@ -112,6 +115,15 @@ impl PartialEq for ElementAttrNamed {
|
||||
impl Eq for ElementAttrNamed {}
|
||||
|
||||
impl ElementAttrNamed {
|
||||
/// Create a new ElementAttrNamed
|
||||
pub fn new(el_name: ElementName, attr: ElementAttr) -> Self {
|
||||
Self {
|
||||
el_name,
|
||||
attr,
|
||||
followed_by_comma: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_combine(&self, other: &Self) -> Option<Self> {
|
||||
if self.el_name == other.el_name && self.attr.name == other.attr.name {
|
||||
if let Some(separator) = self.attr.name.multi_attribute_separator() {
|
||||
@@ -121,16 +133,64 @@ impl ElementAttrNamed {
|
||||
name: self.attr.name.clone(),
|
||||
value: self.attr.value.combine(separator, &other.attr.value),
|
||||
},
|
||||
followed_by_comma: self.followed_by_comma || other.followed_by_comma,
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// If this is the last attribute of an element and it doesn't have a tailing comma,
|
||||
/// we add hints so that rust analyzer completes it either as an attribute or element
|
||||
fn completion_hints(&self) -> TokenStream2 {
|
||||
let ElementAttrNamed {
|
||||
el_name,
|
||||
attr,
|
||||
followed_by_comma,
|
||||
} = self;
|
||||
|
||||
// If there is a trailing comma, rust analyzer does a good job of completing the attribute by itself
|
||||
if *followed_by_comma {
|
||||
return quote! {};
|
||||
}
|
||||
// Only add hints if the attribute is:
|
||||
// - a built in attribute (not a literal)
|
||||
// - an build in element (not a custom element)
|
||||
// - a shorthand attribute
|
||||
let (
|
||||
ElementName::Ident(el),
|
||||
ElementAttrName::BuiltIn(name),
|
||||
ElementAttrValue::Shorthand(_),
|
||||
) = (el_name, &attr.name, &attr.value)
|
||||
else {
|
||||
return quote! {};
|
||||
};
|
||||
// If the attribute is a shorthand attribute, but it is an event handler, rust analyzer already does a good job of completing the attribute by itself
|
||||
if name.to_string().starts_with("on") {
|
||||
return quote! {};
|
||||
}
|
||||
|
||||
quote! {
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
#[doc(hidden)]
|
||||
mod __completions {
|
||||
// Autocomplete as an attribute
|
||||
pub use super::dioxus_elements::#el::*;
|
||||
// Autocomplete as an element
|
||||
pub use super::dioxus_elements::elements::completions::CompleteWithBraces::*;
|
||||
fn ignore() {
|
||||
#name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ElementAttrNamed {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let ElementAttrNamed { el_name, attr } = self;
|
||||
let ElementAttrNamed { el_name, attr, .. } = self;
|
||||
|
||||
let ns = |name: &ElementAttrName| match (el_name, name) {
|
||||
(ElementName::Ident(i), ElementAttrName::BuiltIn(_)) => {
|
||||
@@ -186,19 +246,25 @@ impl ToTokens for ElementAttrNamed {
|
||||
}
|
||||
ElementAttrValue::EventTokens(tokens) => match &self.attr.name {
|
||||
ElementAttrName::BuiltIn(name) => {
|
||||
quote! {
|
||||
quote_spanned! { tokens.span() =>
|
||||
dioxus_elements::events::#name(#tokens)
|
||||
}
|
||||
}
|
||||
ElementAttrName::Custom(_) => unreachable!("Handled elsewhere in the macro"),
|
||||
},
|
||||
_ => {
|
||||
quote! { dioxus_elements::events::#value(#value) }
|
||||
quote_spanned! { value.span() => dioxus_elements::events::#value(#value) }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tokens.append_all(attribute);
|
||||
let completion_hints = self.completion_hints();
|
||||
tokens.append_all(quote! {
|
||||
{
|
||||
#completion_hints
|
||||
#attribute
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +355,11 @@ impl ToTokens for ElementAttrValue {
|
||||
}
|
||||
|
||||
impl ElementAttrValue {
|
||||
/// Create a new ElementAttrValue::Shorthand from an Ident and normalize the identifier
|
||||
pub(crate) fn shorthand(name: &Ident) -> Self {
|
||||
Self::Shorthand(normalize_raw_ident(name))
|
||||
}
|
||||
|
||||
pub fn is_shorthand(&self) -> bool {
|
||||
matches!(self, ElementAttrValue::Shorthand(_))
|
||||
}
|
||||
@@ -388,6 +459,16 @@ impl ElementAttrValue {
|
||||
}
|
||||
}
|
||||
|
||||
// Create and normalize a built-in attribute name
|
||||
// If the identifier is a reserved keyword, this method will create a raw identifier
|
||||
fn normalize_raw_ident(ident: &Ident) -> Ident {
|
||||
if syn::parse2::<syn::Ident>(ident.to_token_stream()).is_err() {
|
||||
syn::Ident::new_raw(&ident.to_string(), ident.span())
|
||||
} else {
|
||||
ident.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||
pub enum ElementAttrName {
|
||||
BuiltIn(Ident),
|
||||
@@ -395,6 +476,10 @@ pub enum ElementAttrName {
|
||||
}
|
||||
|
||||
impl ElementAttrName {
|
||||
pub(crate) fn built_in(name: &Ident) -> Self {
|
||||
Self::BuiltIn(normalize_raw_ident(name))
|
||||
}
|
||||
|
||||
fn multi_attribute_separator(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
ElementAttrName::BuiltIn(i) => match i.to_string().as_str() {
|
||||
|
||||
Reference in new issue
Block a user