mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-09 21:26:14 +03:00
Tweak behavior of selections when renaming
This commit is contained in:
parent
f0a6e8cb9c
commit
80bca57bfa
@ -478,10 +478,10 @@ struct SnippetState {
|
||||
active_index: usize,
|
||||
}
|
||||
|
||||
struct RenameState {
|
||||
range: Range<Anchor>,
|
||||
old_name: String,
|
||||
editor: ViewHandle<Editor>,
|
||||
pub struct RenameState {
|
||||
pub range: Range<Anchor>,
|
||||
pub old_name: String,
|
||||
pub editor: ViewHandle<Editor>,
|
||||
block_id: BlockId,
|
||||
}
|
||||
|
||||
@ -3163,23 +3163,7 @@ impl Editor {
|
||||
}
|
||||
|
||||
pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
|
||||
if let Some((range, column, _, _)) = self.take_rename(cx) {
|
||||
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,
|
||||
);
|
||||
if self.take_rename(cx).is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3227,6 +3211,8 @@ impl Editor {
|
||||
}
|
||||
|
||||
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 context_menu.select_next(cx) {
|
||||
return;
|
||||
@ -4116,39 +4102,57 @@ impl Editor {
|
||||
use language::ToOffset as _;
|
||||
|
||||
let project = self.project.clone()?;
|
||||
let position = self.newest_anchor_selection().head();
|
||||
let (buffer, buffer_position) = self
|
||||
let selection = self.newest_anchor_selection().clone();
|
||||
let (cursor_buffer, cursor_buffer_position) = self
|
||||
.buffer
|
||||
.read(cx)
|
||||
.text_anchor_for_position(position.clone(), cx)?;
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
.text_anchor_for_position(selection.head(), cx)?;
|
||||
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| {
|
||||
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 {
|
||||
if let Some(range) = prepare_rename.await? {
|
||||
let buffer_offset_range = range.to_offset(&snapshot);
|
||||
let buffer_offset = buffer_position.to_offset(&snapshot);
|
||||
let lookbehind = buffer_offset.saturating_sub(buffer_offset_range.start);
|
||||
let lookahead = buffer_offset_range.end.saturating_sub(buffer_offset);
|
||||
if let Some(rename_range) = prepare_rename.await? {
|
||||
let rename_buffer_range = rename_range.to_offset(&snapshot);
|
||||
let cursor_offset_in_rename_range =
|
||||
cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
|
||||
let tail_offset_in_rename_range =
|
||||
tail_buffer_offset.saturating_sub(rename_buffer_range.start);
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
let settings = (this.build_settings)(cx);
|
||||
let buffer = this.buffer.read(cx).read(cx);
|
||||
let offset = position.to_offset(&buffer);
|
||||
let start = offset - lookbehind;
|
||||
let end = offset + lookahead;
|
||||
let rename_range = buffer.anchor_before(start)..buffer.anchor_after(end);
|
||||
let old_name = buffer.text_for_range(start..end).collect::<String>();
|
||||
let cursor_offset = selection.head().to_offset(&buffer);
|
||||
let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
|
||||
let rename_end = rename_start + rename_buffer_range.len();
|
||||
let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
|
||||
let old_name = buffer
|
||||
.text_for_range(rename_start..rename_end)
|
||||
.collect::<String>();
|
||||
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);
|
||||
editor
|
||||
.buffer
|
||||
.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>(
|
||||
vec![Anchor::min()..Anchor::max()],
|
||||
settings.style.diff_background_inserted,
|
||||
@ -4157,17 +4161,28 @@ impl Editor {
|
||||
editor
|
||||
});
|
||||
this.highlight_ranges::<Rename>(
|
||||
vec![rename_range.clone()],
|
||||
vec![range.clone()],
|
||||
settings.style.diff_background_deleted,
|
||||
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(
|
||||
[BlockProperties {
|
||||
position: rename_range.start.clone(),
|
||||
position: range.start.clone(),
|
||||
height: 1,
|
||||
render: Arc::new({
|
||||
let editor = editor.clone();
|
||||
let editor = rename_editor.clone();
|
||||
move |cx: &BlockContext| {
|
||||
ChildView::new(editor.clone())
|
||||
.contained()
|
||||
@ -4180,9 +4195,9 @@ impl Editor {
|
||||
cx,
|
||||
)[0];
|
||||
this.pending_rename = Some(RenameState {
|
||||
range: rename_range,
|
||||
range,
|
||||
old_name,
|
||||
editor,
|
||||
editor: rename_editor,
|
||||
block_id,
|
||||
});
|
||||
});
|
||||
@ -4200,12 +4215,15 @@ impl Editor {
|
||||
let editor = workspace.active_item(cx)?.act_as::<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 (start_buffer, start) = buffer.text_anchor_for_position(range.start.clone(), cx)?;
|
||||
let (end_buffer, end) = buffer.text_anchor_for_position(range.end.clone(), cx)?;
|
||||
let (start_buffer, start) =
|
||||
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 {
|
||||
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 {
|
||||
None
|
||||
}
|
||||
@ -4234,23 +4252,38 @@ impl Editor {
|
||||
}))
|
||||
}
|
||||
|
||||
fn take_rename(
|
||||
&mut self,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<(Range<Anchor>, u32, String, String)> {
|
||||
fn take_rename(&mut self, cx: &mut ViewContext<Self>) -> Option<RenameState> {
|
||||
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.clear_highlighted_ranges::<Rename>(cx);
|
||||
Some((
|
||||
rename.range,
|
||||
rename_position.head().column,
|
||||
rename.old_name,
|
||||
new_name,
|
||||
))
|
||||
|
||||
let editor = rename.editor.read(cx);
|
||||
let buffer = editor.buffer.read(cx).snapshot(cx);
|
||||
let selection = editor.newest_selection::<usize>(&buffer);
|
||||
|
||||
// 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(
|
||||
@ -4266,11 +4299,17 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.take_rename(cx);
|
||||
let rename = self.pending_rename.take().unwrap();
|
||||
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>) {
|
||||
if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
|
||||
let buffer = self.buffer.read(cx).snapshot(cx);
|
||||
|
@ -1153,7 +1153,7 @@ mod tests {
|
||||
},
|
||||
editor::{
|
||||
self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, EditorSettings,
|
||||
Input, MultiBuffer, Redo, Rename, ToggleCodeActions, Undo,
|
||||
Input, MultiBuffer, Redo, Rename, ToOffset, ToggleCodeActions, Undo,
|
||||
},
|
||||
fs::{FakeFs, Fs as _},
|
||||
language::{
|
||||
@ -3140,12 +3140,17 @@ mod tests {
|
||||
.unwrap();
|
||||
prepare_rename.await.unwrap();
|
||||
editor_b.update(&mut cx_b, |editor, cx| {
|
||||
assert_eq!(editor.selected_ranges(cx), [6..9]);
|
||||
editor.handle_input(&Input("T".to_string()), cx);
|
||||
editor.handle_input(&Input("H".to_string()), cx);
|
||||
editor.handle_input(&Input("R".to_string()), cx);
|
||||
editor.handle_input(&Input("E".to_string()), cx);
|
||||
editor.handle_input(&Input("E".to_string()), cx);
|
||||
let rename = editor.pending_rename().unwrap();
|
||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||
assert_eq!(
|
||||
rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),
|
||||
6..9
|
||||
);
|
||||
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| {
|
||||
|
@ -19,7 +19,7 @@ extends = "_base"
|
||||
0 = "#00000052"
|
||||
|
||||
[selection]
|
||||
host = { selection = "#3B57BC33", cursor = "$text.0.color" }
|
||||
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||
guests = [
|
||||
{ selection = "#FDF35133", cursor = "#FDF351" },
|
||||
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
||||
@ -39,8 +39,8 @@ bad = "#b7372e"
|
||||
[state]
|
||||
active_line = "#161313"
|
||||
highlighted_line = "#faca5033"
|
||||
deleted_line = "#dd000022"
|
||||
inserted_line = "#00dd0022"
|
||||
deleted_line = "#dd000036"
|
||||
inserted_line = "#00dd0036"
|
||||
hover = "#00000033"
|
||||
selected = "#00000088"
|
||||
|
||||
|
@ -19,7 +19,7 @@ extends = "_base"
|
||||
0 = "#00000052"
|
||||
|
||||
[selection]
|
||||
host = { selection = "#3B57BC33", cursor = "$text.0.color" }
|
||||
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||
guests = [
|
||||
{ selection = "#FDF35133", cursor = "#FDF351" },
|
||||
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
||||
@ -39,8 +39,8 @@ bad = "#b7372e"
|
||||
[state]
|
||||
active_line = "#00000022"
|
||||
highlighted_line = "#faca5033"
|
||||
deleted_line = "#dd000044"
|
||||
inserted_line = "#00dd0044"
|
||||
deleted_line = "#dd000036"
|
||||
inserted_line = "#00dd0036"
|
||||
hover = "#00000033"
|
||||
selected = "#00000088"
|
||||
|
||||
|
@ -19,7 +19,7 @@ extends = "_base"
|
||||
0 = "#0000000D"
|
||||
|
||||
[selection]
|
||||
host = { selection = "#3B57BC33", cursor = "$text.0.color" }
|
||||
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||
guests = [
|
||||
{ selection = "#D0453B33", cursor = "#D0453B" },
|
||||
{ selection = "#3B874B33", cursor = "#3B874B" },
|
||||
@ -39,8 +39,8 @@ bad = "#b7372e"
|
||||
[state]
|
||||
active_line = "#00000008"
|
||||
highlighted_line = "#faca5033"
|
||||
deleted_line = "#dd000044"
|
||||
inserted_line = "#00dd0044"
|
||||
deleted_line = "#dd000036"
|
||||
inserted_line = "#00dd0036"
|
||||
hover = "#0000000D"
|
||||
selected = "#0000001c"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user