From 428be43710da5edf5a455e5a4e0551ee5bc8e4b2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Nov 2023 18:50:02 +0100 Subject: [PATCH 1/7] Wire up rename editor --- crates/editor2/src/editor.rs | 342 +++++++++++++++++----------------- crates/editor2/src/element.rs | 13 +- 2 files changed, 182 insertions(+), 173 deletions(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index ebe78d95b3ea942e3cdcbcfb5a1b2dad5c09ed89..3a5b150520cc76842f6eafb87bc64ab2c674e28e 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -40,7 +40,7 @@ use fuzzy::{StringMatch, StringMatchCandidate}; use git::diff_hunk_to_display; use gpui::{ action, actions, div, point, px, relative, rems, size, uniform_list, AnyElement, AppContext, - AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context, + AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context, Entity, EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, StatefulInteractive, StatelessInteractive, Styled, Subscription, Task, TextStyle, @@ -100,7 +100,9 @@ use theme::{ use ui::{v_stack, HighlightedLabel, IconButton, StyledExt, TextTooltip}; use util::{post_inc, RangeExt, ResultExt, TryFutureExt}; use workspace::{ - item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, + item::{ItemEvent, ItemHandle}, + searchable::SearchEvent, + ItemNavHistory, SplitDirection, ViewId, Workspace, }; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); @@ -7690,183 +7692,183 @@ impl Editor { } } - // pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext) -> Option>> { - // use language::ToOffset as _; + pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext) -> Option>> { + use language::ToOffset as _; - // let project = self.project.clone()?; - // let selection = self.selections.newest_anchor().clone(); - // let (cursor_buffer, cursor_buffer_position) = self - // .buffer - // .read(cx) - // .text_anchor_for_position(selection.head(), cx)?; - // let (tail_buffer, _) = self - // .buffer - // .read(cx) - // .text_anchor_for_position(selection.tail(), cx)?; - // if tail_buffer != cursor_buffer { - // return None; - // } + let project = self.project.clone()?; + let selection = self.selections.newest_anchor().clone(); + let (cursor_buffer, cursor_buffer_position) = self + .buffer + .read(cx) + .text_anchor_for_position(selection.head(), cx)?; + let (tail_buffer, _) = 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 prepare_rename = project.update(cx, |project, cx| { - // project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx) - // }); + let snapshot = cursor_buffer.read(cx).snapshot(); + let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot); + let prepare_rename = project.update(cx, |project, cx| { + project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx) + }); - // Some(cx.spawn(|this, mut cx| async move { - // let rename_range = if let Some(range) = prepare_rename.await? { - // Some(range) - // } else { - // this.update(&mut cx, |this, cx| { - // let buffer = this.buffer.read(cx).snapshot(cx); - // let mut buffer_highlights = this - // .document_highlights_for_position(selection.head(), &buffer) - // .filter(|highlight| { - // highlight.start.excerpt_id == selection.head().excerpt_id - // && highlight.end.excerpt_id == selection.head().excerpt_id - // }); - // buffer_highlights - // .next() - // .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor) - // })? - // }; - // if let Some(rename_range) = rename_range { - // let rename_buffer_range = rename_range.to_offset(&snapshot); - // let cursor_offset_in_rename_range = - // cursor_buffer_offset.saturating_sub(rename_buffer_range.start); - - // this.update(&mut cx, |this, cx| { - // this.take_rename(false, cx); - // let buffer = this.buffer.read(cx).read(cx); - // 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 mut old_highlight_id = None; - // let old_name: Arc = buffer - // .chunks(rename_start..rename_end, true) - // .map(|chunk| { - // if old_highlight_id.is_none() { - // old_highlight_id = chunk.syntax_highlight_id; - // } - // chunk.text - // }) - // .collect::() - // .into(); - - // drop(buffer); - - // // Position the selection in the rename editor so that it matches the current selection. - // this.show_local_selections = false; - // let rename_editor = cx.build_view(|cx| { - // let mut editor = Editor::single_line(cx); - // if let Some(old_highlight_id) = old_highlight_id { - // editor.override_text_style = - // Some(Box::new(move |style| old_highlight_id.style(&style.syntax))); - // } - // editor.buffer.update(cx, |buffer, cx| { - // buffer.edit([(0..0, old_name.clone())], None, cx) - // }); - // editor.select_all(&SelectAll, cx); - // editor - // }); + Some(cx.spawn(|this, mut cx| async move { + let rename_range = if let Some(range) = prepare_rename.await? { + Some(range) + } else { + this.update(&mut cx, |this, cx| { + let buffer = this.buffer.read(cx).snapshot(cx); + let mut buffer_highlights = this + .document_highlights_for_position(selection.head(), &buffer) + .filter(|highlight| { + highlight.start.excerpt_id == selection.head().excerpt_id + && highlight.end.excerpt_id == selection.head().excerpt_id + }); + buffer_highlights + .next() + .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor) + })? + }; + if let Some(rename_range) = rename_range { + 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 ranges = this - // .clear_background_highlights::(cx) - // .into_iter() - // .flat_map(|(_, ranges)| ranges.into_iter()) - // .chain( - // this.clear_background_highlights::(cx) - // .into_iter() - // .flat_map(|(_, ranges)| ranges.into_iter()), - // ) - // .collect(); - - // this.highlight_text::( - // ranges, - // HighlightStyle { - // fade_out: Some(style.rename_fade), - // ..Default::default() - // }, - // cx, - // ); - // cx.focus(&rename_editor); - // let block_id = this.insert_blocks( - // [BlockProperties { - // style: BlockStyle::Flex, - // position: range.start.clone(), - // height: 1, - // render: Arc::new({ - // let editor = rename_editor.clone(); - // move |cx: &mut BlockContext| { - // ChildView::new(&editor, cx) - // .contained() - // .with_padding_left(cx.anchor_x) - // .into_any() - // } - // }), - // disposition: BlockDisposition::Below, - // }], - // Some(Autoscroll::fit()), - // cx, - // )[0]; - // this.pending_rename = Some(RenameState { - // range, - // old_name, - // editor: rename_editor, - // block_id, - // }); - // })?; - // } + this.update(&mut cx, |this, cx| { + this.take_rename(false, cx); + let buffer = this.buffer.read(cx).read(cx); + 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 mut old_highlight_id = None; + let old_name: Arc = buffer + .chunks(rename_start..rename_end, true) + .map(|chunk| { + if old_highlight_id.is_none() { + old_highlight_id = chunk.syntax_highlight_id; + } + chunk.text + }) + .collect::() + .into(); - // Ok(()) - // })) - // } + drop(buffer); - // pub fn confirm_rename( - // workspace: &mut Workspace, - // _: &ConfirmRename, - // cx: &mut ViewContext, - // ) -> Option>> { - // let editor = workspace.active_item(cx)?.act_as::(cx)?; - - // let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| { - // let rename = editor.take_rename(false, cx)?; - // let buffer = editor.buffer.read(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 { - // let new_name = rename.editor.read(cx).text(cx); - // Some((start_buffer, start..end, rename.old_name, new_name)) - // } else { - // None - // } - // })?; + // Position the selection in the rename editor so that it matches the current selection. + this.show_local_selections = false; + let rename_editor = cx.build_view(|cx| { + let mut editor = Editor::single_line(cx); + editor.buffer.update(cx, |buffer, cx| { + buffer.edit([(0..0, old_name.clone())], None, cx) + }); + editor.select_all(&SelectAll, cx); + editor + }); - // let rename = workspace.project().clone().update(cx, |project, cx| { - // project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx) - // }); + let ranges = this + .clear_background_highlights::(cx) + .into_iter() + .flat_map(|(_, ranges)| ranges.into_iter()) + .chain( + this.clear_background_highlights::(cx) + .into_iter() + .flat_map(|(_, ranges)| ranges.into_iter()), + ) + .collect(); - // let editor = editor.downgrade(); - // Some(cx.spawn(|workspace, mut cx| async move { - // let project_transaction = rename.await?; - // Self::open_project_transaction( - // &editor, - // workspace, - // project_transaction, - // format!("Rename: {} → {}", old_name, new_name), - // cx.clone(), - // ) - // .await?; + this.highlight_text::( + ranges, + HighlightStyle { + fade_out: Some(0.6), + ..Default::default() + }, + cx, + ); + let rename_focus_handle = rename_editor.focus_handle(cx); + cx.focus(&rename_focus_handle); + let block_id = this.insert_blocks( + [BlockProperties { + style: BlockStyle::Flex, + position: range.start.clone(), + height: 1, + render: Arc::new({ + let editor = rename_editor.clone(); + move |cx: &mut BlockContext| { + div().pl(cx.anchor_x).child(editor.clone()).render() + } + }), + disposition: BlockDisposition::Below, + }], + Some(Autoscroll::fit()), + cx, + )[0]; + this.pending_rename = Some(RenameState { + range, + old_name, + editor: rename_editor, + block_id, + }); + })?; + } - // editor.update(&mut cx, |editor, cx| { - // editor.refresh_document_highlights(cx); - // })?; - // Ok(()) - // })) - // } + Ok(()) + })) + } + + pub fn confirm_rename( + &mut self, + _: &ConfirmRename, + cx: &mut ViewContext, + ) -> Option>> { + let rename = self.take_rename(false, cx)?; + let workspace = self.workspace()?; + let (start_buffer, start) = self + .buffer + .read(cx) + .text_anchor_for_position(rename.range.start.clone(), cx)?; + let (end_buffer, end) = self + .buffer + .read(cx) + .text_anchor_for_position(rename.range.end.clone(), cx)?; + if start_buffer != end_buffer { + return None; + } + + let buffer = start_buffer; + let range = start..end; + let old_name = rename.old_name; + let new_name = rename.editor.read(cx).text(cx); + + let rename = workspace + .read(cx) + .project() + .clone() + .update(cx, |project, cx| { + project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx) + }); + let workspace = workspace.downgrade(); + + Some(cx.spawn(|editor, mut cx| async move { + let project_transaction = rename.await?; + Self::open_project_transaction( + &editor, + workspace, + project_transaction, + format!("Rename: {} → {}", old_name, new_name), + cx.clone(), + ) + .await?; + + editor.update(&mut cx, |editor, cx| { + editor.refresh_document_highlights(cx); + })?; + Ok(()) + })) + } fn take_rename( &mut self, diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 638ed3389191e364d0a382c285b0af456db3ee92..b8e7439ff16be1ed9723cc5ce2d57104554c8b88 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -2007,7 +2007,6 @@ impl EditorElement { anchor_x, gutter_padding, line_height, - // scroll_x, gutter_width, em_width, block_id, @@ -2569,8 +2568,16 @@ impl Element for EditorElement { .confirm_code_action(action, cx) .map(|task| task.detach_and_log_err(cx)); }); - // on_action(cx, Editor::rename); todo!() - // on_action(cx, Editor::confirm_rename); todo!() + register_action(cx, |editor, action, cx| { + editor + .rename(action, cx) + .map(|task| task.detach_and_log_err(cx)); + }); + register_action(cx, |editor, action, cx| { + editor + .confirm_rename(action, cx) + .map(|task| task.detach_and_log_err(cx)); + }); register_action(cx, |editor, action, cx| { editor .find_all_references(action, cx) From 48b3a90fbf0ca097b29939a9099f92f7094bef82 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Nov 2023 19:42:07 +0100 Subject: [PATCH 2/7] WIP --- crates/editor2/src/display_map/block_map.rs | 3 ++- crates/editor2/src/editor.rs | 30 +++++++++++++++++++-- crates/editor2/src/element.rs | 7 +++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/crates/editor2/src/display_map/block_map.rs b/crates/editor2/src/display_map/block_map.rs index 2f65903f080a27d936397be1815abd9d1e133da0..05106dd2a1f1416529689750f77b2e264f4d5e83 100644 --- a/crates/editor2/src/display_map/block_map.rs +++ b/crates/editor2/src/display_map/block_map.rs @@ -2,7 +2,7 @@ use super::{ wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot}, Highlights, }; -use crate::{Anchor, Editor, ExcerptId, ExcerptRange, ToPoint as _}; +use crate::{Anchor, Editor, EditorStyle, ExcerptId, ExcerptRange, ToPoint as _}; use collections::{Bound, HashMap, HashSet}; use gpui::{AnyElement, Pixels, ViewContext}; use language::{BufferSnapshot, Chunk, Patch, Point}; @@ -88,6 +88,7 @@ pub struct BlockContext<'a, 'b> { pub em_width: Pixels, pub line_height: Pixels, pub block_id: usize, + pub editor_style: &'b EditorStyle, } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 3a5b150520cc76842f6eafb87bc64ab2c674e28e..23dfc9b9d3ff3512ea6a231cbe4fe412ebca0f22 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -7796,9 +7796,35 @@ impl Editor { position: range.start.clone(), height: 1, render: Arc::new({ - let editor = rename_editor.clone(); + let rename_editor = rename_editor.clone(); move |cx: &mut BlockContext| { - div().pl(cx.anchor_x).child(editor.clone()).render() + let text_style = if let Some(highlight_style) = old_highlight_id + .and_then(|h| h.style(&cx.editor_style.syntax)) + { + cx.editor_style + .text + .clone() + .highlight(highlight_style) + .unwrap_or_else(|_| cx.editor_style.text.clone()) + } else { + cx.editor_style.text.clone() + }; + div().pl(cx.anchor_x).child(with_view( + &rename_editor, + |_, _| { + EditorElement::new(EditorStyle { + background: cx.theme().system().transparent, + local_player: cx.editor_style.local_player, + text: text_style, + scrollbar_width: cx.editor_style.scrollbar_width, + syntax: cx.editor_style.syntax.clone(), + diagnostic_style: cx + .editor_style + .diagnostic_style + .clone(), + }) + }, + )) } }), disposition: BlockDisposition::Below, diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index b8e7439ff16be1ed9723cc5ce2d57104554c8b88..5cdedd1de770d30047b48ca01792815ba997ba86 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -2010,6 +2010,7 @@ impl EditorElement { gutter_width, em_width, block_id, + editor_style: &self.style, }) } TransformBlock::ExcerptHeader { @@ -2658,6 +2659,12 @@ impl Element for EditorElement { } } +impl Component for EditorElement { + fn render(self) -> AnyElement { + AnyElement::new(self) + } +} + // impl EditorElement { // type LayoutState = LayoutState; // type PaintState = (); From 1def355d4467021abfcc87bef05f135ac2d1750b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Nov 2023 09:10:46 +0100 Subject: [PATCH 3/7] Don't return `Result` from `TextStyle::highlight` --- crates/editor2/src/display_map.rs | 7 +------ crates/editor2/src/editor.rs | 23 +++++++++-------------- crates/editor2/src/element.rs | 6 +----- crates/gpui2/src/style.rs | 4 ++-- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/crates/editor2/src/display_map.rs b/crates/editor2/src/display_map.rs index f808ffa7026f496faa0429b6fa7f8af1468e2bcc..d88daaccc1281de2b883fdb36896307d40f35b23 100644 --- a/crates/editor2/src/display_map.rs +++ b/crates/editor2/src/display_map.rs @@ -578,12 +578,7 @@ impl DisplaySnapshot { line.push_str(chunk.chunk); let text_style = if let Some(style) = chunk.style { - editor_style - .text - .clone() - .highlight(style) - .map(Cow::Owned) - .unwrap_or_else(|_| Cow::Borrowed(&editor_style.text)) + Cow::Owned(editor_style.text.clone().highlight(style)) } else { Cow::Borrowed(&editor_style.text) }; diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 23dfc9b9d3ff3512ea6a231cbe4fe412ebca0f22..b37c5e5756b8bdd760de001b50b88fd39b2a6d48 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -7798,20 +7798,15 @@ impl Editor { render: Arc::new({ let rename_editor = rename_editor.clone(); move |cx: &mut BlockContext| { - let text_style = if let Some(highlight_style) = old_highlight_id + let mut text_style = cx.editor_style.text.clone(); + if let Some(highlight_style) = old_highlight_id .and_then(|h| h.style(&cx.editor_style.syntax)) { - cx.editor_style - .text - .clone() - .highlight(highlight_style) - .unwrap_or_else(|_| cx.editor_style.text.clone()) - } else { - cx.editor_style.text.clone() - }; - div().pl(cx.anchor_x).child(with_view( - &rename_editor, - |_, _| { + text_style = text_style.highlight(highlight_style); + } + div() + .pl(cx.anchor_x) + .child(with_view(&rename_editor, |_, _| { EditorElement::new(EditorStyle { background: cx.theme().system().transparent, local_player: cx.editor_style.local_player, @@ -7823,8 +7818,8 @@ impl Editor { .diagnostic_style .clone(), }) - }, - )) + })) + .render() } }), disposition: BlockDisposition::Below, diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 5cdedd1de770d30047b48ca01792815ba997ba86..1ddc5ce7714886fbcd65304d4b21bdb0dd89baa6 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -2253,11 +2253,7 @@ impl LineWithInvisibles { if !line_chunk.is_empty() && !line_exceeded_max_len { let text_style = if let Some(style) = highlighted_chunk.style { - text_style - .clone() - .highlight(style) - .map(Cow::Owned) - .unwrap_or_else(|_| Cow::Borrowed(text_style)) + Cow::Owned(text_style.clone().highlight(style)) } else { Cow::Borrowed(text_style) }; diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 664cc61f8a1bf100678bc13d2cf796019380f9e5..0819ba9255e65a1645cb751fc8d2c99f4fe70824 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -157,7 +157,7 @@ impl Default for TextStyle { } impl TextStyle { - pub fn highlight(mut self, style: HighlightStyle) -> Result { + pub fn highlight(mut self, style: HighlightStyle) -> Self { if let Some(weight) = style.font_weight { self.font_weight = weight; } @@ -177,7 +177,7 @@ impl TextStyle { self.underline = Some(underline); } - Ok(self) + self } pub fn font(&self) -> Font { From c3094b7c3de560b6ee9f5e07b1792c910d43204d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Nov 2023 09:45:23 +0100 Subject: [PATCH 4/7] Introduce gpui::render_view --- crates/editor2/src/editor.rs | 13 +++--- crates/gpui2/src/style.rs | 4 +- crates/gpui2/src/view.rs | 82 +++++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 10 deletions(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index b37c5e5756b8bdd760de001b50b88fd39b2a6d48..e5c7b0e4a2109a6d10f4859405ef354528bce8b2 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -39,9 +39,9 @@ use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; use git::diff_hunk_to_display; use gpui::{ - action, actions, div, point, px, relative, rems, size, uniform_list, AnyElement, AppContext, - AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context, Entity, - EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla, + action, actions, div, point, px, relative, rems, render_view, size, uniform_list, AnyElement, + AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context, + Entity, EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, StatefulInteractive, StatelessInteractive, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WindowContext, @@ -7806,7 +7806,8 @@ impl Editor { } div() .pl(cx.anchor_x) - .child(with_view(&rename_editor, |_, _| { + .child(render_view( + &rename_editor, EditorElement::new(EditorStyle { background: cx.theme().system().transparent, local_player: cx.editor_style.local_player, @@ -7817,8 +7818,8 @@ impl Editor { .editor_style .diagnostic_style .clone(), - }) - })) + }), + )) .render() } }), diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 0819ba9255e65a1645cb751fc8d2c99f4fe70824..20972ca84655fcf1f8fe8d1d7137a4a22003787d 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -1,8 +1,8 @@ use crate::{ black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font, - FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Result, - Rgba, SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, WindowContext, + FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, + SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, WindowContext, }; use refineable::{Cascade, Refineable}; use smallvec::SmallVec; diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index d12d84f43b424f83c5785d7dd0b33c776054bbb3..38120a3e37919e8e6ddac33214f2098bdaa06602 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,7 +1,7 @@ use crate::{ private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, - Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, Model, Pixels, - Size, ViewContext, VisualContext, WeakModel, WindowContext, + BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, + Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; use std::{ @@ -281,6 +281,84 @@ where } } +pub struct RenderView { + view: View, + component: Option, +} + +impl Component for RenderView +where + C: 'static + Component, + ParentViewState: 'static, + ViewState: 'static, +{ + fn render(self) -> AnyElement { + AnyElement::new(self) + } +} + +impl Element for RenderView +where + C: 'static + Component, + ParentViewState: 'static, + ViewState: 'static, +{ + type ElementState = AnyElement; + + fn id(&self) -> Option { + Some(self.view.entity_id().into()) + } + + fn initialize( + &mut self, + _: &mut ParentViewState, + _: Option, + cx: &mut ViewContext, + ) -> Self::ElementState { + cx.with_element_id(self.view.entity_id(), |_, cx| { + self.view.update(cx, |view, cx| { + let mut element = self.component.take().unwrap().render(); + element.initialize(view, cx); + element + }) + }) + } + + fn layout( + &mut self, + _: &mut ParentViewState, + element: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + cx.with_element_id(self.view.entity_id(), |_, cx| { + self.view.update(cx, |view, cx| element.layout(view, cx)) + }) + } + + fn paint( + &mut self, + _: Bounds, + _: &mut ParentViewState, + element: &mut Self::ElementState, + cx: &mut ViewContext, + ) { + cx.with_element_id(self.view.entity_id(), |_, cx| { + self.view.update(cx, |view, cx| element.paint(view, cx)) + }) + } +} + +pub fn render_view(view: &View, component: C) -> RenderView +where + C: 'static + Component, + V: 'static, +{ + RenderView { + view: view.clone(), + component: Some(component), + } +} + mod any_view { use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext}; use std::any::Any; From 003e4bc241945c14d39ad7cf63093e887d9ac916 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Nov 2023 09:53:32 +0100 Subject: [PATCH 5/7] Extract out a register_actions function --- crates/editor2/src/element.rs | 344 +++++++++++++++++----------------- 1 file changed, 174 insertions(+), 170 deletions(-) diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 289834b50296d10f228e034f6391ace193f9bdde..d11408c0ce617330e46110786f883c41da89782f 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -2456,176 +2456,7 @@ impl Element for EditorElement { dispatch_context, Some(editor.focus_handle.clone()), |_, cx| { - register_action(cx, Editor::move_left); - register_action(cx, Editor::move_right); - register_action(cx, Editor::move_down); - register_action(cx, Editor::move_up); - // on_action(cx, Editor::new_file); todo!() - // on_action(cx, Editor::new_file_in_direction); todo!() - register_action(cx, Editor::cancel); - register_action(cx, Editor::newline); - register_action(cx, Editor::newline_above); - register_action(cx, Editor::newline_below); - register_action(cx, Editor::backspace); - register_action(cx, Editor::delete); - register_action(cx, Editor::tab); - register_action(cx, Editor::tab_prev); - register_action(cx, Editor::indent); - register_action(cx, Editor::outdent); - register_action(cx, Editor::delete_line); - register_action(cx, Editor::join_lines); - register_action(cx, Editor::sort_lines_case_sensitive); - register_action(cx, Editor::sort_lines_case_insensitive); - register_action(cx, Editor::reverse_lines); - register_action(cx, Editor::shuffle_lines); - register_action(cx, Editor::convert_to_upper_case); - register_action(cx, Editor::convert_to_lower_case); - register_action(cx, Editor::convert_to_title_case); - register_action(cx, Editor::convert_to_snake_case); - register_action(cx, Editor::convert_to_kebab_case); - register_action(cx, Editor::convert_to_upper_camel_case); - register_action(cx, Editor::convert_to_lower_camel_case); - register_action(cx, Editor::delete_to_previous_word_start); - register_action(cx, Editor::delete_to_previous_subword_start); - register_action(cx, Editor::delete_to_next_word_end); - register_action(cx, Editor::delete_to_next_subword_end); - register_action(cx, Editor::delete_to_beginning_of_line); - register_action(cx, Editor::delete_to_end_of_line); - register_action(cx, Editor::cut_to_end_of_line); - register_action(cx, Editor::duplicate_line); - register_action(cx, Editor::move_line_up); - register_action(cx, Editor::move_line_down); - register_action(cx, Editor::transpose); - register_action(cx, Editor::cut); - register_action(cx, Editor::copy); - register_action(cx, Editor::paste); - register_action(cx, Editor::undo); - register_action(cx, Editor::redo); - register_action(cx, Editor::move_page_up); - register_action(cx, Editor::move_page_down); - register_action(cx, Editor::next_screen); - register_action(cx, Editor::scroll_cursor_top); - register_action(cx, Editor::scroll_cursor_center); - register_action(cx, Editor::scroll_cursor_bottom); - register_action(cx, |editor, _: &LineDown, cx| { - editor.scroll_screen(&ScrollAmount::Line(1.), cx) - }); - register_action(cx, |editor, _: &LineUp, cx| { - editor.scroll_screen(&ScrollAmount::Line(-1.), cx) - }); - register_action(cx, |editor, _: &HalfPageDown, cx| { - editor.scroll_screen(&ScrollAmount::Page(0.5), cx) - }); - register_action(cx, |editor, _: &HalfPageUp, cx| { - editor.scroll_screen(&ScrollAmount::Page(-0.5), cx) - }); - register_action(cx, |editor, _: &PageDown, cx| { - editor.scroll_screen(&ScrollAmount::Page(1.), cx) - }); - register_action(cx, |editor, _: &PageUp, cx| { - editor.scroll_screen(&ScrollAmount::Page(-1.), cx) - }); - register_action(cx, Editor::move_to_previous_word_start); - register_action(cx, Editor::move_to_previous_subword_start); - register_action(cx, Editor::move_to_next_word_end); - register_action(cx, Editor::move_to_next_subword_end); - register_action(cx, Editor::move_to_beginning_of_line); - register_action(cx, Editor::move_to_end_of_line); - register_action(cx, Editor::move_to_start_of_paragraph); - register_action(cx, Editor::move_to_end_of_paragraph); - register_action(cx, Editor::move_to_beginning); - register_action(cx, Editor::move_to_end); - register_action(cx, Editor::select_up); - register_action(cx, Editor::select_down); - register_action(cx, Editor::select_left); - register_action(cx, Editor::select_right); - register_action(cx, Editor::select_to_previous_word_start); - register_action(cx, Editor::select_to_previous_subword_start); - register_action(cx, Editor::select_to_next_word_end); - register_action(cx, Editor::select_to_next_subword_end); - register_action(cx, Editor::select_to_beginning_of_line); - register_action(cx, Editor::select_to_end_of_line); - register_action(cx, Editor::select_to_start_of_paragraph); - register_action(cx, Editor::select_to_end_of_paragraph); - register_action(cx, Editor::select_to_beginning); - register_action(cx, Editor::select_to_end); - register_action(cx, Editor::select_all); - register_action(cx, |editor, action, cx| { - editor.select_all_matches(action, cx).log_err(); - }); - register_action(cx, Editor::select_line); - register_action(cx, Editor::split_selection_into_lines); - register_action(cx, Editor::add_selection_above); - register_action(cx, Editor::add_selection_below); - register_action(cx, |editor, action, cx| { - editor.select_next(action, cx).log_err(); - }); - register_action(cx, |editor, action, cx| { - editor.select_previous(action, cx).log_err(); - }); - register_action(cx, Editor::toggle_comments); - register_action(cx, Editor::select_larger_syntax_node); - register_action(cx, Editor::select_smaller_syntax_node); - register_action(cx, Editor::move_to_enclosing_bracket); - register_action(cx, Editor::undo_selection); - register_action(cx, Editor::redo_selection); - register_action(cx, Editor::go_to_diagnostic); - register_action(cx, Editor::go_to_prev_diagnostic); - register_action(cx, Editor::go_to_hunk); - register_action(cx, Editor::go_to_prev_hunk); - register_action(cx, Editor::go_to_definition); - register_action(cx, Editor::go_to_definition_split); - register_action(cx, Editor::go_to_type_definition); - register_action(cx, Editor::go_to_type_definition_split); - register_action(cx, Editor::fold); - register_action(cx, Editor::fold_at); - register_action(cx, Editor::unfold_lines); - register_action(cx, Editor::unfold_at); - register_action(cx, Editor::fold_selected_ranges); - register_action(cx, Editor::show_completions); - register_action(cx, Editor::toggle_code_actions); - // on_action(cx, Editor::open_excerpts); todo!() - register_action(cx, Editor::toggle_soft_wrap); - register_action(cx, Editor::toggle_inlay_hints); - register_action(cx, Editor::reveal_in_finder); - register_action(cx, Editor::copy_path); - register_action(cx, Editor::copy_relative_path); - register_action(cx, Editor::copy_highlight_json); - register_action(cx, |editor, action, cx| { - editor - .format(action, cx) - .map(|task| task.detach_and_log_err(cx)); - }); - register_action(cx, Editor::restart_language_server); - register_action(cx, Editor::show_character_palette); - // on_action(cx, Editor::confirm_completion); todo!() - register_action(cx, |editor, action, cx| { - editor - .confirm_code_action(action, cx) - .map(|task| task.detach_and_log_err(cx)); - }); - register_action(cx, |editor, action, cx| { - editor - .rename(action, cx) - .map(|task| task.detach_and_log_err(cx)); - }); - register_action(cx, |editor, action, cx| { - editor - .confirm_rename(action, cx) - .map(|task| task.detach_and_log_err(cx)); - }); - register_action(cx, |editor, action, cx| { - editor - .find_all_references(action, cx) - .map(|task| task.detach_and_log_err(cx)); - }); - register_action(cx, Editor::next_copilot_suggestion); - register_action(cx, Editor::previous_copilot_suggestion); - register_action(cx, Editor::copilot_suggest); - register_action(cx, Editor::context_menu_first); - register_action(cx, Editor::context_menu_prev); - register_action(cx, Editor::context_menu_next); - register_action(cx, Editor::context_menu_last); + register_actions(cx); // We call with_z_index to establish a new stacking context. cx.with_z_index(0, |cx| { @@ -4138,6 +3969,179 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: Pixels) -> f32 { // } // } +fn register_actions(cx: &mut ViewContext) { + register_action(cx, Editor::move_left); + register_action(cx, Editor::move_right); + register_action(cx, Editor::move_down); + register_action(cx, Editor::move_up); + // on_action(cx, Editor::new_file); todo!() + // on_action(cx, Editor::new_file_in_direction); todo!() + register_action(cx, Editor::cancel); + register_action(cx, Editor::newline); + register_action(cx, Editor::newline_above); + register_action(cx, Editor::newline_below); + register_action(cx, Editor::backspace); + register_action(cx, Editor::delete); + register_action(cx, Editor::tab); + register_action(cx, Editor::tab_prev); + register_action(cx, Editor::indent); + register_action(cx, Editor::outdent); + register_action(cx, Editor::delete_line); + register_action(cx, Editor::join_lines); + register_action(cx, Editor::sort_lines_case_sensitive); + register_action(cx, Editor::sort_lines_case_insensitive); + register_action(cx, Editor::reverse_lines); + register_action(cx, Editor::shuffle_lines); + register_action(cx, Editor::convert_to_upper_case); + register_action(cx, Editor::convert_to_lower_case); + register_action(cx, Editor::convert_to_title_case); + register_action(cx, Editor::convert_to_snake_case); + register_action(cx, Editor::convert_to_kebab_case); + register_action(cx, Editor::convert_to_upper_camel_case); + register_action(cx, Editor::convert_to_lower_camel_case); + register_action(cx, Editor::delete_to_previous_word_start); + register_action(cx, Editor::delete_to_previous_subword_start); + register_action(cx, Editor::delete_to_next_word_end); + register_action(cx, Editor::delete_to_next_subword_end); + register_action(cx, Editor::delete_to_beginning_of_line); + register_action(cx, Editor::delete_to_end_of_line); + register_action(cx, Editor::cut_to_end_of_line); + register_action(cx, Editor::duplicate_line); + register_action(cx, Editor::move_line_up); + register_action(cx, Editor::move_line_down); + register_action(cx, Editor::transpose); + register_action(cx, Editor::cut); + register_action(cx, Editor::copy); + register_action(cx, Editor::paste); + register_action(cx, Editor::undo); + register_action(cx, Editor::redo); + register_action(cx, Editor::move_page_up); + register_action(cx, Editor::move_page_down); + register_action(cx, Editor::next_screen); + register_action(cx, Editor::scroll_cursor_top); + register_action(cx, Editor::scroll_cursor_center); + register_action(cx, Editor::scroll_cursor_bottom); + register_action(cx, |editor, _: &LineDown, cx| { + editor.scroll_screen(&ScrollAmount::Line(1.), cx) + }); + register_action(cx, |editor, _: &LineUp, cx| { + editor.scroll_screen(&ScrollAmount::Line(-1.), cx) + }); + register_action(cx, |editor, _: &HalfPageDown, cx| { + editor.scroll_screen(&ScrollAmount::Page(0.5), cx) + }); + register_action(cx, |editor, _: &HalfPageUp, cx| { + editor.scroll_screen(&ScrollAmount::Page(-0.5), cx) + }); + register_action(cx, |editor, _: &PageDown, cx| { + editor.scroll_screen(&ScrollAmount::Page(1.), cx) + }); + register_action(cx, |editor, _: &PageUp, cx| { + editor.scroll_screen(&ScrollAmount::Page(-1.), cx) + }); + register_action(cx, Editor::move_to_previous_word_start); + register_action(cx, Editor::move_to_previous_subword_start); + register_action(cx, Editor::move_to_next_word_end); + register_action(cx, Editor::move_to_next_subword_end); + register_action(cx, Editor::move_to_beginning_of_line); + register_action(cx, Editor::move_to_end_of_line); + register_action(cx, Editor::move_to_start_of_paragraph); + register_action(cx, Editor::move_to_end_of_paragraph); + register_action(cx, Editor::move_to_beginning); + register_action(cx, Editor::move_to_end); + register_action(cx, Editor::select_up); + register_action(cx, Editor::select_down); + register_action(cx, Editor::select_left); + register_action(cx, Editor::select_right); + register_action(cx, Editor::select_to_previous_word_start); + register_action(cx, Editor::select_to_previous_subword_start); + register_action(cx, Editor::select_to_next_word_end); + register_action(cx, Editor::select_to_next_subword_end); + register_action(cx, Editor::select_to_beginning_of_line); + register_action(cx, Editor::select_to_end_of_line); + register_action(cx, Editor::select_to_start_of_paragraph); + register_action(cx, Editor::select_to_end_of_paragraph); + register_action(cx, Editor::select_to_beginning); + register_action(cx, Editor::select_to_end); + register_action(cx, Editor::select_all); + register_action(cx, |editor, action, cx| { + editor.select_all_matches(action, cx).log_err(); + }); + register_action(cx, Editor::select_line); + register_action(cx, Editor::split_selection_into_lines); + register_action(cx, Editor::add_selection_above); + register_action(cx, Editor::add_selection_below); + register_action(cx, |editor, action, cx| { + editor.select_next(action, cx).log_err(); + }); + register_action(cx, |editor, action, cx| { + editor.select_previous(action, cx).log_err(); + }); + register_action(cx, Editor::toggle_comments); + register_action(cx, Editor::select_larger_syntax_node); + register_action(cx, Editor::select_smaller_syntax_node); + register_action(cx, Editor::move_to_enclosing_bracket); + register_action(cx, Editor::undo_selection); + register_action(cx, Editor::redo_selection); + register_action(cx, Editor::go_to_diagnostic); + register_action(cx, Editor::go_to_prev_diagnostic); + register_action(cx, Editor::go_to_hunk); + register_action(cx, Editor::go_to_prev_hunk); + register_action(cx, Editor::go_to_definition); + register_action(cx, Editor::go_to_definition_split); + register_action(cx, Editor::go_to_type_definition); + register_action(cx, Editor::go_to_type_definition_split); + register_action(cx, Editor::fold); + register_action(cx, Editor::fold_at); + register_action(cx, Editor::unfold_lines); + register_action(cx, Editor::unfold_at); + register_action(cx, Editor::fold_selected_ranges); + register_action(cx, Editor::show_completions); + register_action(cx, Editor::toggle_code_actions); + // on_action(cx, Editor::open_excerpts); todo!() + register_action(cx, Editor::toggle_soft_wrap); + register_action(cx, Editor::toggle_inlay_hints); + register_action(cx, Editor::reveal_in_finder); + register_action(cx, Editor::copy_path); + register_action(cx, Editor::copy_relative_path); + register_action(cx, Editor::copy_highlight_json); + register_action(cx, |editor, action, cx| { + editor + .format(action, cx) + .map(|task| task.detach_and_log_err(cx)); + }); + register_action(cx, Editor::restart_language_server); + register_action(cx, Editor::show_character_palette); + // on_action(cx, Editor::confirm_completion); todo!() + register_action(cx, |editor, action, cx| { + editor + .confirm_code_action(action, cx) + .map(|task| task.detach_and_log_err(cx)); + }); + register_action(cx, |editor, action, cx| { + editor + .rename(action, cx) + .map(|task| task.detach_and_log_err(cx)); + }); + register_action(cx, |editor, action, cx| { + editor + .confirm_rename(action, cx) + .map(|task| task.detach_and_log_err(cx)); + }); + register_action(cx, |editor, action, cx| { + editor + .find_all_references(action, cx) + .map(|task| task.detach_and_log_err(cx)); + }); + register_action(cx, Editor::next_copilot_suggestion); + register_action(cx, Editor::previous_copilot_suggestion); + register_action(cx, Editor::copilot_suggest); + register_action(cx, Editor::context_menu_first); + register_action(cx, Editor::context_menu_prev); + register_action(cx, Editor::context_menu_next); + register_action(cx, Editor::context_menu_last); +} + fn register_action( cx: &mut ViewContext, listener: impl Fn(&mut Editor, &T, &mut ViewContext) + 'static, From 45381e566c1497d929c1237285c730cc8ff4847a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Nov 2023 11:05:09 +0100 Subject: [PATCH 6/7] Fix focus management on editor when renaming --- crates/editor2/src/editor.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 7edf8edc8c8e36e3c7f0e10f115561590dc02bda..e3d94409338269e663b4448509994b7f4ec8acc1 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -1880,10 +1880,8 @@ impl Editor { ); let focus_handle = cx.focus_handle(); - cx.on_focus_in(&focus_handle, Self::handle_focus_in) - .detach(); - cx.on_focus_out(&focus_handle, Self::handle_focus_out) - .detach(); + cx.on_focus(&focus_handle, Self::handle_focus).detach(); + cx.on_blur(&focus_handle, Self::handle_blur).detach(); let mut this = Self { handle: cx.view().downgrade(), @@ -7903,6 +7901,10 @@ impl Editor { cx: &mut ViewContext, ) -> Option { let rename = self.pending_rename.take()?; + if rename.editor.focus_handle(cx).is_focused(cx) { + cx.focus(&self.focus_handle); + } + self.remove_blocks( [rename.block_id].into_iter().collect(), Some(Autoscroll::fit()), @@ -9201,17 +9203,13 @@ impl Editor { self.focus_handle.is_focused(cx) } - fn handle_focus_in(&mut self, cx: &mut ViewContext) { - if self.focus_handle.is_focused(cx) { - // todo!() - // let focused_event = EditorFocused(cx.handle()); - // cx.emit_global(focused_event); - cx.emit(Event::Focused); - } + fn handle_focus(&mut self, cx: &mut ViewContext) { + cx.emit(Event::Focused); + if let Some(rename) = self.pending_rename.as_ref() { let rename_editor_focus_handle = rename.editor.read(cx).focus_handle.clone(); cx.focus(&rename_editor_focus_handle); - } else if self.focus_handle.is_focused(cx) { + } else { self.blink_manager.update(cx, BlinkManager::enable); self.buffer.update(cx, |buffer, cx| { buffer.finalize_last_transaction(cx); @@ -9227,7 +9225,7 @@ impl Editor { } } - fn handle_focus_out(&mut self, cx: &mut ViewContext) { + fn handle_blur(&mut self, cx: &mut ViewContext) { // todo!() // let blurred_event = EditorBlurred(cx.handle()); // cx.emit_global(blurred_event); From 786cc59d7a1a918cc97f283637a5f9fe789587ed Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Nov 2023 11:07:32 +0100 Subject: [PATCH 7/7] Fix formatting --- crates/gpui2/src/style.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 35b08b84c2c6b80eb4bfc92d756a90ab5db6e3a9..5d9dd5d804376e8f4840c2c4a56f1d1ef35274df 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -1,8 +1,8 @@ use crate::{ black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font, - FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, - Rgba, SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, + FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, + SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, }; use refineable::{Cascade, Refineable}; use smallvec::SmallVec;