diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 7fae4ecdd0..19b5707405 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -1086,12 +1086,15 @@ impl Buffer { let mut prev_row = prev_non_blank_row.unwrap_or(0); let mut prev_indent_column = - prev_non_blank_row.map_or(0, |prev_row| self.indent_column_for_line(prev_row, cx)); + prev_non_blank_row.map_or(0, |prev_row| self.indent_column_for_line(prev_row)); for row in row_range { let request = autoindent_requests.get(&row).unwrap(); - let row_start = Point::new(row, self.indent_column_for_line(row, cx)); + let row_start = Point::new(row, self.indent_column_for_line(row)); - eprintln!("autoindent row: {:?}", row); + eprintln!( + "autoindent row: {:?}, prev_indent_column: {:?}", + row, prev_indent_column + ); let mut increase_from_prev_row = false; let mut dedent_to_row = u32::MAX; @@ -1114,7 +1117,7 @@ impl Buffer { if increase_from_prev_row { indent_column += request.indent_size as u32; } else if dedent_to_row < row { - indent_column = self.indent_column_for_line(dedent_to_row, cx); + indent_column = self.indent_column_for_line(dedent_to_row); } self.set_indent_column_for_line(row, indent_column, cx); @@ -1133,7 +1136,7 @@ impl Buffer { None } - fn indent_column_for_line(&mut self, row: u32, cx: &mut ModelContext) -> u32 { + pub fn indent_column_for_line(&self, row: u32) -> u32 { let mut result = 0; for c in self.chars_at(Point::new(row, 0)) { if c == ' ' { @@ -1146,7 +1149,7 @@ impl Buffer { } fn set_indent_column_for_line(&mut self, row: u32, column: u32, cx: &mut ModelContext) { - let current_column = self.indent_column_for_line(row, cx); + let current_column = self.indent_column_for_line(row); if column > current_column { let offset = self.visible_text.to_offset(Point::new(row, 0)); @@ -1346,6 +1349,10 @@ impl Buffer { self.visible_text.chars_at(offset) } + pub fn chars_for_range(&self, range: Range) -> impl Iterator + '_ { + self.text_for_range(range).flat_map(str::chars) + } + pub fn bytes_at(&self, position: T) -> impl Iterator + '_ { let offset = position.to_offset(self); self.visible_text.bytes_at(offset) diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 3fa4bdfa27..27cb92afa2 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -38,6 +38,7 @@ action!(Cancel); action!(Backspace); action!(Delete); action!(Input, String); +action!(Tab); action!(DeleteLine); action!(DeleteToPreviousWordBoundary); action!(DeleteToNextWordBoundary); @@ -101,7 +102,7 @@ pub fn init(cx: &mut MutableAppContext) { Input("\n".into()), Some("Editor && mode == auto_height"), ), - Binding::new("tab", Input("\t".into()), Some("Editor")), + Binding::new("tab", Tab, Some("Editor")), Binding::new("ctrl-shift-K", DeleteLine, Some("Editor")), Binding::new( "alt-backspace", @@ -195,6 +196,7 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(Editor::handle_input); cx.add_action(Editor::backspace); cx.add_action(Editor::delete); + cx.add_action(Editor::tab); cx.add_action(Editor::delete_line); cx.add_action(Editor::delete_to_previous_word_boundary); cx.add_action(Editor::delete_to_next_word_boundary); @@ -962,6 +964,51 @@ impl Editor { self.end_transaction(cx); } + pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { + self.start_transaction(cx); + let tab_size = self.build_settings.borrow()(cx).tab_size; + let mut selections = self.selections(cx).to_vec(); + self.buffer.update(cx, |buffer, cx| { + let mut last_indented_row = None; + for selection in &mut selections { + let mut range = selection.point_range(buffer); + if range.is_empty() { + let char_column = buffer + .chars_for_range(Point::new(range.start.row, 0)..range.start) + .count(); + let chars_to_next_tab_stop = tab_size - (char_column % tab_size); + buffer.edit( + [range.start..range.start], + " ".repeat(chars_to_next_tab_stop), + cx, + ); + range.start.column += chars_to_next_tab_stop as u32; + + let head = buffer.anchor_before(range.start); + selection.start = head.clone(); + selection.end = head; + } else { + for row in range.start.row..=range.end.row { + if last_indented_row != Some(row) { + let char_column = buffer.indent_column_for_line(row) as usize; + let chars_to_next_tab_stop = tab_size - (char_column % tab_size); + let row_start = Point::new(row, 0); + buffer.edit( + [row_start..row_start], + " ".repeat(chars_to_next_tab_stop), + cx, + ); + last_indented_row = Some(row); + } + } + } + } + }); + + self.update_selections(selections, true, cx); + self.end_transaction(cx); + } + pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext) { self.start_transaction(cx);