Skip to content

Commit 2523581

Browse files
ealmloffjkelleyrtp
andauthored
Autocomplete rsx (DioxusLabs#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 194899c. * 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 <[email protected]>
1 parent 245003a commit 2523581

File tree

21 files changed

+788
-217
lines changed

21 files changed

+788
-217
lines changed

packages/autofmt/src/element.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ impl Writer<'_> {
5252
..
5353
} = el;
5454

55+
let brace = brace
56+
.as_ref()
57+
.expect("braces should always be present in strict mode");
58+
5559
/*
5660
1. Write the tag
5761
2. Write the key
@@ -426,7 +430,7 @@ impl Writer<'_> {
426430
}
427431
}
428432

429-
fn get_expr_length(expr: &Expr) -> Option<usize> {
433+
fn get_expr_length(expr: &impl Spanned) -> Option<usize> {
430434
let span = expr.span();
431435
let (start, end) = (span.start(), span.end());
432436
if start.line == end.line {

packages/autofmt/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use collect_macros::byte_offset;
99
use dioxus_rsx::{BodyNode, CallBody, IfmtInput};
1010
use proc_macro2::LineColumn;
1111
use quote::ToTokens;
12-
use syn::{ExprMacro, MacroDelimiter};
12+
use syn::{parse::Parser, ExprMacro, MacroDelimiter};
1313

1414
mod buffer;
1515
mod collect_macros;
@@ -77,7 +77,7 @@ pub fn fmt_file(contents: &str, indent: IndentOptions) -> Vec<FormattedBlock> {
7777
continue;
7878
}
7979

80-
let body = item.parse_body::<CallBody>().unwrap();
80+
let body = item.parse_body_with(CallBody::parse_strict).unwrap();
8181

8282
let rsx_start = macro_path.span().start();
8383

@@ -153,7 +153,7 @@ fn write_body(buf: &mut Writer, body: &CallBody) {
153153
}
154154

155155
pub fn fmt_block_from_expr(raw: &str, expr: ExprMacro) -> Option<String> {
156-
let body = syn::parse2::<CallBody>(expr.mac.tokens).unwrap();
156+
let body = CallBody::parse_strict.parse2(expr.mac.tokens).unwrap();
157157

158158
let mut buf = Writer::new(raw);
159159

@@ -163,7 +163,7 @@ pub fn fmt_block_from_expr(raw: &str, expr: ExprMacro) -> Option<String> {
163163
}
164164

165165
pub fn fmt_block(block: &str, indent_level: usize, indent: IndentOptions) -> Option<String> {
166-
let body = syn::parse_str::<dioxus_rsx::CallBody>(block).unwrap();
166+
let body = CallBody::parse_strict.parse_str(block).unwrap();
167167

168168
let mut buf = Writer::new(block);
169169

packages/core-macro/src/component.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,15 @@ impl ToTokens for ComponentBody {
5151
}
5252
};
5353

54+
let completion_hints = self.completion_hints();
55+
5456
tokens.append_all(quote! {
5557
#props_struct
5658

5759
#[allow(non_snake_case)]
5860
#comp_fn
61+
62+
#completion_hints
5963
});
6064
}
6165
}
@@ -221,6 +225,31 @@ impl ComponentBody {
221225

222226
false
223227
}
228+
229+
// We generate an extra enum to help us autocomplete the braces after the component.
230+
// This is a bit of a hack, but it's the only way to get the braces to autocomplete.
231+
fn completion_hints(&self) -> TokenStream {
232+
let comp_fn = &self.item_fn.sig.ident;
233+
let completions_mod = Ident::new(&format!("{}_completions", comp_fn), comp_fn.span());
234+
235+
let vis = &self.item_fn.vis;
236+
237+
quote! {
238+
#[allow(non_snake_case)]
239+
#[doc(hidden)]
240+
mod #completions_mod {
241+
#[doc(hidden)]
242+
#[allow(non_camel_case_types)]
243+
/// This enum is generated to help autocomplete the braces after the component. It does nothing
244+
pub enum Component {
245+
#comp_fn {}
246+
}
247+
}
248+
249+
#[allow(unused)]
250+
#vis use #completions_mod::Component::#comp_fn;
251+
}
252+
}
224253
}
225254

226255
struct DocField<'a> {

packages/dioxus-lib/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub mod prelude {
4242
pub use dioxus_html as dioxus_elements;
4343

4444
#[cfg(feature = "html")]
45-
pub use dioxus_elements::{prelude::*, GlobalAttributes, SvgAttributes};
45+
pub use dioxus_elements::{global_attributes, prelude::*, svg_attributes};
4646

4747
pub use dioxus_core;
4848
}

packages/dioxus/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub mod prelude {
6565

6666
#[cfg(feature = "html")]
6767
#[cfg_attr(docsrs, doc(cfg(feature = "html")))]
68-
pub use dioxus_elements::{prelude::*, GlobalAttributes, SvgAttributes};
68+
pub use dioxus_elements::{global_attributes, prelude::*, svg_attributes};
6969

7070
#[cfg(all(
7171
not(any(target_arch = "wasm32", target_os = "ios", target_os = "android")),

packages/html-internal-macro/src/lib.rs

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ pub fn impl_extension_attributes(input: TokenStream) -> TokenStream {
1414
}
1515

1616
struct ImplExtensionAttributes {
17-
is_element: bool,
1817
name: Ident,
1918
attrs: Punctuated<Ident, Token![,]>,
2019
}
@@ -23,16 +22,11 @@ impl Parse for ImplExtensionAttributes {
2322
fn parse(input: ParseStream) -> syn::Result<Self> {
2423
let content;
2524

26-
let element: Ident = input.parse()?;
2725
let name = input.parse()?;
2826
braced!(content in input);
2927
let attrs = content.parse_terminated(Ident::parse, Token![,])?;
3028

31-
Ok(ImplExtensionAttributes {
32-
is_element: element == "ELEMENT",
33-
name,
34-
attrs,
35-
})
29+
Ok(ImplExtensionAttributes { name, attrs })
3630
}
3731
}
3832

@@ -44,22 +38,10 @@ impl ToTokens for ImplExtensionAttributes {
4438
.strip_prefix("r#")
4539
.unwrap_or(&name_string)
4640
.to_case(Case::UpperCamel);
47-
let impl_name = Ident::new(format!("{}Impl", &camel_name).as_str(), name.span());
4841
let extension_name = Ident::new(format!("{}Extension", &camel_name).as_str(), name.span());
4942

50-
if !self.is_element {
51-
tokens.append_all(quote! {
52-
struct #impl_name;
53-
impl #name for #impl_name {}
54-
});
55-
}
56-
5743
let impls = self.attrs.iter().map(|ident| {
58-
let d = if self.is_element {
59-
quote! { #name::#ident }
60-
} else {
61-
quote! { <#impl_name as #name>::#ident }
62-
};
44+
let d = quote! { #name::#ident };
6345
quote! {
6446
fn #ident(self, value: impl IntoAttributeValue) -> Self {
6547
let d = #d;

packages/html/src/global_attributes.rs renamed to packages/html/src/attribute_groups.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use dioxus_html_internal_macro::impl_extension_attributes;
77
use crate::AttributeDiscription;
88

99
#[cfg(feature = "hot-reload-context")]
10-
macro_rules! trait_method_mapping {
10+
macro_rules! mod_method_mapping {
1111
(
1212
$matching:ident;
1313
$(#[$attr:meta])*
@@ -68,30 +68,31 @@ macro_rules! html_to_rsx_attribute_mapping {
6868
};
6969
}
7070

71-
macro_rules! trait_methods {
71+
macro_rules! mod_methods {
7272
(
7373
@base
74-
$(#[$trait_attr:meta])*
75-
$trait:ident;
74+
$(#[$mod_attr:meta])*
75+
$mod:ident;
7676
$fn:ident;
7777
$fn_html_to_rsx:ident;
7878
$(
7979
$(#[$attr:meta])*
8080
$name:ident $(: $($arg:literal),*)*;
8181
)+
8282
) => {
83-
$(#[$trait_attr])*
84-
pub trait $trait {
83+
$(#[$mod_attr])*
84+
pub mod $mod {
85+
use super::*;
8586
$(
8687
$(#[$attr])*
87-
const $name: AttributeDiscription = trait_methods! { $name $(: $($arg),*)*; };
88+
pub const $name: AttributeDiscription = mod_methods! { $name $(: $($arg),*)*; };
8889
)*
8990
}
9091

9192
#[cfg(feature = "hot-reload-context")]
9293
pub(crate) fn $fn(attr: &str) -> Option<(&'static str, Option<&'static str>)> {
9394
$(
94-
trait_method_mapping! {
95+
mod_method_mapping! {
9596
attr;
9697
$name$(: $($arg),*)*;
9798
}
@@ -111,7 +112,7 @@ macro_rules! trait_methods {
111112
None
112113
}
113114

114-
impl_extension_attributes![GLOBAL $trait { $($name,)* }];
115+
impl_extension_attributes![$mod { $($name,)* }];
115116
};
116117

117118
// Rename the incoming ident and apply a custom namespace
@@ -124,10 +125,10 @@ macro_rules! trait_methods {
124125
( $name:ident; ) => { (stringify!($name), None, false) };
125126
}
126127

127-
trait_methods! {
128+
mod_methods! {
128129
@base
129130

130-
GlobalAttributes;
131+
global_attributes;
131132
map_global_attributes;
132133
map_html_global_attributes_to_rsx;
133134

@@ -1640,9 +1641,9 @@ trait_methods! {
16401641
aria_setsize: "aria-setsize";
16411642
}
16421643

1643-
trait_methods! {
1644+
mod_methods! {
16441645
@base
1645-
SvgAttributes;
1646+
svg_attributes;
16461647
map_svg_attributes;
16471648
map_html_svg_attributes_to_rsx;
16481649

packages/html/src/elements.rs

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use dioxus_rsx::HotReloadingContext;
88

99
#[cfg(feature = "hot-reload-context")]
1010
use crate::{map_global_attributes, map_svg_attributes};
11-
use crate::{GlobalAttributes, SvgAttributes};
1211

1312
pub type AttributeDiscription = (&'static str, Option<&'static str>, bool);
1413

@@ -115,9 +114,11 @@ macro_rules! impl_element {
115114
) => {
116115
#[allow(non_camel_case_types)]
117116
$(#[$attr])*
118-
pub struct $name;
117+
pub mod $name {
118+
#[allow(unused)]
119+
use super::*;
120+
pub use crate::attribute_groups::global_attributes::*;
119121

120-
impl $name {
121122
pub const TAG_NAME: &'static str = stringify!($name);
122123
pub const NAME_SPACE: Option<&'static str> = None;
123124

@@ -128,8 +129,6 @@ macro_rules! impl_element {
128129
);
129130
)*
130131
}
131-
132-
impl GlobalAttributes for $name {}
133132
};
134133

135134
(
@@ -141,13 +140,12 @@ macro_rules! impl_element {
141140
)*
142141
}
143142
) => {
144-
#[allow(non_camel_case_types)]
145143
$(#[$attr])*
146-
pub struct $name;
147-
148-
impl SvgAttributes for $name {}
144+
pub mod $name {
145+
#[allow(unused)]
146+
use super::*;
147+
pub use crate::attribute_groups::svg_attributes::*;
149148

150-
impl $name {
151149
pub const TAG_NAME: &'static str = stringify!($name);
152150
pub const NAME_SPACE: Option<&'static str> = Some($namespace);
153151

@@ -171,11 +169,11 @@ macro_rules! impl_element {
171169
) => {
172170
#[allow(non_camel_case_types)]
173171
$(#[$attr])*
174-
pub struct $element;
175-
176-
impl SvgAttributes for $element {}
172+
pub mod $element {
173+
#[allow(unused)]
174+
use super::*;
175+
pub use crate::attribute_groups::svg_attributes::*;
177176

178-
impl $element {
179177
pub const TAG_NAME: &'static str = $name;
180178
pub const NAME_SPACE: Option<&'static str> = Some($namespace);
181179

@@ -384,10 +382,23 @@ macro_rules! builder_constructors {
384382
);
385383
)*
386384

385+
/// This module contains helpers for rust analyzer autocompletion
386+
#[doc(hidden)]
387+
pub mod completions {
388+
/// This helper tells rust analyzer that it should autocomplete the element name with braces.
389+
#[allow(non_camel_case_types)]
390+
pub enum CompleteWithBraces {
391+
$(
392+
$(#[$attr])*
393+
$name {}
394+
),*
395+
}
396+
}
397+
387398
pub(crate) mod extensions {
388399
use super::*;
389400
$(
390-
impl_extension_attributes![ELEMENT $name { $($fil,)* }];
401+
impl_extension_attributes![$name { $($fil,)* }];
391402
)*
392403
}
393404
};

packages/html/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@
1616
//!
1717
//! Currently, we don't validate for structures, but do validate attributes.
1818
19-
mod elements;
19+
pub mod elements;
2020
#[cfg(feature = "hot-reload-context")]
2121
pub use elements::HtmlCtx;
2222
#[cfg(feature = "html-to-rsx")]
2323
pub use elements::{map_html_attribute_to_rsx, map_html_element_to_rsx};
2424
pub mod events;
2525
pub(crate) mod file_data;
2626
pub use file_data::*;
27+
mod attribute_groups;
2728
pub mod geometry;
28-
mod global_attributes;
2929
pub mod input_data;
3030
#[cfg(feature = "native-bind")]
3131
pub mod native_bind;
@@ -40,25 +40,25 @@ mod transit;
4040
#[cfg(feature = "serialize")]
4141
pub use transit::*;
4242

43+
pub use attribute_groups::*;
4344
pub use elements::*;
4445
pub use events::*;
45-
pub use global_attributes::*;
4646
pub use render_template::*;
4747

4848
#[cfg(feature = "eval")]
4949
pub mod eval;
5050

5151
pub mod extensions {
52+
pub use crate::attribute_groups::{GlobalAttributesExtension, SvgAttributesExtension};
5253
pub use crate::elements::extensions::*;
53-
pub use crate::global_attributes::{GlobalAttributesExtension, SvgAttributesExtension};
5454
}
5555

5656
pub mod prelude {
57+
pub use crate::attribute_groups::{GlobalAttributesExtension, SvgAttributesExtension};
5758
pub use crate::elements::extensions::*;
5859
#[cfg(feature = "eval")]
5960
pub use crate::eval::*;
6061
pub use crate::events::*;
61-
pub use crate::global_attributes::{GlobalAttributesExtension, SvgAttributesExtension};
6262
pub use crate::point_interaction::*;
6363
pub use keyboard_types::{self, Code, Key, Location, Modifiers};
6464
}

0 commit comments

Comments
 (0)