Thertzlor / semantic-rainbow

A maximalist VSCode color theme for semantic highlighting featuring bold colors and subtle distinctions.
https://thertzlor.github.io/semantic-rainbow/
GNU General Public License v3.0
15 stars 4 forks source link

Rust Support #5

Open BenjaminBrienen opened 11 months ago

BenjaminBrienen commented 11 months ago

Couldn't find a better place to add a feature request or gauge interest...

I know the readme suggests adding support for more language-specific features. I'm simply here to ask whether rust is of particular interest to this project, be it implemented by the current maintainer or a new maintainer such as myself. If supporting Rust is something that you are particularly interested in, then I'm interested in having a discussion about which language features should be considered for semantic coloring, the feasibility of each, and related topics.

Thertzlor commented 11 months ago

Hello,

I haven't personally used Rust but it would be a neat language to fully support given its popularity. The highlighting depends on what VSCode offers for any given language so when adding support for a language I generally start with checking out the most popular or advanced LSP extension that developers would have installed for it.

For rust that seems to be the semantic highlighting of Rust Analyzer. This is in fact one of the more comprehensive semantic highlighters I've come across, and I'm already seeing both new tokens (such as struct, trait, lifetime) and modifiers (such as consuming, callable, reference) that are not yet part of the Semantic Rainbow Specification.

The main part is just figuring out how to situate those tokens within the theme's design philosophy and that's where, having no rust experience, I'd be grateful for help.

Helpful things to know would be:

...And so on.

circuitfox commented 4 months ago

Hi.

I recently started using your theme and I like its approach of maximal use of semantic information. Here are some specific observations about Rust and how some of its concepts can fit into this theme's design philosophy. This is probably not a complete list and I could be missing things.

  1. structs are Rust's way of storing state. There are no classes in Rust, so a simple alias would suffice.
  2. traits are essentially interfaces. They are a group of functions and methods that can be implemented by another type and then the trait can be used generically.
  3. Variables (let bindings, function parameters, etc.) are immutable by default and must be declared as mut to be mutated. Mutable items get a mutable modifier. This inverts the readonly distinction that the theme uses.
  4. Top-level items (functions, structs, traits, etc.) are private by default, and can be declared either pub(crate) (usable only in the current crate, Rust's version of a package, basically) or pub. This inverts the theme's privacy distinction, as well as adding a second level.
  5. const variables are read-only and calculated at compile-time. There are also const functions and methods, which can be used to initialize const variables and have restrictions on what they can do so they can be run at compile-time. It would be nice to highlight these differently from other functions and methods.
  6. static variables are non-constant variables with specifically 'static lifetime. They are valid for the entire lifetime of the running program. They can technically be modified (you can have mut static) but this requires the use of unsafe and is also not thread-safe and is practically never done. So static variables are almost always read-only.
  7. There is a derive token that is used for the derive attribute, which allows automatic implementation of some traits. Maybe these should be highlighted like traits?
  8. The self keyword has selfKeyword token that should get the "self parameter" highlighting.

Methods have a three-way (technically four-way) distinction in how they access self that should be highlighted.

  1. consuming: Method takes self by value and moves it out of the calling function. The value cannot be used after that point. This also includes methods which take mut self.
  2. reference: Method takes self by reference &self. Self cannot be mutated and is not consumed.
  3. mutable.reference: Method takes self by mutable reference &mut self. The value that this method is called with must be mutable with let mut or another form of mutable binding.

The value - reference - mutable reference distinction also applies to parameters.

Lifetime parameters should be highlighted differently from type parameters. To give a quick explanation, if you want to store a reference to borrowed data, that reference must be marked with a lifetime.

struct Example<'a> {
    p: &'a i32
}

struct Example holds a reference to an i32. The lifetime 'a means that an instance of Example can not live longer than the lifetime 'a of the owner of the i32, otherwise the reference would become invalid. So something like this is illegal:

fn bad() -> &i32 {
    let x = 0;
    &x // x is dropped at the end of the function; this reference is invalid
}

They are essentially a generic type parameter that controls where and how object may be used in the flow of the program. A borrower can never outlive the owner of its data and lifetimes are what enforces this.

One final thing that I'm not sure about is how the theme can highlight scopes. Rust has an unsafe feature that enables you to do things like access raw pointers or do FFI with C which could potentially cause memory errors that the compiler cannot prevent. Use of unsafe can be a bit of a contentious issue and lots of crates advertise their performance with no use of unsafe. I think it would be a good idea and in the spirit of the theme to highlight these blocks somehow, even if it's just the unsafe keyword. Highlighting the entire block with a separate background may not be possible.

Thertzlor commented 4 months ago

Thanks for the input, I can definitely work with that, although some of the stuff sure seems challenging. Scope highlighting is not something that semantic tokens are good at because well, it's really about individual tokens. But perhaps the Textmate grammar recognizes unsafe scopes that would also make them styleable.

I guess I'll see when I check out some more Rust code.