Add support for auto-closing of JSX tags (#25681)
Closes #4271 Implemented by kicking of a task on the main thread at the end of `Editor::handle_input` which waits for the buffer to be re-parsed before checking if JSX tag completion possible based on the recent edits, and if it is then it spawns a task on the background thread to generate the edits to be auto-applied to the buffer Release Notes: - Added support for auto-closing of JSX tags --------- Co-authored-by: Cole Miller <cole@zed.dev> Co-authored-by: Max Brunsfeld <max@zed.dev> Co-authored-by: Marshall Bowers <git@maxdeviant.com> Co-authored-by: Mikayla <mikayla@zed.dev> Co-authored-by: Peter Tripp <peter@zed.dev>
This commit is contained in:
parent
05df3d1bd6
commit
ff25fa24e7
15 changed files with 1207 additions and 149 deletions
|
@ -591,6 +591,7 @@ impl<'a> Cursor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Chunks<'a> {
|
||||
chunks: sum_tree::Cursor<'a, Chunk, usize>,
|
||||
range: Range<usize>,
|
||||
|
@ -780,6 +781,40 @@ impl<'a> Chunks<'a> {
|
|||
reversed,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn equals_str(&self, other: &str) -> bool {
|
||||
let chunk = self.clone();
|
||||
if chunk.reversed {
|
||||
let mut offset = other.len();
|
||||
for chunk in chunk {
|
||||
if other[0..offset].ends_with(chunk) {
|
||||
offset -= chunk.len();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if offset != 0 {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
let mut offset = 0;
|
||||
for chunk in chunk {
|
||||
if offset >= other.len() {
|
||||
return false;
|
||||
}
|
||||
if other[offset..].starts_with(chunk) {
|
||||
offset += chunk.len();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if offset != other.len() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Chunks<'a> {
|
||||
|
@ -1855,6 +1890,53 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunks_equals_str() {
|
||||
let text = "This is a multi-chunk\n& multi-line test string!";
|
||||
let rope = Rope::from(text);
|
||||
for start in 0..text.len() {
|
||||
for end in start..text.len() {
|
||||
let range = start..end;
|
||||
let correct_substring = &text[start..end];
|
||||
|
||||
// Test that correct range returns true
|
||||
assert!(rope
|
||||
.chunks_in_range(range.clone())
|
||||
.equals_str(correct_substring));
|
||||
assert!(rope
|
||||
.reversed_chunks_in_range(range.clone())
|
||||
.equals_str(correct_substring));
|
||||
|
||||
// Test that all other ranges return false (unless they happen to match)
|
||||
for other_start in 0..text.len() {
|
||||
for other_end in other_start..text.len() {
|
||||
if other_start == start && other_end == end {
|
||||
continue;
|
||||
}
|
||||
let other_substring = &text[other_start..other_end];
|
||||
|
||||
// Only assert false if the substrings are actually different
|
||||
if other_substring == correct_substring {
|
||||
continue;
|
||||
}
|
||||
assert!(!rope
|
||||
.chunks_in_range(range.clone())
|
||||
.equals_str(other_substring));
|
||||
assert!(!rope
|
||||
.reversed_chunks_in_range(range.clone())
|
||||
.equals_str(other_substring));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let rope = Rope::from("");
|
||||
assert!(rope.chunks_in_range(0..0).equals_str(""));
|
||||
assert!(rope.reversed_chunks_in_range(0..0).equals_str(""));
|
||||
assert!(!rope.chunks_in_range(0..0).equals_str("foo"));
|
||||
assert!(!rope.reversed_chunks_in_range(0..0).equals_str("foo"));
|
||||
}
|
||||
|
||||
fn clip_offset(text: &str, mut offset: usize, bias: Bias) -> usize {
|
||||
while !text.is_char_boundary(offset) {
|
||||
match bias {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue