Improve the slint! macro with rust-analyzer with -

We currently use the debug representation of Span to know if they are
next touching eachother as there are no stable way currently.
But that doesn't work with rust analyzer as it doesn't have a
representation we can test.
Also Span::source_text is not implemented with rust analyzer.

So just default to identifier with `-` touching instead of not touching
as this happens more often.

One can still use `(foo)-(bar)` when one really need minus

CC #685
This commit is contained in:
Olivier Goffart 2023-10-26 09:15:10 +02:00 committed by Olivier Goffart
parent bdd275811e
commit c51fb14a0e
2 changed files with 37 additions and 23 deletions

View file

@ -26,8 +26,9 @@ All notable changes to this project are documented in this file.
- `SpinBox` value can now be incremented and decremented by scroll event
- Added `focus-changed-event` callback to `FocusScope`
### Rust API
### Rust
- Improved support of the `slint!` macro for rust-analyzer.
- Added `source_model()` to `MapModel`, `FilterModel`, `SortModel`, `ReverseModel` to access inner model.
### C++

View file

@ -18,13 +18,15 @@ use quote::quote;
/// Returns true if the two token are touching. For example the two token `foo`and `-` are touching if
/// it was written like so in the source code: `foo-` but not when written like so `foo -`
fn are_token_touching(token1: proc_macro::Span, token2: proc_macro::Span) -> bool {
///
/// Returns None if we couldn't detect whether they are touching (eg, our heuristics don't work with rust-analyzer)
fn are_token_touching(token1: proc_macro::Span, token2: proc_macro::Span) -> Option<bool> {
// There is no way with stable API to find out if the token are touching, so do it by
// extracting the range from the debug representation of the span
are_token_touching_impl(&format!("{:?}", token1), &format!("{:?}", token2))
are_token_touching_impl(&format!("{token1:?}"), &format!("{token2:?}"))
}
fn are_token_touching_impl(token1_debug: &str, token2_debug: &str) -> bool {
fn are_token_touching_impl(token1_debug: &str, token2_debug: &str) -> Option<bool> {
// The debug representation of a span look like this: "#0 bytes(6662789..6662794)"
// we just have to find out if the first number of the range of second span
// is the same as the second number of the first span
@ -33,35 +35,44 @@ fn are_token_touching_impl(token1_debug: &str, token2_debug: &str) -> bool {
let end_of_token1 = token1_debug
.trim_end_matches(not_is_byte_char)
.rsplit(not_is_byte_char)
.next()
.map(|x| x.trim_matches(':'));
.next()?
.trim_matches(':');
let begin_of_token2 = token2_debug
.trim_end_matches(not_is_byte_char)
.strip_suffix(is_byte_char)?
.trim_end_matches(is_byte_char)
.trim_end_matches(not_is_byte_char)
.rsplit(not_is_byte_char)
.next()
.map(|x| x.trim_matches(':'));
end_of_token1.zip(begin_of_token2).map(|(a, b)| !a.is_empty() && a == b).unwrap_or(false)
.next()?
.trim_matches(':');
(!begin_of_token2.is_empty()).then_some(end_of_token1 == begin_of_token2)
}
#[test]
fn are_token_touching_impl_test() {
assert!(are_token_touching_impl("#0 bytes(6662788..6662789)", "#0 bytes(6662789..6662794)"));
assert!(!are_token_touching_impl("#0 bytes(6662788..6662789)", "#0 bytes(6662790..6662794)"));
assert!(!are_token_touching_impl("#0 bytes(6662789..6662794)", "#0 bytes(6662788..6662789)"));
assert!(!are_token_touching_impl("#0 bytes(6662788..6662789)", "#0 bytes(662789..662794)"));
assert!(are_token_touching_impl("#0 bytes(123..456)", "#0 bytes(456..789)"));
assert!(are_token_touching_impl("#0 bytes(6662788..6662789)", "#0 bytes(6662789..6662794)")
.unwrap());
assert!(!are_token_touching_impl("#0 bytes(6662788..6662789)", "#0 bytes(6662790..6662794)")
.unwrap());
assert!(!are_token_touching_impl("#0 bytes(6662789..6662794)", "#0 bytes(6662788..6662789)")
.unwrap());
assert!(
!are_token_touching_impl("#0 bytes(6662788..6662789)", "#0 bytes(662789..662794)").unwrap()
);
assert!(are_token_touching_impl("#0 bytes(123..456)", "#0 bytes(456..789)").unwrap());
// Alternative representation on nightly with a special flag
assert!(are_token_touching_impl("/foo/bar.rs:12:7: 12:18", "/foo/bar.rs:12:18: 12:19"));
assert!(are_token_touching_impl("/foo/bar.rs:2:7: 13:18", "/foo/bar.rs:13:18: 14:29"));
assert!(!are_token_touching_impl("/foo/bar.rs:2:7: 13:18", "/foo/bar.rs:14:18: 14:29"));
assert!(!are_token_touching_impl("/foo/bar.rs:2:7: 2:8", "/foo/bar.rs:2:18: 2:29"));
assert!(are_token_touching_impl("/foo/bar.rs:12:7: 12:18", "/foo/bar.rs:12:18: 12:19").unwrap());
assert!(are_token_touching_impl("/foo/bar.rs:2:7: 13:18", "/foo/bar.rs:13:18: 14:29").unwrap());
assert!(!are_token_touching_impl("/foo/bar.rs:2:7: 13:18", "/foo/bar.rs:14:18: 14:29").unwrap());
assert!(!are_token_touching_impl("/foo/bar.rs:2:7: 2:8", "/foo/bar.rs:2:18: 2:29").unwrap());
// What happens if the representation change
assert!(!are_token_touching_impl("hello", "hello"));
assert!(!are_token_touching_impl("hello42", "hello42"));
assert!(are_token_touching_impl("hello", "hello").is_none());
assert!(are_token_touching_impl("hello42", "hello42").is_none());
// rust-analyzer just has indices that means nothing
assert!(are_token_touching_impl("55", "56").is_none());
}
fn fill_token_vec(stream: impl Iterator<Item = TokenTree>, vec: &mut Vec<parser::Token>) {
@ -74,7 +85,8 @@ fn fill_token_vec(stream: impl Iterator<Item = TokenTree>, vec: &mut Vec<parser:
if let Some(last) = vec.last_mut() {
if (last.kind == SyntaxKind::ColorLiteral && last.text.len() == 1)
|| (last.kind == SyntaxKind::Identifier
&& are_token_touching(prev_span, span))
&& are_token_touching(prev_span, span)
.unwrap_or_else(|| last.text.ends_with("-")))
{
last.text = format!("{}{}", last.text, i).into();
prev_span = span;
@ -122,7 +134,7 @@ fn fill_token_vec(stream: impl Iterator<Item = TokenTree>, vec: &mut Vec<parser:
'-' => {
if let Some(last) = vec.last_mut() {
if last.kind == SyntaxKind::Identifier
&& are_token_touching(prev_span, p.span())
&& are_token_touching(prev_span, p.span()).unwrap_or(true)
{
last.text = format!("{}-", last.text).into();
prev_span = span;
@ -213,7 +225,8 @@ fn fill_token_vec(stream: impl Iterator<Item = TokenTree>, vec: &mut Vec<parser:
if let Some(last) = vec.last_mut() {
if (last.kind == SyntaxKind::ColorLiteral && last.text.len() == 1)
|| (last.kind == SyntaxKind::Identifier
&& are_token_touching(prev_span, span))
&& are_token_touching(prev_span, span)
.unwrap_or_else(|| last.text.ends_with("-")))
{
last.text = format!("{}{}", last.text, s).into();
prev_span = span;