Extending rust syntax and have IDE formatters work

I want to extend rust syntax with 'rust xml' which is a declarative way of writing UIs. You would have a .rx file similar to a .jsx file where functions may be parsed as functional components and all usages of rust xml gets parsed into something like create_element('div', attributes). The existing frameworks like yew, dioxus, etc. are nice but they rely heavily on macros, which doesnt seem to work too well with the IDE tools to parse and prettify the UI declaration code.

So I was thinking of having a separate system for build.rs to hook onto and pre-process the .rx into actual rust structs + impls. Do you think theres a nicer way to do this? And maybe extend rustfmt to work with it?

I don't think rustfmt will give you any way to extend its supported syntax or modify the formatting code[1], so you might be on your own there.

That said, I've been doing a deep dive into rust-analyzer's architecture over the last couple weeks as part of a project I'm working on and if you can trick it into parsing your *.rx files, you should still get nice things like auto-complete. That thing is crazy - you can give it hideously broken code and it'll somehow limp on and try to give you useful suggestions.


  1. Not short of forking the repo and changing things yourself, anyway. ↩ī¸Ž

1 Like

What if you wrapped rustfmt in something like rxfmt which detects .rx files. And rxfmt prioritises tokens of rust xml first. So you lex the file into an tokens, and pass that to rxfmt. If it detects a token it wants to deal with, it will keep going and see if it finds an appropriate rust xml scheme. Maybe <>...</>. If it does, it formats that. And for normal rust tokens like fn, struct, etc, it passes the tokens to rustfmt.

Then somehow modify rust-analyzer to expand those rust xml blocks into Component::new() blocks. Maybe modify rust-analyzer's parser to also include a rust_xml() expression?

Finally, to compile, have build.rs manually expand those blocks by searching for .rx files

If you're okay with putting in the time and effort, then the sky's your limit.

I'm just saying that there probably aren't any of the convenient extension points you're looking for, so you'll most likely need to hack things in.

It might be easier to use some sort of declarative rsx!() macro like yew and friends. For the formatting part you can make some sort of tool that will look for the start/end of an rsx!() invocation and do a string.split() to extract the xml code and splice in a formatted copy (see Self Modifying Code for prior work).

I have something called rx which is something like jsx but for rust. And I want to make an rx-analyzer for it to work on IDEs. It would parse the rx file and expand it to rust, then pass that on to rust-analyzer to analyze the actual rust. Then I want to the get the output of rust-analyzer and pass it back to rx-analyzer to give us analytics of the rx code.

What do you guys think?

// index.rx
pub fn Index() -> Element {
    let animate = Animate {duration: 10};

    @{
        Heading {}
        Box {
            Quote {}
            Flex {}
            Link(to="component") {
                Text {"CLICK ME"}
            }
            Flex(animate={animate}) {}
            // custom component
            Component {}
        }
    }
}

// component.rx
pub fn Component() -> Element {
    return @{
        Box {}
    }
}

Sounds like a good idea. You should start building it and let us know how it goes :+1:

1 Like