-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flatten nested highlight ranges during DFS traversal #3826
Conversation
|
||
let mut current_macro_call: Option<ast::MacroCall> = None; | ||
|
||
// Walk all nodes, keeping track of whether we are inside a macro or not. | ||
// If in macro, expand it first and highlight the expanded code. | ||
for event in root.preorder_with_tokens() { | ||
assert!(!res.is_empty()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have this assert!
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The invariant is that the stack never becomes empty. This is asserted before and after the modification. I am fine with removing this assertion, I just usually err on the side of too many assertions 😉
Makes sense to me. I question the usefulness of One thing... how will this interact with the range LSP request? In theory I could see that splicing nested tokens. |
This PR changes only the representation of the nesting and keeps the original logic untouched. Thus, the handling of range requests should be the same as before. |
assert!(!res.is_empty()); | ||
let current = res.last_mut().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The server will panic on either line of code, I'd propose to replace assert!()
with res.last_mut().expect("reason of the assert");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I'll update the PR with this change
1d666b2
to
bb45aca
Compare
I have updated the PR with the suggested changes and a new test case |
@@ -119,19 +161,20 @@ pub(crate) fn highlight( | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we add highlights below this line, I think we have an invariant that the highlight must not extend beyond the current node (otherwise, flattening might be broken). Let's add an assert for this.
} | ||
} | ||
|
||
res | ||
assert_eq!(res.len(), 1, "after DFS traversal, the stack should only contain a single element"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also assert that ranges are sorted and disjoint
* | ||
* The following code implements the flattening, for our example this results to: | ||
* `[Attribute [0, 16), String [16, 21), Attribute [21, 23)]` | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After this, we should be able to remove the relevant logic from highlight_as_html
function.
@@ -131,3 +131,19 @@ fn test_ranges() { | |||
|
|||
assert_eq!(&highlights[0].highlight.to_string(), "field.declaration"); | |||
} | |||
|
|||
#[test] | |||
fn test_flattening() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A good test here would be something that touches highlight_injection
logic:
fn fixture(ra_fixture: &str) {}
fn main() {
fixture(r#"
trait Foo {
fn foo() {
println!("2 + 2 = {}", 4);
}
}
"#)
}
This functionality is currently untested simply because naive flattening in highlight_as_html can't deal with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't aware of the highlight_injection
logic, this is only a special case for rust-analyzer development, right? However, this is a great test for the flattening logic, otherwise, Rust does not seem to contain many nestings other than the attributes from the issue.
The current highlight_as_html
logic iterates over both, the parsed tokens and the highlight ranges. With the change of the function type to be natively flat, it would be better to only iterate over the highlight ranges and consume the text file range by range. Is there an easy way to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, this is only for rust-anayzer. And yes, you'd need to iteratete the text:
let text = parse.tree().syntax().to_string();
let mut curr = &text[..];
for range in ranges {
curr = &curr[range.len..]
}
I wonder if it makes sense to change the return type of the function to be natively flat. Like this: #[derive(Debug)]
pub struct HighlightedRange {
pub len: TextUnit,
pub highlight: Option<Highlight>,
pub binding_hash: Option<u64>,
} I would probably go for it |
bors r+ Thanks! |
Build succeeded |
3998: Make add_function generate functions in other modules via qualified path r=matklad a=TimoFreiberg Additional feature for #3639 - [x] Add tests for paths with more segments - [x] Make generating the function in another file work - [x] Add `pub` or `pub(crate)` to the generated function if it's generated in a different module - [x] Make the assist jump to the edited file - [x] Enable file support in the `check_assist` helper 4006: Syntax highlighting for format strings r=matklad a=ltentrup I have an implementation for syntax highlighting for format string modifiers `{}`. The first commit refactors the changes in #3826 into a separate struct. The second commit implements the highlighting: first we check in a macro call whether the macro is a format macro from `std`. In this case, we remember the format string node. If we encounter this node during syntax highlighting, we check for the format modifiers `{}` using regular expressions. There are a few places which I am not quite sure: - Is the way I extract the macro names correct? - Is the `HighlightTag::Attribute` suitable for highlighting the `{}`? Let me know what you think, any feedback is welcome! Co-authored-by: Timo Freiberg <[email protected]> Co-authored-by: Leander Tentrup <[email protected]> Co-authored-by: Leander Tentrup <[email protected]>
Implements the flattening of nested highlights from #3447.
There is a caveat: I needed to add
Clone
toHighlightedRange
to split highlight rangesand the nesting does not appear in the syntax highlighting test (it does appear in the accidental-quadratic test but there it is not checked against a ground-truth).I have added a test case for the example mentioned in #3447.