Fix issues:

- fix the operators' display in the status bar
- fill the subword object placeholder
- fix some spelling mistakes
- fix a bug where the first and last words in a buffer couldn't be selected
This commit is contained in:
fantacell 2025-07-21 21:57:19 +02:00
parent 9b44bb6706
commit bd3b5c6829
4 changed files with 50 additions and 27 deletions

View file

@ -4,7 +4,7 @@
use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
use crate::{DisplayRow, EditorStyle, ToOffset, ToPoint, scroll::ScrollAnchor};
use gpui::{Pixels, WindowTextSystem};
use language::Point;
use language::{CharClassifier, Point};
use multi_buffer::{MultiBufferRow, MultiBufferSnapshot};
use serde::Deserialize;
use workspace::searchable::Direction;
@ -303,13 +303,16 @@ pub fn previous_subword_start(map: &DisplaySnapshot, point: DisplayPoint) -> Dis
let classifier = map.buffer_snapshot.char_classifier_at(raw_point);
find_preceding_boundary_display_point(map, point, FindRange::MultiLine, |left, right| {
let is_word_start =
classifier.kind(left) != classifier.kind(right) && !right.is_whitespace();
is_subword_start(left, right, &classifier) || left == '\n'
})
}
pub fn is_subword_start(left: char, right: char, classifier: &CharClassifier) -> bool {
let is_word_start = classifier.kind(left) != classifier.kind(right) && !right.is_whitespace();
let is_subword_start = classifier.is_word('-') && left == '-' && right != '-'
|| left == '_' && right != '_'
|| left.is_lowercase() && right.is_uppercase();
is_word_start || is_subword_start || left == '\n'
})
is_word_start || is_subword_start
}
/// Returns a position of the next word boundary, where a word character is defined as either
@ -361,13 +364,17 @@ pub fn next_subword_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPo
let classifier = map.buffer_snapshot.char_classifier_at(raw_point);
find_boundary(map, point, FindRange::MultiLine, |left, right| {
is_subword_end(left, right, &classifier) || right == '\n'
})
}
pub fn is_subword_end(left: char, right: char, classifier: &CharClassifier) -> bool {
let is_word_end =
(classifier.kind(left) != classifier.kind(right)) && !classifier.is_whitespace(left);
let is_subword_end = classifier.is_word('-') && left != '-' && right == '-'
|| left != '_' && right == '_'
|| left.is_lowercase() && right.is_uppercase();
is_word_end || is_subword_end || right == '\n'
})
is_word_end || is_subword_end
}
/// Returns a position of the start of the current paragraph, where a paragraph

View file

