Restore scroll position and selections when cancelling go-to-line

Nathan Sobo created

But preserve the line when confirming.

Change summary

crates/editor/src/lib.rs     |  9 +++++++--
crates/go_to_line/src/lib.rs | 36 ++++++++++++++++++++++++++++++++----
2 files changed, 39 insertions(+), 6 deletions(-)

Detailed changes

crates/editor/src/lib.rs 🔗

@@ -534,7 +534,7 @@ impl Editor {
         cx.notify();
     }
 
-    fn set_scroll_position(&mut self, scroll_position: Vector2F, cx: &mut ViewContext<Self>) {
+    pub fn set_scroll_position(&mut self, scroll_position: Vector2F, cx: &mut ViewContext<Self>) {
         let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let scroll_top_buffer_offset =
             DisplayPoint::new(scroll_position.y() as u32, 0).to_offset(&map, Bias::Right);
@@ -555,6 +555,11 @@ impl Editor {
         cx.notify();
     }
 
+    pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> Vector2F {
+        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        compute_scroll_position(&display_map, self.scroll_position, &self.scroll_top_anchor)
+    }
+
     pub fn clamp_scroll_left(&mut self, max: f32) -> bool {
         if max < self.scroll_position.x() {
             self.scroll_position.set_x(max);
@@ -3029,7 +3034,7 @@ impl Editor {
             .unwrap()
     }
 
-    fn update_selections<T>(
+    pub fn update_selections<T>(
         &mut self,
         mut selections: Vec<Selection<T>>,
         autoscroll: Option<Autoscroll>,

crates/go_to_line/src/lib.rs 🔗

@@ -1,26 +1,35 @@
-use buffer::{Bias, Point};
+use buffer::{Bias, Point, Selection};
 use editor::{Autoscroll, Editor, EditorSettings};
 use gpui::{
-    action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View,
-    ViewContext, ViewHandle,
+    action, elements::*, geometry::vector::Vector2F, keymap::Binding, Entity, MutableAppContext,
+    RenderContext, View, ViewContext, ViewHandle,
 };
 use postage::watch;
 use workspace::{Settings, Workspace};
 
 action!(Toggle);
+action!(Confirm);
 
 pub fn init(cx: &mut MutableAppContext) {
     cx.add_bindings([
         Binding::new("ctrl-g", Toggle, Some("Editor")),
         Binding::new("escape", Toggle, Some("GoToLine")),
+        Binding::new("enter", Confirm, Some("GoToLine")),
     ]);
     cx.add_action(GoToLine::toggle);
+    cx.add_action(GoToLine::confirm);
 }
 
 pub struct GoToLine {
     settings: watch::Receiver<Settings>,
     line_editor: ViewHandle<Editor>,
     active_editor: ViewHandle<Editor>,
+    restore_state: Option<RestoreState>,
+}
+
+struct RestoreState {
+    scroll_position: Vector2F,
+    selections: Vec<Selection<usize>>,
 }
 
 pub enum Event {
@@ -50,10 +59,19 @@ impl GoToLine {
         });
         cx.subscribe(&line_editor, Self::on_line_editor_event)
             .detach();
+
+        let restore_state = active_editor.update(cx, |editor, cx| {
+            Some(RestoreState {
+                scroll_position: editor.scroll_position(cx),
+                selections: editor.selections::<usize>(cx).collect(),
+            })
+        });
+
         Self {
             settings: settings.clone(),
             line_editor,
             active_editor,
+            restore_state,
         }
     }
 
@@ -71,6 +89,11 @@ impl GoToLine {
         });
     }
 
+    fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
+        self.restore_state.take();
+        cx.emit(Event::Dismissed);
+    }
+
     fn on_event(
         workspace: &mut Workspace,
         _: ViewHandle<Self>,
@@ -119,8 +142,13 @@ impl Entity for GoToLine {
     type Event = Event;
 
     fn release(&mut self, cx: &mut MutableAppContext) {
-        self.active_editor.update(cx, |editor, _| {
+        let restore_state = self.restore_state.take();
+        self.active_editor.update(cx, |editor, cx| {
             editor.set_highlighted_row(None);
+            if let Some(restore_state) = restore_state {
+                editor.set_scroll_position(restore_state.scroll_position, cx);
+                editor.update_selections(restore_state.selections, None, cx);
+            }
         })
     }
 }