diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index cdcd1655e7..a14f37306a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -478,10 +478,10 @@ struct SnippetState { active_index: usize, } -struct RenameState { - range: Range, - old_name: String, - editor: ViewHandle, +pub struct RenameState { + pub range: Range, + pub old_name: String, + pub editor: ViewHandle, block_id: BlockId, } @@ -3163,23 +3163,7 @@ impl Editor { } pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { - 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.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::(); + 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::(); 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::( vec![Anchor::min()..Anchor::max()], settings.style.diff_background_inserted, @@ -4157,17 +4161,28 @@ impl Editor { editor }); this.highlight_ranges::( - 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::(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, - ) -> Option<(Range, u32, String, String)> { + fn take_rename(&mut self, cx: &mut ViewContext) -> Option { 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::(&buffer); self.remove_blocks([rename.block_id].into_iter().collect(), cx); self.clear_highlighted_ranges::(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::(&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::(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) { if let Some(active_diagnostics) = self.active_diagnostics.as_mut() { let buffer = self.buffer.read(cx).snapshot(cx); diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 35330cfc2f..c6a0ef2be6 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -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| { diff --git a/crates/zed/assets/themes/black.toml b/crates/zed/assets/themes/black.toml index 8bc60207ae..769076645f 100644 --- a/crates/zed/assets/themes/black.toml +++ b/crates/zed/assets/themes/black.toml @@ -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" diff --git a/crates/zed/assets/themes/dark.toml b/crates/zed/assets/themes/dark.toml index 678127e21f..ed6deed040 100644 --- a/crates/zed/assets/themes/dark.toml +++ b/crates/zed/assets/themes/dark.toml @@ -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" diff --git a/crates/zed/assets/themes/light.toml b/crates/zed/assets/themes/light.toml index 934dc59a6d..f51b3f4656 100644 --- a/crates/zed/assets/themes/light.toml +++ b/crates/zed/assets/themes/light.toml @@ -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"