@ -3,6 +3,7 @@ use std::{error::Error, fmt::Display};
use editor::{
DisplayPoint,
display_map::{DisplaySnapshot, ToDisplayPoint},
movement,
};
use language::{CharClassifier, CharKind};
use text::Bias;
@ -19,7 +20,8 @@ impl Display for UnboundedErr {
impl Error for UnboundedErr {}
impl Object {
/// Returns the beginning of the inside of the closest object after the cursor if it can easily be found. Follows helix convention;
/// Returns the beginning of the inside of the closest object after the cursor if it can easily be found.
/// Follows helix convention.
pub fn helix_next_start(
self,
map: &DisplaySnapshot,
@ -32,7 +34,8 @@ impl Object {
self.helix_is_start(right, left, classifier)
})
}
/// Returns the end of the inside of the closest object after the cursor if it can easily be found. Follows helix convention;
/// Returns the end of the inside of the closest object after the cursor if it can easily be found.
/// Follows helix convention.
pub fn helix_next_end(
self,
map: &DisplaySnapshot,
@ -45,7 +48,8 @@ impl Object {
self.helix_is_end(right, left, classifier)
})
}
/// Returns the beginning of the inside of the closest object before the cursor if it can easily be found. Follows helix convention;
/// Returns the beginning of the inside of the closest object before the cursor if it can easily be found.
/// Follows helix convention.
pub fn helix_previous_start(
self,
map: &DisplaySnapshot,
@ -58,7 +62,8 @@ impl Object {
self.helix_is_start(right, left, classifier)
})
}
/// Returns the end of the inside of the closest object before the cursor if it can easily be found. Follows helix convention;
/// Returns the end of the inside of the closest object before the cursor if it can easily be found.
/// Follows helix convention.
pub fn helix_previous_end(
self,
map: &DisplaySnapshot,
@ -81,10 +86,11 @@ impl Object {
match self {
Self::Word { ignore_punctuation } => {
let classifier = classifier.ignore_punctuation(ignore_punctuation);
Ok(is_word_start(left, right, classifier))
Ok(is_word_start(left, right, classifier) || is_buffer_start(left))
}
Self::Subword { ignore_punctuation } => {
todo!()
let classifier = classifier.ignore_punctuation(ignore_punctuation);
Ok(movement::is_subword_start(left, right, &classifier) || is_buffer_start(left))
}
Self::AngleBrackets => Ok(left == '<'),
Self::BackQuotes => Ok(left == '`'),
@ -106,10 +112,11 @@ impl Object {
match self {
Self::Word { ignore_punctuation } => {
let classifier = classifier.ignore_punctuation(ignore_punctuation);
Ok(is_word_end(left, right, classifier))
Ok(is_word_end(left, right, classifier) || is_buffer_end(right))
}
Self::Subword { ignore_punctuation } => {
todo!()
let classifier = classifier.ignore_punctuation(ignore_punctuation);
Ok(movement::is_subword_end(left, right, &classifier) || is_buffer_end(right))
}
Self::AngleBrackets => Ok(right == '>'),
Self::BackQuotes => Ok(right == '`'),
@ -136,7 +143,7 @@ fn try_find_boundary(
.next()
.unwrap_or('\0');
for ch in map.buffer_snapshot.chars_at(offset) {
for ch in map.buffer_snapshot.chars_at(offset).chain(['\0']) {
if is_boundary(prev_ch, ch)? {
return Ok(Some(
map.clip_point(offset.to_display_point(map), Bias::Right),
@ -157,13 +164,13 @@ fn try_find_preceding_boundary(
let mut offset = from.to_offset(map, Bias::Right);
let mut prev_ch = map.buffer_snapshot.chars_at(offset).next().unwrap_or('\0');
for ch in map.buffer_snapshot.reversed_chars_at(offset) {
for ch in map.buffer_snapshot.reversed_chars_at(offset).chain(['\0']) {
if is_boundary(ch, prev_ch)? {
return Ok(Some(
map.clip_point(offset.to_display_point(map), Bias::Right),
));
}
offset -= ch.len_utf8();
offset = offset.saturating_sub(ch.len_utf8());
prev_ch = ch;
}
@ -174,6 +181,10 @@ fn is_buffer_start(left: char) -> bool {
left == '\0'
}
fn is_buffer_end(right: char) -> bool {
right == '\0'
}
fn is_word_start(left: char, right: char, classifier: CharClassifier) -> bool {
classifier.kind(left) != classifier.kind(right)
&& classifier.kind(right) != CharKind::Whitespace

View file

@ -84,7 +84,8 @@ impl Object {
}
}
/// Returns the range of the object the cursor is over if it can be found with simple boundary checking. Potentially none. Follows helix convention.
/// Returns the range of the object the cursor is over if it can be found with simple boundary checking.
/// Potentially none. Follows helix convention.
fn current_bounded_object(
self,
map: &DisplaySnapshot,
@ -116,7 +117,8 @@ impl Object {
Ok(Some(prev_start..next_end))
}
/// Returns the range of the next object the cursor is not over if it can be found with simple boundary checking. Potentially none. Follows helix convention.
/// Returns the range of the next object the cursor is not over if it can be found with simple boundary checking.
/// Potentially none. Follows helix convention.
fn next_bounded_object(
self,
map: &DisplaySnapshot,
@ -138,7 +140,8 @@ impl Object {
Ok(Some(next_start..end))
}
/// Returns the previous range of the object the cursor not is over if it can be found with simple boundary checking. Potentially none. Follows helix convention.
/// Returns the previous range of the object the cursor not is over if it can be found with simple boundary checking.
/// Potentially none. Follows helix convention.
fn previous_bounded_object(
self,
map: &DisplaySnapshot,

View file

@ -1044,6 +1044,8 @@ impl Operator {
Operator::AutoIndent => "=".to_string(),
Operator::ShellCommand => "=".to_string(),
Operator::HelixMatch => "m".to_string(),
Operator::SelectNext => "]".to_string(),
Operator::SelectPrevious => "[".to_string(),
_ => self.id().to_string(),
}
}