WIP: Start on go to line

Antonio Scandurra created

Change summary

Cargo.lock                   |  12 +++
crates/editor/src/lib.rs     |   6 
crates/go_to_line/Cargo.toml |  11 ++
crates/go_to_line/src/lib.rs | 141 ++++++++++++++++++++++++++++++++++++++
crates/zed/Cargo.toml        |   1 
crates/zed/src/main.rs       |   1 
6 files changed, 169 insertions(+), 3 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2084,6 +2084,17 @@ dependencies = [
  "web-sys",
 ]
 
+[[package]]
+name = "go_to_line"
+version = "0.1.0"
+dependencies = [
+ "buffer",
+ "editor",
+ "gpui",
+ "postage",
+ "workspace",
+]
+
 [[package]]
 name = "gpui"
 version = "0.1.0"
@@ -5671,6 +5682,7 @@ dependencies = [
  "fsevent",
  "futures",
  "fuzzy",
+ "go_to_line",
  "gpui",
  "http-auth-basic",
  "ignore",

crates/editor/src/lib.rs 🔗

@@ -994,7 +994,7 @@ impl Editor {
         }
     }
 
-    fn select_ranges<I, T>(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext<Self>)
+    pub fn select_ranges<I, T>(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext<Self>)
     where
         I: IntoIterator<Item = Range<T>>,
         T: ToOffset,
@@ -1013,8 +1013,8 @@ impl Editor {
                 };
                 Selection {
                     id: post_inc(&mut self.next_selection_id),
-                    start: start,
-                    end: end,
+                    start,
+                    end,
                     reversed,
                     goal: SelectionGoal::None,
                 }

crates/go_to_line/Cargo.toml 🔗

@@ -0,0 +1,11 @@
+[package]
+name = "go_to_line"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+buffer = { path = "../buffer" }
+editor = { path = "../editor" }
+gpui = { path = "../gpui" }
+workspace = { path = "../workspace" }
+postage = { version = "0.4", features = ["futures-traits"] }

crates/go_to_line/src/lib.rs 🔗

@@ -0,0 +1,141 @@
+use buffer::{Bias, Point};
+use editor::{Editor, EditorSettings};
+use gpui::{
+    action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View,
+    ViewContext, ViewHandle,
+};
+use postage::watch;
+use workspace::{Settings, Workspace};
+
+action!(Toggle);
+
+pub fn init(cx: &mut MutableAppContext) {
+    cx.add_bindings([
+        Binding::new("ctrl-g", Toggle, Some("Editor")),
+        Binding::new("escape", Toggle, Some("GoToLine")),
+    ]);
+    cx.add_action(GoToLine::toggle);
+}
+
+pub struct GoToLine {
+    settings: watch::Receiver<Settings>,
+    line_editor: ViewHandle<Editor>,
+    active_editor: ViewHandle<Editor>,
+}
+
+pub enum Event {
+    Dismissed,
+}
+
+impl GoToLine {
+    pub fn new(
+        active_editor: ViewHandle<Editor>,
+        settings: watch::Receiver<Settings>,
+        cx: &mut ViewContext<Self>,
+    ) -> Self {
+        let line_editor = cx.add_view(|cx| {
+            Editor::single_line(
+                {
+                    let settings = settings.clone();
+                    move |_| {
+                        let settings = settings.borrow();
+                        EditorSettings {
+                            tab_size: settings.tab_size,
+                            style: settings.theme.editor.clone(),
+                        }
+                    }
+                },
+                cx,
+            )
+        });
+        cx.subscribe(&line_editor, Self::on_line_editor_event)
+            .detach();
+        Self {
+            settings: settings.clone(),
+            line_editor,
+            active_editor,
+        }
+    }
+
+    fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
+        workspace.toggle_modal(cx, |cx, workspace| {
+            let editor = workspace
+                .active_item(cx)
+                .unwrap()
+                .to_any()
+                .downcast::<Editor>()
+                .unwrap();
+            let view = cx.add_view(|cx| GoToLine::new(editor, workspace.settings.clone(), cx));
+            cx.subscribe(&view, Self::on_event).detach();
+            view
+        });
+    }
+
+    fn on_event(
+        workspace: &mut Workspace,
+        _: ViewHandle<Self>,
+        event: &Event,
+        cx: &mut ViewContext<Workspace>,
+    ) {
+        match event {
+            Event::Dismissed => workspace.dismiss_modal(cx),
+        }
+    }
+
+    fn on_line_editor_event(
+        &mut self,
+        _: ViewHandle<Editor>,
+        event: &editor::Event,
+        cx: &mut ViewContext<Self>,
+    ) {
+        match event {
+            editor::Event::Blurred => cx.emit(Event::Dismissed),
+            editor::Event::Edited => {
+                let line_editor = self.line_editor.read(cx).buffer().read(cx).text();
+                let mut components = line_editor.trim().split(':');
+                let row = components.next().and_then(|row| row.parse::<u32>().ok());
+                let column = components.next().and_then(|row| row.parse::<u32>().ok());
+                if let Some(point) = row.map(|row| Point::new(row, column.unwrap_or(0))) {
+                    self.active_editor.update(cx, |active_editor, cx| {
+                        let point = active_editor
+                            .buffer()
+                            .read(cx)
+                            .clip_point(point, Bias::Left);
+                        active_editor.select_ranges([point..point], true, cx);
+                    });
+                    cx.notify();
+                }
+            }
+            _ => {}
+        }
+    }
+}
+
+impl Entity for GoToLine {
+    type Event = Event;
+}
+
+impl View for GoToLine {
+    fn ui_name() -> &'static str {
+        "GoToLine"
+    }
+
+    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+        Align::new(
+            ConstrainedBox::new(
+                Container::new(ChildView::new(self.line_editor.id()).boxed()).boxed(),
+            )
+            .with_max_width(500.0)
+            .with_max_height(420.0)
+            .boxed(),
+        )
+        .top()
+        .named("go to line")
+    }
+
+    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+        cx.focus(&self.line_editor);
+    }
+
+    fn on_blur(&mut self, _: &mut ViewContext<Self>) {}
+}

crates/zed/Cargo.toml 🔗

@@ -36,6 +36,7 @@ fsevent = { path = "../fsevent" }
 fuzzy = { path = "../fuzzy" }
 editor = { path = "../editor" }
 file_finder = { path = "../file_finder" }
+go_to_line = { path = "../go_to_line" }
 gpui = { path = "../gpui" }
 language = { path = "../language" }
 lsp = { path = "../lsp" }

crates/zed/src/main.rs 🔗

@@ -38,6 +38,7 @@ fn main() {
         client::init(client.clone(), cx);
         workspace::init(cx);
         editor::init(cx, &mut entry_openers);
+        go_to_line::init(cx);
         file_finder::init(cx);
         people_panel::init(cx);
         chat_panel::init(cx);