diff --git a/Cargo.lock b/Cargo.lock index c500ab6d9d..79c577aad8 100644 --- a/Cargo.lock +++ b/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", diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 0eefe2e6b1..400abb3abc 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -994,7 +994,7 @@ impl Editor { } } - fn select_ranges(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext) + pub fn select_ranges(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext) where I: IntoIterator>, 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, } diff --git a/crates/go_to_line/Cargo.toml b/crates/go_to_line/Cargo.toml new file mode 100644 index 0000000000..c1cf2863df --- /dev/null +++ b/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"] } diff --git a/crates/go_to_line/src/lib.rs b/crates/go_to_line/src/lib.rs new file mode 100644 index 0000000000..2180b214d4 --- /dev/null +++ b/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, + line_editor: ViewHandle, + active_editor: ViewHandle, +} + +pub enum Event { + Dismissed, +} + +impl GoToLine { + pub fn new( + active_editor: ViewHandle, + settings: watch::Receiver, + cx: &mut ViewContext, + ) -> 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.toggle_modal(cx, |cx, workspace| { + let editor = workspace + .active_item(cx) + .unwrap() + .to_any() + .downcast::() + .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, + event: &Event, + cx: &mut ViewContext, + ) { + match event { + Event::Dismissed => workspace.dismiss_modal(cx), + } + } + + fn on_line_editor_event( + &mut self, + _: ViewHandle, + event: &editor::Event, + cx: &mut ViewContext, + ) { + 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::().ok()); + let column = components.next().and_then(|row| row.parse::().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) -> 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) { + cx.focus(&self.line_editor); + } + + fn on_blur(&mut self, _: &mut ViewContext) {} +} diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index a2ae271d5b..8e4441b594 100644 --- a/crates/zed/Cargo.toml +++ b/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" } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 23ad33d8bd..b28066717c 100644 --- a/crates/zed/src/main.rs +++ b/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);