Tweak behavior of selections when renaming
This commit is contained in:
parent
f0a6e8cb9c
commit
80bca57bfa
5 changed files with 124 additions and 80 deletions
|
@ -478,10 +478,10 @@ struct SnippetState {
|
||||||
active_index: usize,
|
active_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RenameState {
|
pub struct RenameState {
|
||||||
range: Range<Anchor>,
|
pub range: Range<Anchor>,
|
||||||
old_name: String,
|
pub old_name: String,
|
||||||
editor: ViewHandle<Editor>,
|
pub editor: ViewHandle<Editor>,
|
||||||
block_id: BlockId,
|
block_id: BlockId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3163,23 +3163,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
|
pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
|
||||||
if let Some((range, column, _, _)) = self.take_rename(cx) {
|
if self.take_rename(cx).is_some() {
|
||||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
|
||||||
let position = snapshot.clip_point(
|
|
||||||
range.start.to_point(&snapshot) + Point::new(0, column),
|
|
||||||
Bias::Left,
|
|
||||||
);
|
|
||||||
self.update_selections(
|
|
||||||
vec![Selection {
|
|
||||||
id: self.newest_anchor_selection().id,
|
|
||||||
start: position,
|
|
||||||
end: position,
|
|
||||||
reversed: false,
|
|
||||||
goal: SelectionGoal::None,
|
|
||||||
}],
|
|
||||||
None,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3227,6 +3211,8 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
|
pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
|
||||||
|
self.take_rename(cx);
|
||||||
|
|
||||||
if let Some(context_menu) = self.context_menu.as_mut() {
|
if let Some(context_menu) = self.context_menu.as_mut() {
|
||||||
if context_menu.select_next(cx) {
|
if context_menu.select_next(cx) {
|
||||||
return;
|
return;
|
||||||
|
@ -4116,39 +4102,57 @@ impl Editor {
|
||||||
use language::ToOffset as _;
|
use language::ToOffset as _;
|
||||||
|
|
||||||
let project = self.project.clone()?;
|
let project = self.project.clone()?;
|
||||||
let position = self.newest_anchor_selection().head();
|
let selection = self.newest_anchor_selection().clone();
|
||||||
let (buffer, buffer_position) = self
|
let (cursor_buffer, cursor_buffer_position) = self
|
||||||
.buffer
|
.buffer
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.text_anchor_for_position(position.clone(), cx)?;
|
.text_anchor_for_position(selection.head(), cx)?;
|
||||||
let snapshot = buffer.read(cx).snapshot();
|
let (tail_buffer, tail_buffer_position) = self
|
||||||
|
.buffer
|
||||||
|
.read(cx)
|
||||||
|
.text_anchor_for_position(selection.tail(), cx)?;
|
||||||
|
if tail_buffer != cursor_buffer {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let snapshot = cursor_buffer.read(cx).snapshot();
|
||||||
|
let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
|
||||||
|
let tail_buffer_offset = tail_buffer_position.to_offset(&snapshot);
|
||||||
let prepare_rename = project.update(cx, |project, cx| {
|
let prepare_rename = project.update(cx, |project, cx| {
|
||||||
project.prepare_rename(buffer.clone(), buffer_position.to_offset(&snapshot), cx)
|
project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(cx.spawn(|this, mut cx| async move {
|
Some(cx.spawn(|this, mut cx| async move {
|
||||||
if let Some(range) = prepare_rename.await? {
|
if let Some(rename_range) = prepare_rename.await? {
|
||||||
let buffer_offset_range = range.to_offset(&snapshot);
|
let rename_buffer_range = rename_range.to_offset(&snapshot);
|
||||||
let buffer_offset = buffer_position.to_offset(&snapshot);
|
let cursor_offset_in_rename_range =
|
||||||
let lookbehind = buffer_offset.saturating_sub(buffer_offset_range.start);
|
cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
|
||||||
let lookahead = buffer_offset_range.end.saturating_sub(buffer_offset);
|
let tail_offset_in_rename_range =
|
||||||
|
tail_buffer_offset.saturating_sub(rename_buffer_range.start);
|
||||||
|
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
let settings = (this.build_settings)(cx);
|
let settings = (this.build_settings)(cx);
|
||||||
let buffer = this.buffer.read(cx).read(cx);
|
let buffer = this.buffer.read(cx).read(cx);
|
||||||
let offset = position.to_offset(&buffer);
|
let cursor_offset = selection.head().to_offset(&buffer);
|
||||||
let start = offset - lookbehind;
|
let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
|
||||||
let end = offset + lookahead;
|
let rename_end = rename_start + rename_buffer_range.len();
|
||||||
let rename_range = buffer.anchor_before(start)..buffer.anchor_after(end);
|
let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
|
||||||
let old_name = buffer.text_for_range(start..end).collect::<String>();
|
let old_name = buffer
|
||||||
|
.text_for_range(rename_start..rename_end)
|
||||||
|
.collect::<String>();
|
||||||
drop(buffer);
|
drop(buffer);
|
||||||
|
|
||||||
let editor = cx.add_view(|cx| {
|
// Position the selection in the rename editor so that it matches the current selection.
|
||||||
|
let rename_editor = cx.add_view(|cx| {
|
||||||
let mut editor = Editor::single_line(this.build_settings.clone(), cx);
|
let mut editor = Editor::single_line(this.build_settings.clone(), cx);
|
||||||
editor
|
editor
|
||||||
.buffer
|
.buffer
|
||||||
.update(cx, |buffer, cx| buffer.edit([0..0], &old_name, cx));
|
.update(cx, |buffer, cx| buffer.edit([0..0], &old_name, cx));
|
||||||
editor.select_ranges([0..old_name.len()], None, cx);
|
editor.select_ranges(
|
||||||
|
[tail_offset_in_rename_range..cursor_offset_in_rename_range],
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
editor.highlight_ranges::<Rename>(
|
editor.highlight_ranges::<Rename>(
|
||||||
vec![Anchor::min()..Anchor::max()],
|
vec![Anchor::min()..Anchor::max()],
|
||||||
settings.style.diff_background_inserted,
|
settings.style.diff_background_inserted,
|
||||||
|
@ -4157,17 +4161,28 @@ impl Editor {
|
||||||
editor
|
editor
|
||||||
});
|
});
|
||||||
this.highlight_ranges::<Rename>(
|
this.highlight_ranges::<Rename>(
|
||||||
vec![rename_range.clone()],
|
vec![range.clone()],
|
||||||
settings.style.diff_background_deleted,
|
settings.style.diff_background_deleted,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
cx.focus(&editor);
|
this.update_selections(
|
||||||
|
vec![Selection {
|
||||||
|
id: selection.id,
|
||||||
|
start: rename_end,
|
||||||
|
end: rename_end,
|
||||||
|
reversed: false,
|
||||||
|
goal: SelectionGoal::None,
|
||||||
|
}],
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
cx.focus(&rename_editor);
|
||||||
let block_id = this.insert_blocks(
|
let block_id = this.insert_blocks(
|
||||||
[BlockProperties {
|
[BlockProperties {
|
||||||
position: rename_range.start.clone(),
|
position: range.start.clone(),
|
||||||
height: 1,
|
height: 1,
|
||||||
render: Arc::new({
|
render: Arc::new({
|
||||||
let editor = editor.clone();
|
let editor = rename_editor.clone();
|
||||||
move |cx: &BlockContext| {
|
move |cx: &BlockContext| {
|
||||||
ChildView::new(editor.clone())
|
ChildView::new(editor.clone())
|
||||||
.contained()
|
.contained()
|
||||||
|
@ -4180,9 +4195,9 @@ impl Editor {
|
||||||
cx,
|
cx,
|
||||||
)[0];
|
)[0];
|
||||||
this.pending_rename = Some(RenameState {
|
this.pending_rename = Some(RenameState {
|
||||||
range: rename_range,
|
range,
|
||||||
old_name,
|
old_name,
|
||||||
editor,
|
editor: rename_editor,
|
||||||
block_id,
|
block_id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4200,12 +4215,15 @@ impl Editor {
|
||||||
let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
|
let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
|
||||||
|
|
||||||
let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
|
let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
|
||||||
let (range, _, old_name, new_name) = editor.take_rename(cx)?;
|
let rename = editor.take_rename(cx)?;
|
||||||
let buffer = editor.buffer.read(cx);
|
let buffer = editor.buffer.read(cx);
|
||||||
let (start_buffer, start) = buffer.text_anchor_for_position(range.start.clone(), cx)?;
|
let (start_buffer, start) =
|
||||||
let (end_buffer, end) = buffer.text_anchor_for_position(range.end.clone(), cx)?;
|
buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
|
||||||
|
let (end_buffer, end) =
|
||||||
|
buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
|
||||||
if start_buffer == end_buffer {
|
if start_buffer == end_buffer {
|
||||||
Some((start_buffer, start..end, old_name, new_name))
|
let new_name = rename.editor.read(cx).text(cx);
|
||||||
|
Some((start_buffer, start..end, rename.old_name, new_name))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -4234,23 +4252,38 @@ impl Editor {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_rename(
|
fn take_rename(&mut self, cx: &mut ViewContext<Self>) -> Option<RenameState> {
|
||||||
&mut self,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) -> Option<(Range<Anchor>, u32, String, String)> {
|
|
||||||
let rename = self.pending_rename.take()?;
|
let rename = self.pending_rename.take()?;
|
||||||
let editor = rename.editor.read(cx);
|
|
||||||
let new_name = editor.text(cx);
|
|
||||||
let buffer = editor.buffer.read(cx).snapshot(cx);
|
|
||||||
let rename_position = editor.newest_selection::<Point>(&buffer);
|
|
||||||
self.remove_blocks([rename.block_id].into_iter().collect(), cx);
|
self.remove_blocks([rename.block_id].into_iter().collect(), cx);
|
||||||
self.clear_highlighted_ranges::<Rename>(cx);
|
self.clear_highlighted_ranges::<Rename>(cx);
|
||||||
Some((
|
|
||||||
rename.range,
|
let editor = rename.editor.read(cx);
|
||||||
rename_position.head().column,
|
let buffer = editor.buffer.read(cx).snapshot(cx);
|
||||||
rename.old_name,
|
let selection = editor.newest_selection::<usize>(&buffer);
|
||||||
new_name,
|
|
||||||
))
|
// Update the selection to match the position of the selection inside
|
||||||
|
// the rename editor.
|
||||||
|
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||||
|
let rename_range = rename.range.to_offset(&snapshot);
|
||||||
|
let start = snapshot
|
||||||
|
.clip_offset(rename_range.start + selection.start, Bias::Left)
|
||||||
|
.min(rename_range.end);
|
||||||
|
let end = snapshot
|
||||||
|
.clip_offset(rename_range.start + selection.end, Bias::Left)
|
||||||
|
.min(rename_range.end);
|
||||||
|
self.update_selections(
|
||||||
|
vec![Selection {
|
||||||
|
id: self.newest_anchor_selection().id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
reversed: selection.reversed,
|
||||||
|
goal: SelectionGoal::None,
|
||||||
|
}],
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(rename)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalidate_rename_range(
|
fn invalidate_rename_range(
|
||||||
|
@ -4266,11 +4299,17 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let rename = self.pending_rename.take().unwrap();
|
||||||
self.take_rename(cx);
|
self.remove_blocks([rename.block_id].into_iter().collect(), cx);
|
||||||
|
self.clear_highlighted_ranges::<Rename>(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
pub fn pending_rename(&self) -> Option<&RenameState> {
|
||||||
|
self.pending_rename.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
|
fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
|
||||||
if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
|
if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
|
||||||
let buffer = self.buffer.read(cx).snapshot(cx);
|
let buffer = self.buffer.read(cx).snapshot(cx);
|
||||||
|
|
|
@ -1153,7 +1153,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
editor::{
|
editor::{
|
||||||
self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, EditorSettings,
|
self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, EditorSettings,
|
||||||
Input, MultiBuffer, Redo, Rename, ToggleCodeActions, Undo,
|
Input, MultiBuffer, Redo, Rename, ToOffset, ToggleCodeActions, Undo,
|
||||||
},
|
},
|
||||||
fs::{FakeFs, Fs as _},
|
fs::{FakeFs, Fs as _},
|
||||||
language::{
|
language::{
|
||||||
|
@ -3140,12 +3140,17 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
prepare_rename.await.unwrap();
|
prepare_rename.await.unwrap();
|
||||||
editor_b.update(&mut cx_b, |editor, cx| {
|
editor_b.update(&mut cx_b, |editor, cx| {
|
||||||
assert_eq!(editor.selected_ranges(cx), [6..9]);
|
let rename = editor.pending_rename().unwrap();
|
||||||
editor.handle_input(&Input("T".to_string()), cx);
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
editor.handle_input(&Input("H".to_string()), cx);
|
assert_eq!(
|
||||||
editor.handle_input(&Input("R".to_string()), cx);
|
rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),
|
||||||
editor.handle_input(&Input("E".to_string()), cx);
|
6..9
|
||||||
editor.handle_input(&Input("E".to_string()), cx);
|
);
|
||||||
|
rename.editor.update(cx, |rename_editor, cx| {
|
||||||
|
rename_editor.buffer().update(cx, |rename_buffer, cx| {
|
||||||
|
rename_buffer.edit([0..3], "THREE", cx);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let confirm_rename = workspace_b.update(&mut cx_b, |workspace, cx| {
|
let confirm_rename = workspace_b.update(&mut cx_b, |workspace, cx| {
|
||||||
|
|
|
@ -19,7 +19,7 @@ extends = "_base"
|
||||||
0 = "#00000052"
|
0 = "#00000052"
|
||||||
|
|
||||||
[selection]
|
[selection]
|
||||||
host = { selection = "#3B57BC33", cursor = "$text.0.color" }
|
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||||
guests = [
|
guests = [
|
||||||
{ selection = "#FDF35133", cursor = "#FDF351" },
|
{ selection = "#FDF35133", cursor = "#FDF351" },
|
||||||
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
||||||
|
@ -39,8 +39,8 @@ bad = "#b7372e"
|
||||||
[state]
|
[state]
|
||||||
active_line = "#161313"
|
active_line = "#161313"
|
||||||
highlighted_line = "#faca5033"
|
highlighted_line = "#faca5033"
|
||||||
deleted_line = "#dd000022"
|
deleted_line = "#dd000036"
|
||||||
inserted_line = "#00dd0022"
|
inserted_line = "#00dd0036"
|
||||||
hover = "#00000033"
|
hover = "#00000033"
|
||||||
selected = "#00000088"
|
selected = "#00000088"
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ extends = "_base"
|
||||||
0 = "#00000052"
|
0 = "#00000052"
|
||||||
|
|
||||||
[selection]
|
[selection]
|
||||||
host = { selection = "#3B57BC33", cursor = "$text.0.color" }
|
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||||
guests = [
|
guests = [
|
||||||
{ selection = "#FDF35133", cursor = "#FDF351" },
|
{ selection = "#FDF35133", cursor = "#FDF351" },
|
||||||
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
||||||
|
@ -39,8 +39,8 @@ bad = "#b7372e"
|
||||||
[state]
|
[state]
|
||||||
active_line = "#00000022"
|
active_line = "#00000022"
|
||||||
highlighted_line = "#faca5033"
|
highlighted_line = "#faca5033"
|
||||||
deleted_line = "#dd000044"
|
deleted_line = "#dd000036"
|
||||||
inserted_line = "#00dd0044"
|
inserted_line = "#00dd0036"
|
||||||
hover = "#00000033"
|
hover = "#00000033"
|
||||||
selected = "#00000088"
|
selected = "#00000088"
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ extends = "_base"
|
||||||
0 = "#0000000D"
|
0 = "#0000000D"
|
||||||
|
|
||||||
[selection]
|
[selection]
|
||||||
host = { selection = "#3B57BC33", cursor = "$text.0.color" }
|
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||||
guests = [
|
guests = [
|
||||||
{ selection = "#D0453B33", cursor = "#D0453B" },
|
{ selection = "#D0453B33", cursor = "#D0453B" },
|
||||||
{ selection = "#3B874B33", cursor = "#3B874B" },
|
{ selection = "#3B874B33", cursor = "#3B874B" },
|
||||||
|
@ -39,8 +39,8 @@ bad = "#b7372e"
|
||||||
[state]
|
[state]
|
||||||
active_line = "#00000008"
|
active_line = "#00000008"
|
||||||
highlighted_line = "#faca5033"
|
highlighted_line = "#faca5033"
|
||||||
deleted_line = "#dd000044"
|
deleted_line = "#dd000036"
|
||||||
inserted_line = "#00dd0044"
|
inserted_line = "#00dd0036"
|
||||||
hover = "#0000000D"
|
hover = "#0000000D"
|
||||||
selected = "#0000001c"
|
selected = "#0000001c"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue