Skip to content

Syntax Highlighting Improvements #284

Open
@ehuss

Description

@ehuss

I've done a survey of syntax issues of some things I think can be highlighted better. Syntax highlighting can be subjective so it's not always clear how things should work. I'm thinking it would be preferred to try to address issues with individual PRs rather than trying to do massive changes, however, that might cause a lot of merge conflicts and may be a pain for @jasonwilliams to review (thoughts?). @dten would you be willing to help, or at least review changes or make suggestions?

  • 1. type-any-identifiers not referenced.

  • 2. Global const and static values don't show up in goto symbol.

    const VERSION: u32 = 1;
    static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

    Const identifier should include entity.name.constant. (and possibly variable.other.constant.?) and add entity.name.constant to RustSymbols.

    I'm not sure what scope static identifiers should have. Most other syntaxes don't seem to have special support.

  • 3. Turbofish calls don't get colored the same as regular calls.
    They get assigned meta.path.rust instead of support.function.rust.

    foo::<Vec<_>>();
    // vs
    foo();
  • 4. mut highlights weird when part of the type of a trait impl.

    impl<A> Thing for &'a mut A {}

    I think it should be storage.modifier, not part of the name.

  • 5. Function and closure parameters don't highlight irrefutable patterns as regular parameters. I think it looks weird.

    let c = |(foo, bar)| {};
    fn f((a, b): (i32, i32)) {}
  • 6. Newlines in closure arguments breaks highlighting.

    let c = |foo,
             bar| {};
  • 7. Comments in strange places doesn't always work.

    let c = |foo,  // weird, but should work
             bar| {};
  • 8. Macro calls should not break highlighting on unusual tokens. It would be nice to retain some Rust-like expression handling within macros since that is the common case, however, it shouldn't break down when given invalid syntax since macros can contain almost anything. I hit this most frequently with serde's macro where the struct keyword breaks highlighting until the next block closes.

    forward_to_deserialize_any! {
        f32 f64 char str bytes
        byte_buf unit unit_struct
        struct enum identifier ignored_any
    }
  • 9. Add support for dyn trait object type keyword. See stabilize dyn Trait in Rust 2015 rust#49218 for some valid/invalid examples.

  • 10. Hex codes above 0x7f are invalid in string escapes.

    let s = "\xff"; // should be invalid
  • 11. Unicode escape sequences can include underscores.

    let s = '\u{10_FFFF}';;
  • 12. Tuple indexes show up with float highlighting. I don't think the dot should be highlighted (like a field access expression), but I'm uncertain if the number should be highlighted (probably not?).

    t.0;
  • 13. super and self when used as a path highlight differently, although they are generally the same thing. I think they should be the same (although self should probably stay as variable.language.rust when used as a method parameter/variable).

    pub(super)
    pub(self)
    super::foo
    self::foo
    use std::collections::hash_map::{self, HashMap};
    use super::*;
  • 14. Support attributes for type or lifetime parameters. (48848)

    unsafe impl<#[may_dangle] T: ?Sized> Drop for Box<T> { }
  • 15. where clauses tend to avoid highlighting much, leaving large blocks of unhighlighted text. Here are some examples, but there are probably many more.

    fn f<F>(func: F) -> usize
        where F: Fn(usize) -> usize {}
    fn f<L, R>(lhs: L, rhs: R)
        where L: IntoIterator<Item=(&'a i32, &'a i32)>,
              R: IntoIterator<Item=(&'a i32, &'a i32)>, {}
    // Bounds in generic parameters seem better.
    fn f<F: Fn(usize) -> usize>(func: f) {}
    fn f<L: IntoIterator<Item=(&'a i32, &'a i32)>>(lhs: L) {}
  • 16. for as a trait bound does not highlight as a keyword in a few situations.

    fn f<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {}
    // `unsafe` doesn't correctly highlight here, either.
    fn f(a: for<'a, 'b> unsafe fn() -> String) {}
  • 17. Visibility modifiers on struct/union fields doesn't seem to support anything besides plain pub.

    struct S {
        // `crate` should highlight here.
        pub(crate) f1: i32,
    }
  • 18. enums don't highlight any generics.

    enum E<'asdf> {}
    enum C<T> where T: Copy {}
    // many other examples
  • 19. Trait definitions don't highlight bounds or type parameters.

    trait Foo<'a>: Sized {}
    trait IntoCow<'a, B: ?Sized> where B: ToOwned {}
  • 20. Opt-out trait impls highlight weird.

    impl !Send for MyStruct {}
  • 21. Type qualified paths highlight as less-than/greater-than operators when they shouldn't.

    let some_constructor = Some::<i32>;
    let push_integer = Vec::<i32>::push;
    let slice_reverse = <[i32]>::reverse;
  • 22. break/continue labels are highlighted as lifetimes, but probably should be entity.name.label.

    'outer: loop {
        break 'outer;
    }
  • 23. (2018) Anonymous lifetimes

    Foo<'_>
  • 24. match-beginning-vert (RFC #1925)

    match foo {
        | A | B | C | D => (),
    }
  • 25. Macro blocks need to support semicolons between matches.

    macro_rules! c {
        ($a:ident) => (
        );
        // Everything after the previous semicolon is broken.
        ($a:ident = $e:expr) => (
        )
    }
  • 26. Lifetime bounds on a trait do not highlight as a lifetime.

     trait Foo: 'static {}
  • 27. Lifetime parameter in enum does not highlight as a lifetime.

    enum Foo<'a> {}
  • 28. Support unreserved keywords in 1.28. pure, sizeof, alignof, offsetof. And proc from 1.27.

  • 29. Add lifetime specifier to macro_rules! (1.28)

    macro_rules! m { ($lt:lifetime) => {} }
  • 30. Raw const pointer in function parameter is not highlighted correctly.

     fn f(a: *const u8) {}
  • 31. Raw pointer types still aren't quite right. *const and *mut should be the same. I think mut should be storage.type in this case. Also, it looks like *const is getting confused with const FOO, so the type immediately after *const is wrong.

     let p: *const T;
     let p: *mut u8;
  • 32. Closures fail to highlight in some positions. In this example the second closure fails.

    foo_or_else(|x,y| x+y, |a,b| a*b);
  • 33. type aliases do not properly handle generic arguments.

    type Foo<i32> = Bar<i32>;

Grammar references:

Currently tested on Rust Enhanced 2.11.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-syntaxArea: Syntax highlighting

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions