Insert tabs instead of indenting only when all selections are empty

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-03-28 16:36:12 +02:00
parent ac88003c19
commit 2a1fed1387

View file

@ -307,7 +307,7 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action(Editor::newline); cx.add_action(Editor::newline);
cx.add_action(Editor::backspace); cx.add_action(Editor::backspace);
cx.add_action(Editor::delete); cx.add_action(Editor::delete);
cx.add_action(Editor::handle_tab); cx.add_action(Editor::tab);
cx.add_action(Editor::indent); cx.add_action(Editor::indent);
cx.add_action(Editor::outdent); cx.add_action(Editor::outdent);
cx.add_action(Editor::delete_line); cx.add_action(Editor::delete_line);
@ -2865,7 +2865,7 @@ impl Editor {
}); });
} }
pub fn handle_tab(&mut self, &Tab(direction): &Tab, cx: &mut ViewContext<Self>) { pub fn tab(&mut self, &Tab(direction): &Tab, cx: &mut ViewContext<Self>) {
match direction { match direction {
Direction::Prev => { Direction::Prev => {
if !self.snippet_stack.is_empty() { if !self.snippet_stack.is_empty() {
@ -2880,22 +2880,17 @@ impl Editor {
return; return;
} }
self.tab(false, cx);
}
}
}
pub fn tab(&mut self, force_indentation: bool, cx: &mut ViewContext<Self>) {
let tab_size = cx.global::<Settings>().tab_size; let tab_size = cx.global::<Settings>().tab_size;
let mut selections = self.local_selections::<Point>(cx); let mut selections = self.local_selections::<Point>(cx);
if selections.iter().all(|s| s.is_empty()) {
self.transact(cx, |this, cx| { self.transact(cx, |this, cx| {
let mut last_indent = None;
this.buffer.update(cx, |buffer, cx| { this.buffer.update(cx, |buffer, cx| {
for selection in &mut selections { for selection in &mut selections {
if selection.is_empty() && !force_indentation {
let char_column = buffer let char_column = buffer
.read(cx) .read(cx)
.text_for_range(Point::new(selection.start.row, 0)..selection.start) .text_for_range(
Point::new(selection.start.row, 0)..selection.start,
)
.flat_map(str::chars) .flat_map(str::chars)
.count(); .count();
let chars_to_next_tab_stop = tab_size - (char_column % tab_size); let chars_to_next_tab_stop = tab_size - (char_column % tab_size);
@ -2906,7 +2901,24 @@ impl Editor {
); );
selection.start.column += chars_to_next_tab_stop as u32; selection.start.column += chars_to_next_tab_stop as u32;
selection.end = selection.start; selection.end = selection.start;
}
});
this.update_selections(selections, Some(Autoscroll::Fit), cx);
});
} else { } else {
self.indent(&Indent, cx);
}
}
}
}
pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
let tab_size = cx.global::<Settings>().tab_size;
let mut selections = self.local_selections::<Point>(cx);
self.transact(cx, |this, cx| {
let mut last_indent = None;
this.buffer.update(cx, |buffer, cx| {
for selection in &mut selections {
let mut start_row = selection.start.row; let mut start_row = selection.start.row;
let mut end_row = selection.end.row + 1; let mut end_row = selection.end.row + 1;
@ -2930,8 +2942,7 @@ impl Editor {
} }
for row in start_row..end_row { for row in start_row..end_row {
let indent_column = let indent_column = buffer.read(cx).indent_column_for_line(row) as usize;
buffer.read(cx).indent_column_for_line(row) as usize;
let columns_to_next_tab_stop = tab_size - (indent_column % tab_size); let columns_to_next_tab_stop = tab_size - (indent_column % tab_size);
let row_start = Point::new(row, 0); let row_start = Point::new(row, 0);
buffer.edit( buffer.edit(
@ -2951,17 +2962,12 @@ impl Editor {
last_indent = Some((row, columns_to_next_tab_stop as u32)); last_indent = Some((row, columns_to_next_tab_stop as u32));
} }
} }
}
}); });
this.update_selections(selections, Some(Autoscroll::Fit), cx); this.update_selections(selections, Some(Autoscroll::Fit), cx);
}); });
} }
pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
self.tab(true, cx);
}
pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) { pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
let tab_size = cx.global::<Settings>().tab_size; let tab_size = cx.global::<Settings>().tab_size;
let selections = self.local_selections::<Point>(cx); let selections = self.local_selections::<Point>(cx);
@ -7477,7 +7483,7 @@ mod tests {
); );
// indent from mid-tabstop to full tabstop // indent from mid-tabstop to full tabstop
view.tab(false, cx); view.tab(&Tab(Direction::Next), cx);
assert_eq!(view.text(cx), " one two\nthree\n four"); assert_eq!(view.text(cx), " one two\nthree\n four");
assert_eq!( assert_eq!(
view.selected_display_ranges(cx), view.selected_display_ranges(cx),
@ -7488,7 +7494,7 @@ mod tests {
); );
// outdent from 1 tabstop to 0 tabstops // outdent from 1 tabstop to 0 tabstops
view.outdent(&Outdent, cx); view.tab(&Tab(Direction::Prev), cx);
assert_eq!(view.text(cx), "one two\nthree\n four"); assert_eq!(view.text(cx), "one two\nthree\n four");
assert_eq!( assert_eq!(
view.selected_display_ranges(cx), view.selected_display_ranges(cx),
@ -7502,13 +7508,13 @@ mod tests {
view.select_display_ranges(&[DisplayPoint::new(1, 1)..DisplayPoint::new(2, 0)], cx); view.select_display_ranges(&[DisplayPoint::new(1, 1)..DisplayPoint::new(2, 0)], cx);
// indent and outdent affect only the preceding line // indent and outdent affect only the preceding line
view.tab(false, cx); view.tab(&Tab(Direction::Next), cx);
assert_eq!(view.text(cx), "one two\n three\n four"); assert_eq!(view.text(cx), "one two\n three\n four");
assert_eq!( assert_eq!(
view.selected_display_ranges(cx), view.selected_display_ranges(cx),
&[DisplayPoint::new(1, 5)..DisplayPoint::new(2, 0)] &[DisplayPoint::new(1, 5)..DisplayPoint::new(2, 0)]
); );
view.outdent(&Outdent, cx); view.tab(&Tab(Direction::Prev), cx);
assert_eq!(view.text(cx), "one two\nthree\n four"); assert_eq!(view.text(cx), "one two\nthree\n four");
assert_eq!( assert_eq!(
view.selected_display_ranges(cx), view.selected_display_ranges(cx),
@ -7517,7 +7523,7 @@ mod tests {
// Ensure that indenting/outdenting works when the cursor is at column 0. // Ensure that indenting/outdenting works when the cursor is at column 0.
view.select_display_ranges(&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], cx); view.select_display_ranges(&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], cx);
view.tab(false, cx); view.tab(&Tab(Direction::Next), cx);
assert_eq!(view.text(cx), "one two\n three\n four"); assert_eq!(view.text(cx), "one two\n three\n four");
assert_eq!( assert_eq!(
view.selected_display_ranges(cx), view.selected_display_ranges(cx),
@ -7525,7 +7531,7 @@ mod tests {
); );
view.select_display_ranges(&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], cx); view.select_display_ranges(&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], cx);
view.outdent(&Outdent, cx); view.tab(&Tab(Direction::Prev), cx);
assert_eq!(view.text(cx), "one two\nthree\n four"); assert_eq!(view.text(cx), "one two\nthree\n four");
assert_eq!( assert_eq!(
view.selected_display_ranges(cx), view.selected_display_ranges(cx),