Improve Editor::DuplicateSelection (#21976)
Improves the new `Editor::DuplicateSelection` @CharlesChen0823 added in https://github.com/zed-industries/zed/pull/21154. - Merge `duplicate_selection` and `duplicate_line` into single function. - Add keyboard shortcuts to JetBrains and SublimeText keymaps. - If the selection is empty (e.g. just a cursor) make `Editor::DuplicateSelection` fallback to being the same as `Editor::DuplicateLineDown`. - Tested with multiple cursors and for multiple selections. | Editor | Action | macOS | Linux | | ----------- | ------------------- | ----------- | ------------ | | VSCode | Duplicate Selection | | | | JetBrains | Duplicate Selection | cmd-d | ctrl-d | | XCode | Duplicate | cmd-d | N/A | | SublimeText | duplicate_line | cmd-shift-d | ctrl-shift-d | This matches behavior of the `duplicate` functionality in all other major editors, with one exception: other editors change the selection so that the newly duplicated object, current Zed behavior leaves the original selection unchanged (TODO?)
This commit is contained in:
parent
06edcd18be
commit
735849e201
5 changed files with 45 additions and 55 deletions
|
@ -12,7 +12,7 @@
|
|||
"ctrl->": "zed::IncreaseBufferFontSize",
|
||||
"ctrl-<": "zed::DecreaseBufferFontSize",
|
||||
"ctrl-shift-j": "editor::JoinLines",
|
||||
"ctrl-d": "editor::DuplicateLineDown",
|
||||
"ctrl-d": "editor::DuplicateSelection",
|
||||
"ctrl-y": "editor::DeleteLine",
|
||||
"ctrl-m": "editor::ScrollCursorCenter",
|
||||
"ctrl-pagedown": "editor::MovePageDown",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"ctrl-shift-m": "editor::SelectLargerSyntaxNode",
|
||||
"ctrl-shift-l": "editor::SplitSelectionIntoLines",
|
||||
"ctrl-shift-a": "editor::SelectLargerSyntaxNode",
|
||||
"ctrl-shift-d": "editor::DuplicateLineDown",
|
||||
"ctrl-shift-d": "editor::DuplicateSelection",
|
||||
"alt-f3": "editor::SelectAllMatches", // find_all_under
|
||||
"f12": "editor::GoToDefinition",
|
||||
"ctrl-f12": "editor::GoToDefinitionSplit",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"ctrl->": "zed::IncreaseBufferFontSize",
|
||||
"ctrl-<": "zed::DecreaseBufferFontSize",
|
||||
"ctrl-shift-j": "editor::JoinLines",
|
||||
"cmd-d": "editor::DuplicateLineDown",
|
||||
"cmd-d": "editor::DuplicateSelection",
|
||||
"cmd-backspace": "editor::DeleteLine",
|
||||
"cmd-pagedown": "editor::MovePageDown",
|
||||
"cmd-pageup": "editor::MovePageUp",
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"ctrl-shift-m": "editor::SelectLargerSyntaxNode",
|
||||
"cmd-shift-l": "editor::SplitSelectionIntoLines",
|
||||
"cmd-shift-a": "editor::SelectLargerSyntaxNode",
|
||||
"cmd-shift-d": "editor::DuplicateLineDown",
|
||||
"cmd-shift-d": "editor::DuplicateSelection",
|
||||
"ctrl-cmd-g": "editor::SelectAllMatches", // find_all_under
|
||||
"shift-f12": "editor::FindAllReferences",
|
||||
"alt-cmd-down": "editor::GoToDefinition",
|
||||
|
|
|
@ -6135,29 +6135,7 @@ impl Editor {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn duplicate_selection(&mut self, _: &DuplicateSelection, cx: &mut ViewContext<Self>) {
|
||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let buffer = &display_map.buffer_snapshot;
|
||||
let selections = self.selections.all::<Point>(cx);
|
||||
|
||||
let mut edits = Vec::new();
|
||||
for selection in selections.iter() {
|
||||
let start = selection.start;
|
||||
let end = selection.end;
|
||||
let text = buffer.text_for_range(start..end).collect::<String>();
|
||||
edits.push((selection.end..selection.end, text));
|
||||
}
|
||||
|
||||
self.transact(cx, |this, cx| {
|
||||
this.buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit(edits, None, cx);
|
||||
});
|
||||
|
||||
this.request_autoscroll(Autoscroll::fit(), cx);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn duplicate_line(&mut self, upwards: bool, cx: &mut ViewContext<Self>) {
|
||||
pub fn duplicate(&mut self, upwards: bool, whole_lines: bool, cx: &mut ViewContext<Self>) {
|
||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let buffer = &display_map.buffer_snapshot;
|
||||
let selections = self.selections.all::<Point>(cx);
|
||||
|
@ -6165,36 +6143,44 @@ impl Editor {
|
|||
let mut edits = Vec::new();
|
||||
let mut selections_iter = selections.iter().peekable();
|
||||
while let Some(selection) = selections_iter.next() {
|
||||
// Avoid duplicating the same lines twice.
|
||||
let mut rows = selection.spanned_rows(false, &display_map);
|
||||
|
||||
while let Some(next_selection) = selections_iter.peek() {
|
||||
let next_rows = next_selection.spanned_rows(false, &display_map);
|
||||
if next_rows.start < rows.end {
|
||||
rows.end = next_rows.end;
|
||||
selections_iter.next().unwrap();
|
||||
} else {
|
||||
break;
|
||||
// duplicate line-wise
|
||||
if whole_lines || selection.start == selection.end {
|
||||
// Avoid duplicating the same lines twice.
|
||||
while let Some(next_selection) = selections_iter.peek() {
|
||||
let next_rows = next_selection.spanned_rows(false, &display_map);
|
||||
if next_rows.start < rows.end {
|
||||
rows.end = next_rows.end;
|
||||
selections_iter.next().unwrap();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the text from the selected row region and splice it either at the start
|
||||
// or end of the region.
|
||||
let start = Point::new(rows.start.0, 0);
|
||||
let end = Point::new(
|
||||
rows.end.previous_row().0,
|
||||
buffer.line_len(rows.end.previous_row()),
|
||||
);
|
||||
let text = buffer
|
||||
.text_for_range(start..end)
|
||||
.chain(Some("\n"))
|
||||
.collect::<String>();
|
||||
let insert_location = if upwards {
|
||||
Point::new(rows.end.0, 0)
|
||||
// Copy the text from the selected row region and splice it either at the start
|
||||
// or end of the region.
|
||||
let start = Point::new(rows.start.0, 0);
|
||||
let end = Point::new(
|
||||
rows.end.previous_row().0,
|
||||
buffer.line_len(rows.end.previous_row()),
|
||||
);
|
||||
let text = buffer
|
||||
.text_for_range(start..end)
|
||||
.chain(Some("\n"))
|
||||
.collect::<String>();
|
||||
let insert_location = if upwards {
|
||||
Point::new(rows.end.0, 0)
|
||||
} else {
|
||||
start
|
||||
};
|
||||
edits.push((insert_location..insert_location, text));
|
||||
} else {
|
||||
start
|
||||
};
|
||||
edits.push((insert_location..insert_location, text));
|
||||
// duplicate character-wise
|
||||
let start = selection.start;
|
||||
let end = selection.end;
|
||||
let text = buffer.text_for_range(start..end).collect::<String>();
|
||||
edits.push((selection.end..selection.end, text));
|
||||
}
|
||||
}
|
||||
|
||||
self.transact(cx, |this, cx| {
|
||||
|
@ -6207,11 +6193,15 @@ impl Editor {
|
|||
}
|
||||
|
||||
pub fn duplicate_line_up(&mut self, _: &DuplicateLineUp, cx: &mut ViewContext<Self>) {
|
||||
self.duplicate_line(true, cx);
|
||||
self.duplicate(true, true, cx);
|
||||
}
|
||||
|
||||
pub fn duplicate_line_down(&mut self, _: &DuplicateLineDown, cx: &mut ViewContext<Self>) {
|
||||
self.duplicate_line(false, cx);
|
||||
self.duplicate(false, true, cx);
|
||||
}
|
||||
|
||||
pub fn duplicate_selection(&mut self, _: &DuplicateSelection, cx: &mut ViewContext<Self>) {
|
||||
self.duplicate(false, false, cx);
|
||||
}
|
||||
|
||||
pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue