mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-20 02:47:34 +03:00
Merge pull request #423 from zed-industries/line-selection
Refine line-oriented selection and deletion
This commit is contained in:
commit
01f702ae5e
@ -101,7 +101,7 @@ action!(SelectRight);
|
||||
action!(SelectToPreviousWordBoundary);
|
||||
action!(SelectToNextWordBoundary);
|
||||
action!(SelectToBeginningOfLine, bool);
|
||||
action!(SelectToEndOfLine);
|
||||
action!(SelectToEndOfLine, bool);
|
||||
action!(SelectToBeginning);
|
||||
action!(SelectToEnd);
|
||||
action!(SelectAll);
|
||||
@ -212,8 +212,8 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec<Box<dyn PathOpene
|
||||
SelectToBeginningOfLine(true),
|
||||
Some("Editor"),
|
||||
),
|
||||
Binding::new("cmd-shift-right", SelectToEndOfLine, Some("Editor")),
|
||||
Binding::new("ctrl-shift-E", SelectToEndOfLine, Some("Editor")),
|
||||
Binding::new("cmd-shift-right", SelectToEndOfLine(true), Some("Editor")),
|
||||
Binding::new("ctrl-shift-E", SelectToEndOfLine(true), Some("Editor")),
|
||||
Binding::new("cmd-shift-up", SelectToBeginning, Some("Editor")),
|
||||
Binding::new("cmd-shift-down", SelectToEnd, Some("Editor")),
|
||||
Binding::new("cmd-a", SelectAll, Some("Editor")),
|
||||
@ -968,15 +968,16 @@ impl Editor {
|
||||
mode = SelectMode::Word(start.clone()..end.clone());
|
||||
}
|
||||
3 => {
|
||||
let position = display_map.clip_point(position, Bias::Left);
|
||||
let line_start = movement::line_beginning(&display_map, position, false);
|
||||
let mut next_line_start = line_start.clone();
|
||||
*next_line_start.row_mut() += 1;
|
||||
*next_line_start.column_mut() = 0;
|
||||
next_line_start = display_map.clip_point(next_line_start, Bias::Right);
|
||||
|
||||
start = buffer.anchor_before(line_start.to_point(&display_map));
|
||||
end = buffer.anchor_before(next_line_start.to_point(&display_map));
|
||||
let position = display_map
|
||||
.clip_point(position, Bias::Left)
|
||||
.to_point(&display_map);
|
||||
let line_start = display_map.prev_line_boundary(position).0;
|
||||
let next_line_start = buffer.clip_point(
|
||||
display_map.next_line_boundary(position).0 + Point::new(1, 0),
|
||||
Bias::Left,
|
||||
);
|
||||
start = buffer.anchor_before(line_start);
|
||||
end = buffer.anchor_before(next_line_start);
|
||||
mode = SelectMode::Line(start.clone()..end.clone());
|
||||
}
|
||||
_ => {
|
||||
@ -1082,26 +1083,27 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
SelectMode::Line(original_range) => {
|
||||
let original_display_range = original_range.start.to_display_point(&display_map)
|
||||
..original_range.end.to_display_point(&display_map);
|
||||
let original_buffer_range = original_display_range.start.to_point(&display_map)
|
||||
..original_display_range.end.to_point(&display_map);
|
||||
let line_start = movement::line_beginning(&display_map, position, false);
|
||||
let mut next_line_start = line_start.clone();
|
||||
*next_line_start.row_mut() += 1;
|
||||
*next_line_start.column_mut() = 0;
|
||||
next_line_start = display_map.clip_point(next_line_start, Bias::Right);
|
||||
let original_range = original_range.to_point(&display_map.buffer_snapshot);
|
||||
|
||||
if line_start < original_display_range.start {
|
||||
head = line_start.to_point(&display_map);
|
||||
let position = display_map
|
||||
.clip_point(position, Bias::Left)
|
||||
.to_point(&display_map);
|
||||
let line_start = display_map.prev_line_boundary(position).0;
|
||||
let next_line_start = buffer.clip_point(
|
||||
display_map.next_line_boundary(position).0 + Point::new(1, 0),
|
||||
Bias::Left,
|
||||
);
|
||||
|
||||
if line_start < original_range.start {
|
||||
head = line_start
|
||||
} else {
|
||||
head = next_line_start.to_point(&display_map);
|
||||
head = next_line_start
|
||||
}
|
||||
|
||||
if head <= original_buffer_range.start {
|
||||
tail = original_buffer_range.end;
|
||||
if head <= original_range.start {
|
||||
tail = original_range.end;
|
||||
} else {
|
||||
tail = original_buffer_range.start;
|
||||
tail = original_range.start;
|
||||
}
|
||||
}
|
||||
SelectMode::All => {
|
||||
@ -2923,14 +2925,14 @@ impl Editor {
|
||||
|
||||
pub fn select_to_beginning_of_line(
|
||||
&mut self,
|
||||
SelectToBeginningOfLine(toggle_indent): &SelectToBeginningOfLine,
|
||||
SelectToBeginningOfLine(stop_at_soft_boundaries): &SelectToBeginningOfLine,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let mut selections = self.local_selections::<Point>(cx);
|
||||
for selection in &mut selections {
|
||||
let head = selection.head().to_display_point(&display_map);
|
||||
let new_head = movement::line_beginning(&display_map, head, *toggle_indent);
|
||||
let new_head = movement::line_beginning(&display_map, head, *stop_at_soft_boundaries);
|
||||
selection.set_head(new_head.to_point(&display_map));
|
||||
selection.goal = SelectionGoal::None;
|
||||
}
|
||||
@ -2954,7 +2956,7 @@ impl Editor {
|
||||
{
|
||||
for selection in &mut selections {
|
||||
let head = selection.head().to_display_point(&display_map);
|
||||
let new_head = movement::line_end(&display_map, head);
|
||||
let new_head = movement::line_end(&display_map, head, true);
|
||||
let anchor = new_head.to_point(&display_map);
|
||||
selection.start = anchor.clone();
|
||||
selection.end = anchor;
|
||||
@ -2965,12 +2967,16 @@ impl Editor {
|
||||
self.update_selections(selections, Some(Autoscroll::Fit), cx);
|
||||
}
|
||||
|
||||
pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext<Self>) {
|
||||
pub fn select_to_end_of_line(
|
||||
&mut self,
|
||||
SelectToEndOfLine(stop_at_soft_boundaries): &SelectToEndOfLine,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let mut selections = self.local_selections::<Point>(cx);
|
||||
for selection in &mut selections {
|
||||
let head = selection.head().to_display_point(&display_map);
|
||||
let new_head = movement::line_end(&display_map, head);
|
||||
let new_head = movement::line_end(&display_map, head, *stop_at_soft_boundaries);
|
||||
selection.set_head(new_head.to_point(&display_map));
|
||||
selection.goal = SelectionGoal::None;
|
||||
}
|
||||
@ -2979,14 +2985,14 @@ impl Editor {
|
||||
|
||||
pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
|
||||
self.start_transaction(cx);
|
||||
self.select_to_end_of_line(&SelectToEndOfLine, cx);
|
||||
self.select_to_end_of_line(&SelectToEndOfLine(false), cx);
|
||||
self.delete(&Delete, cx);
|
||||
self.end_transaction(cx);
|
||||
}
|
||||
|
||||
pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
|
||||
self.start_transaction(cx);
|
||||
self.select_to_end_of_line(&SelectToEndOfLine, cx);
|
||||
self.select_to_end_of_line(&SelectToEndOfLine(false), cx);
|
||||
self.cut(&Cut, cx);
|
||||
self.end_transaction(cx);
|
||||
}
|
||||
@ -5671,7 +5677,7 @@ mod tests {
|
||||
});
|
||||
|
||||
view.update(cx, |view, cx| {
|
||||
view.select_to_end_of_line(&SelectToEndOfLine, cx);
|
||||
view.select_to_end_of_line(&SelectToEndOfLine(true), cx);
|
||||
assert_eq!(
|
||||
view.selected_display_ranges(cx),
|
||||
&[
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
|
||||
use crate::{char_kind, CharKind, ToPoint};
|
||||
use anyhow::Result;
|
||||
use language::Point;
|
||||
use std::ops::Range;
|
||||
|
||||
pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> Result<DisplayPoint> {
|
||||
@ -93,20 +94,42 @@ pub fn down(
|
||||
|
||||
pub fn line_beginning(
|
||||
map: &DisplaySnapshot,
|
||||
point: DisplayPoint,
|
||||
toggle_indent: bool,
|
||||
display_point: DisplayPoint,
|
||||
stop_at_soft_boundaries: bool,
|
||||
) -> DisplayPoint {
|
||||
let (indent, is_blank) = map.line_indent(point.row());
|
||||
if toggle_indent && !is_blank && point.column() != indent {
|
||||
DisplayPoint::new(point.row(), indent)
|
||||
let point = display_point.to_point(map);
|
||||
let soft_line_start = map.clip_point(DisplayPoint::new(display_point.row(), 0), Bias::Right);
|
||||
let indent_start = Point::new(
|
||||
point.row,
|
||||
map.buffer_snapshot.indent_column_for_line(point.row),
|
||||
)
|
||||
.to_display_point(map);
|
||||
let line_start = map.prev_line_boundary(point).1;
|
||||
|
||||
if stop_at_soft_boundaries && soft_line_start > indent_start && display_point != soft_line_start
|
||||
{
|
||||
soft_line_start
|
||||
} else if stop_at_soft_boundaries && display_point != indent_start {
|
||||
indent_start
|
||||
} else {
|
||||
DisplayPoint::new(point.row(), 0)
|
||||
line_start
|
||||
}
|
||||
}
|
||||
|
||||
pub fn line_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let line_end = DisplayPoint::new(point.row(), map.line_len(point.row()));
|
||||
map.clip_point(line_end, Bias::Left)
|
||||
pub fn line_end(
|
||||
map: &DisplaySnapshot,
|
||||
display_point: DisplayPoint,
|
||||
stop_at_soft_boundaries: bool,
|
||||
) -> DisplayPoint {
|
||||
let soft_line_end = map.clip_point(
|
||||
DisplayPoint::new(display_point.row(), map.line_len(display_point.row())),
|
||||
Bias::Left,
|
||||
);
|
||||
if stop_at_soft_boundaries && display_point != soft_line_end {
|
||||
soft_line_end
|
||||
} else {
|
||||
map.next_line_boundary(display_point.to_point(map)).1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prev_word_boundary(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint {
|
||||
|
Loading…
Reference in New Issue
Block a user