diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index c0b320cfac568a70af20476ba05d0b5375f9160e..f5aa563ccde07bdf93ea5cf5f4d277094f34ec71 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -54,6 +54,11 @@ pub fn init(app: &mut MutableAppContext) { Binding::new("down", "buffer:move_down", Some("BufferView")), Binding::new("left", "buffer:move_left", Some("BufferView")), Binding::new("right", "buffer:move_right", Some("BufferView")), + Binding::new( + "alt-right", + "buffer:move_to_next_word_boundary", + Some("BufferView"), + ), Binding::new( "cmd-left", "buffer:move_to_beginning_of_line", @@ -141,6 +146,10 @@ pub fn init(app: &mut MutableAppContext) { app.add_action("buffer:move_down", BufferView::move_down); app.add_action("buffer:move_left", BufferView::move_left); app.add_action("buffer:move_right", BufferView::move_right); + app.add_action( + "buffer:move_to_next_word_boundary", + BufferView::move_to_next_word_boundary, + ); app.add_action( "buffer:move_to_beginning_of_line", BufferView::move_to_beginning_of_line, @@ -1085,6 +1094,24 @@ impl BufferView { self.update_selections(selections, true, ctx); } + pub fn move_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + let map = self.display_map.read(app); + for selection in &mut selections { + let head = selection.head().to_display_point(map, app).unwrap(); + let new_head = movement::next_word_boundary(map, head, app).unwrap(); + let anchor = map.anchor_before(new_head, Bias::Left, app).unwrap(); + selection.start = anchor.clone(); + selection.end = anchor; + selection.reversed = false; + selection.goal_column = None; + } + } + self.update_selections(selections, true, ctx); + } + pub fn move_to_beginning_of_line(&mut self, _: &(), ctx: &mut ViewContext) { let app = ctx.as_ref(); let mut selections = self.selections(app).to_vec(); diff --git a/zed/src/editor/movement.rs b/zed/src/editor/movement.rs index 44e981f71b0bbddbe413cfe215057cbcb66363f4..040e59705dc40070269ca9ca26f8c9b753ddb593 100644 --- a/zed/src/editor/movement.rs +++ b/zed/src/editor/movement.rs @@ -79,3 +79,42 @@ pub fn line_end(map: &DisplayMap, point: DisplayPoint, app: &AppContext) -> Resu map.line_len(point.row(), app)?, )) } + +pub fn prev_word_boundary( + map: &DisplayMap, + point: DisplayPoint, + app: &AppContext, +) -> Result { + todo!() +} + +pub fn next_word_boundary( + map: &DisplayMap, + mut point: DisplayPoint, + app: &AppContext, +) -> Result { + let mut prev_c = None; + for c in map.chars_at(point, app)? { + if prev_c.is_some() && (c == '\n' || is_word_char(prev_c.unwrap()) != is_word_char(c)) { + break; + } + + if c == '\n' { + *point.row_mut() += 1; + *point.column_mut() = 0; + } else { + *point.column_mut() += 1; + } + prev_c = Some(c); + } + Ok(point) +} + +fn is_word_char(c: char) -> bool { + match c { + '/' | '\\' | '(' | ')' | '"' | '\'' | ':' | ',' | '.' | ';' | '<' | '>' | '~' | '!' + | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '|' | '+' | '=' | '[' | ']' | '{' | '}' + | '`' | '?' | '-' | '…' | ' ' | '\n' => false, + _ => true, + } +}