W30: Closing bracket pair highlight (also check before cursor)
The existing bracket_flash only triggered when the cursor was ON a bracket character. This meant that after typing a closing bracket (the most common trigger scenario), the cursor sits AFTER the bracket and the flash doesn't fire. Update update_bracket_flash to also check the character BEFORE the cursor (pos - 1) and use it as a fallback. The pair position is adjusted accordingly (the match is at pos - 1 for the before- cursor case). Tests: 1393 pass, zero warnings.
This commit is contained in:
@@ -824,24 +824,47 @@ impl Editor {
|
||||
fn update_bracket_flash(&mut self) {
|
||||
let pos = self.cursor.position();
|
||||
let text = self.buffer.as_string();
|
||||
if pos >= text.len() || !text.is_char_boundary(pos) {
|
||||
if pos > text.len() || !text.is_char_boundary(pos) {
|
||||
self.bracket_flash = None;
|
||||
return;
|
||||
}
|
||||
let ch = text[pos..].chars().next().unwrap();
|
||||
let open = "([{<";
|
||||
let close = ")]}>";
|
||||
let result = if let Some(idx) = open.find(ch) {
|
||||
let target = close.as_bytes()[idx] as char;
|
||||
Self::find_matching_forward(&text, pos, ch, target)
|
||||
.map(|end| (pos, end))
|
||||
} else if let Some(idx) = close.find(ch) {
|
||||
let target = open.as_bytes()[idx] as char;
|
||||
Self::find_matching_backward(&text, pos, ch, target)
|
||||
.map(|start| (start, pos))
|
||||
// Check the character UNDER the cursor first. If the cursor
|
||||
// sits on an opening bracket, the match is forward. If it
|
||||
// sits on a closing bracket, the match is backward.
|
||||
let ch_at = text[pos..].chars().next();
|
||||
// Also check the character BEFORE the cursor (pos - 1).
|
||||
// When the user types a closing bracket, the cursor sits
|
||||
// *after* the bracket; we still want to flash the pair.
|
||||
let ch_before = if pos > 0 && text.is_char_boundary(pos - 1) {
|
||||
text[..pos].chars().next_back()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let open = "([{<";
|
||||
let close = ")]}>";
|
||||
let resolve = |c: char| -> Option<(usize, usize)> {
|
||||
if let Some(idx) = open.find(c) {
|
||||
let target = close.as_bytes()[idx] as char;
|
||||
Self::find_matching_forward(&text, pos, c, target)
|
||||
.map(|end| (pos, end))
|
||||
} else if let Some(idx) = close.find(c) {
|
||||
let target = open.as_bytes()[idx] as char;
|
||||
Self::find_matching_backward(&text, pos, c, target)
|
||||
.map(|start| (start, pos))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
// Prefer the char under the cursor. Fall back to the char
|
||||
// before (for the typed-closing-bracket case).
|
||||
let result = ch_at.and_then(&resolve).or_else(|| {
|
||||
ch_before.and_then(&resolve).map(|(s, _)| {
|
||||
// For backward lookup the match is at (pos - 1) and
|
||||
// the opening bracket is before it.
|
||||
let _ = pos;
|
||||
(s, pos.saturating_sub(1))
|
||||
})
|
||||
});
|
||||
self.bracket_flash = result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user