From cea8107242ae8abeb38b67e2ffa16392fb5ce070 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 24 Nov 2021 18:45:36 +0100 Subject: [PATCH 1/7] WIP: Start on go to line --- 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(-) create mode 100644 crates/go_to_line/Cargo.toml create mode 100644 crates/go_to_line/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c500ab6d9d6d48fb0421cc3a3bc66bb6871b1c8a..79c577aad84edf52c24b22900b8d16710e12dd1e 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 0eefe2e6b17d6bf5ccaedbed374be9c89e68a100..400abb3abcf425933b6412e82aa77bf6153afea3 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 0000000000000000000000000000000000000000..c1cf2863dfc665c9e77a7d9d332e017ad5780c33 --- /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 0000000000000000000000000000000000000000..2180b214d4d1f53a097ce9c951f980f79e0a6fee --- /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 a2ae271d5b1c3cba1d753a94fa4995e66f489d6b..8e4441b594d150122a07f573c3f1fb016694a794 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 23ad33d8bd28702d55d4e6a17a08af02b61796e5..b28066717cecdfe51e65682f39a94700081cb14b 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); From 53a7da9d3fe02e789746bbf42711bdbfc6b7f7f7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 24 Nov 2021 19:50:47 +0100 Subject: [PATCH 2/7] Allow centering selections when requesting autoscroll We use this new capability in the "go to line" modal. --- crates/editor/src/lib.rs | 195 ++++++++++++++++++++--------------- crates/go_to_line/src/lib.rs | 10 +- 2 files changed, 113 insertions(+), 92 deletions(-) diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 400abb3abcf425933b6412e82aa77bf6153afea3..1dee47ca826192dfc16ac05b88d566fab5737e2a 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -311,6 +311,11 @@ enum SelectMode { All, } +pub enum Autoscroll { + Closest, + Center, +} + #[derive(Copy, Clone, PartialEq, Eq)] pub enum EditorMode { SingleLine, @@ -338,7 +343,7 @@ pub struct Editor { active_diagnostics: Option, scroll_position: Vector2F, scroll_top_anchor: Anchor, - autoscroll_requested: bool, + autoscroll_request: Option, build_settings: Rc EditorSettings>>, focused: bool, show_local_cursors: bool, @@ -473,7 +478,7 @@ impl Editor { build_settings, scroll_position: Vector2F::zero(), scroll_top_anchor: Anchor::min(), - autoscroll_requested: false, + autoscroll_request: None, focused: false, show_local_cursors: false, blink_epoch: 0, @@ -577,11 +582,11 @@ impl Editor { self.set_scroll_position(scroll_position, cx); } - if self.autoscroll_requested { - self.autoscroll_requested = false; + let autoscroll = if let Some(autoscroll) = self.autoscroll_request.take() { + autoscroll } else { return false; - } + }; let mut selections = self.selections::(cx).peekable(); let first_cursor_top = selections @@ -597,29 +602,35 @@ impl Editor { .to_display_point(&display_map) .row() as f32 + 1.0; - let margin = if matches!(self.mode, EditorMode::AutoHeight { .. }) { 0. } else { - ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0) - .floor() - .min(3.0) + ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0).floor() }; if margin < 0.0 { return false; } - let target_top = (first_cursor_top - margin).max(0.0); - let target_bottom = last_cursor_bottom + margin; - let start_row = scroll_position.y(); - let end_row = start_row + visible_lines; - - if target_top < start_row { - scroll_position.set_y(target_top); - self.set_scroll_position(scroll_position, cx); - } else if target_bottom >= end_row { - scroll_position.set_y(target_bottom - visible_lines); - self.set_scroll_position(scroll_position, cx); + match autoscroll { + Autoscroll::Closest => { + let margin = margin.min(3.0); + let target_top = (first_cursor_top - margin).max(0.0); + let target_bottom = last_cursor_bottom + margin; + let start_row = scroll_position.y(); + let end_row = start_row + visible_lines; + + if target_top < start_row { + scroll_position.set_y(target_top); + self.set_scroll_position(scroll_position, cx); + } else if target_bottom >= end_row { + scroll_position.set_y(target_bottom - visible_lines); + self.set_scroll_position(scroll_position, cx); + } + } + Autoscroll::Center => { + scroll_position.set_y((first_cursor_top - margin).max(0.0)); + self.set_scroll_position(scroll_position, cx); + } } true @@ -782,7 +793,7 @@ impl Editor { }; if !add { - self.update_selections::(Vec::new(), false, cx); + self.update_selections::(Vec::new(), None, cx); } else if click_count > 1 { // Remove the newest selection since it was only added as part of this multi-click. let newest_selection = self.newest_selection::(cx); @@ -790,7 +801,7 @@ impl Editor { self.selections(cx) .filter(|selection| selection.id != newest_selection.id) .collect(), - false, + None, cx, ) } @@ -921,7 +932,7 @@ impl Editor { self.columnar_selection_tail.take(); if self.pending_selection.is_some() { let selections = self.selections::(cx).collect::>(); - self.update_selections(selections, false, cx); + self.update_selections(selections, None, cx); } } @@ -961,7 +972,7 @@ impl Editor { }) .collect::>(); - self.update_selections(selections, false, cx); + self.update_selections(selections, None, cx); cx.notify(); } @@ -982,7 +993,7 @@ impl Editor { goal: selection.goal, }; if self.selections::(cx).next().is_none() { - self.update_selections(vec![selection], true, cx); + self.update_selections(vec![selection], Some(Autoscroll::Closest), cx); } } else { let mut oldest_selection = self.oldest_selection::(cx); @@ -990,12 +1001,16 @@ impl Editor { oldest_selection.start = oldest_selection.head().clone(); oldest_selection.end = oldest_selection.head().clone(); } - self.update_selections(vec![oldest_selection], true, cx); + self.update_selections(vec![oldest_selection], Some(Autoscroll::Closest), cx); } } - pub fn select_ranges(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext) - where + pub fn select_ranges( + &mut self, + ranges: I, + autoscroll: Option, + cx: &mut ViewContext, + ) where I: IntoIterator>, T: ToOffset, { @@ -1053,7 +1068,7 @@ impl Editor { } }) .collect(); - self.update_selections(selections, false, cx); + self.update_selections(selections, None, cx); Ok(()) } @@ -1179,7 +1194,7 @@ impl Editor { )) }); - self.update_selections(new_selections, true, cx); + self.update_selections(new_selections, Some(Autoscroll::Closest), cx); self.end_transaction(cx); #[derive(Default)] @@ -1219,7 +1234,7 @@ impl Editor { .collect(); }); - self.update_selections(new_selections, true, cx); + self.update_selections(new_selections, Some(Autoscroll::Closest), cx); self.end_transaction(cx); } @@ -1319,7 +1334,7 @@ impl Editor { }) .collect(); self.autoclose_stack.pop(); - self.update_selections(new_selections, true, cx); + self.update_selections(new_selections, Some(Autoscroll::Closest), cx); true } else { false @@ -1347,7 +1362,7 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); self.insert("", cx); self.end_transaction(cx); } @@ -1366,7 +1381,7 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); self.insert(&"", cx); self.end_transaction(cx); } @@ -1437,7 +1452,7 @@ impl Editor { } }); - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); self.end_transaction(cx); } @@ -1481,7 +1496,11 @@ impl Editor { buffer.edit(deletion_ranges, "", cx); }); - self.update_selections(self.selections::(cx).collect(), true, cx); + self.update_selections( + self.selections::(cx).collect(), + Some(Autoscroll::Closest), + cx, + ); self.end_transaction(cx); } @@ -1550,7 +1569,7 @@ impl Editor { .collect(); self.buffer .update(cx, |buffer, cx| buffer.edit(edit_ranges, "", cx)); - self.update_selections(new_selections, true, cx); + self.update_selections(new_selections, Some(Autoscroll::Closest), cx); self.end_transaction(cx); } @@ -1608,7 +1627,7 @@ impl Editor { } }); - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); self.end_transaction(cx); } @@ -1697,7 +1716,7 @@ impl Editor { } }); self.fold_ranges(new_folds, cx); - self.select_ranges(new_selection_ranges, true, cx); + self.select_ranges(new_selection_ranges, Some(Autoscroll::Closest), cx); self.end_transaction(cx); } @@ -1784,7 +1803,7 @@ impl Editor { } }); self.fold_ranges(new_folds, cx); - self.select_ranges(new_selection_ranges, true, cx); + self.select_ranges(new_selection_ranges, Some(Autoscroll::Closest), cx); self.end_transaction(cx); } @@ -1814,7 +1833,7 @@ impl Editor { }); } } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); self.insert("", cx); self.end_transaction(cx); @@ -1899,7 +1918,7 @@ impl Editor { selection.end = selection.start; }); } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } else { self.insert(clipboard_text, cx); } @@ -1908,12 +1927,12 @@ impl Editor { pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext) { self.buffer.update(cx, |buffer, cx| buffer.undo(cx)); - self.request_autoscroll(cx); + self.request_autoscroll(Autoscroll::Closest, cx); } pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext) { self.buffer.update(cx, |buffer, cx| buffer.redo(cx)); - self.request_autoscroll(cx); + self.request_autoscroll(Autoscroll::Closest, cx); } pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { @@ -1935,7 +1954,7 @@ impl Editor { selection.reversed = false; selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext) { @@ -1949,7 +1968,7 @@ impl Editor { selection.set_head(cursor); selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext) { @@ -1971,7 +1990,7 @@ impl Editor { selection.reversed = false; selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext) { @@ -1985,7 +2004,7 @@ impl Editor { selection.set_head(cursor); selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { @@ -2010,7 +2029,7 @@ impl Editor { selection.goal = goal; selection.reversed = false; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext) { @@ -2023,7 +2042,7 @@ impl Editor { selection.set_head(cursor); selection.goal = goal; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { @@ -2048,7 +2067,7 @@ impl Editor { selection.goal = goal; selection.reversed = false; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext) { @@ -2061,7 +2080,7 @@ impl Editor { selection.set_head(cursor); selection.goal = goal; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn move_to_previous_word_boundary( @@ -2079,7 +2098,7 @@ impl Editor { selection.reversed = false; selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_to_previous_word_boundary( @@ -2095,7 +2114,7 @@ impl Editor { selection.set_head(cursor); selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn delete_to_previous_word_boundary( @@ -2115,7 +2134,7 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); self.insert("", cx); self.end_transaction(cx); } @@ -2135,7 +2154,7 @@ impl Editor { selection.reversed = false; selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_to_next_word_boundary( @@ -2151,7 +2170,7 @@ impl Editor { selection.set_head(cursor); selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn delete_to_next_word_boundary( @@ -2171,7 +2190,7 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); self.insert("", cx); self.end_transaction(cx); } @@ -2192,7 +2211,7 @@ impl Editor { selection.reversed = false; selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_to_beginning_of_line( @@ -2208,7 +2227,7 @@ impl Editor { selection.set_head(new_head.to_point(&display_map)); selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn delete_to_beginning_of_line( @@ -2236,7 +2255,7 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext) { @@ -2248,7 +2267,7 @@ impl Editor { selection.set_head(new_head.to_point(&display_map)); selection.goal = SelectionGoal::None; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext) { @@ -2273,13 +2292,13 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }; - self.update_selections(vec![selection], true, cx); + self.update_selections(vec![selection], Some(Autoscroll::Closest), cx); } pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext) { let mut selection = self.selections::(cx).last().unwrap().clone(); selection.set_head(Point::zero()); - self.update_selections(vec![selection], true, cx); + self.update_selections(vec![selection], Some(Autoscroll::Closest), cx); } pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext) { @@ -2292,13 +2311,13 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }; - self.update_selections(vec![selection], true, cx); + self.update_selections(vec![selection], Some(Autoscroll::Closest), cx); } pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext) { let mut selection = self.selections::(cx).last().unwrap().clone(); selection.set_head(self.buffer.read(cx).len()); - self.update_selections(vec![selection], true, cx); + self.update_selections(vec![selection], Some(Autoscroll::Closest), cx); } pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext) { @@ -2309,7 +2328,7 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }; - self.update_selections(vec![selection], false, cx); + self.update_selections(vec![selection], None, cx); } pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext) { @@ -2323,7 +2342,7 @@ impl Editor { selection.end = cmp::min(max_point, Point::new(rows.end, 0)); selection.reversed = false; } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn split_selection_into_lines( @@ -2357,7 +2376,7 @@ impl Editor { to_unfold.push(selection.start..selection.end); } self.unfold_ranges(to_unfold, cx); - self.update_selections(new_selections, true, cx); + self.update_selections(new_selections, Some(Autoscroll::Closest), cx); } pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext) { @@ -2455,7 +2474,7 @@ impl Editor { state.stack.pop(); } - self.update_selections(new_selections, true, cx); + self.update_selections(new_selections, Some(Autoscroll::Closest), cx); if state.stack.len() > 1 { self.add_selections_state = Some(state); } @@ -2547,7 +2566,11 @@ impl Editor { } }); - self.update_selections(self.selections::(cx).collect(), true, cx); + self.update_selections( + self.selections::(cx).collect(), + Some(Autoscroll::Closest), + cx, + ); self.end_transaction(cx); } @@ -2592,7 +2615,7 @@ impl Editor { if selected_larger_node { stack.push(old_selections); new_selections.sort_unstable_by_key(|selection| selection.start); - self.update_selections(new_selections, true, cx); + self.update_selections(new_selections, Some(Autoscroll::Closest), cx); } self.select_larger_syntax_node_stack = stack; } @@ -2604,7 +2627,7 @@ impl Editor { ) { let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); if let Some(selections) = stack.pop() { - self.update_selections(selections.to_vec(), true, cx); + self.update_selections(selections.to_vec(), Some(Autoscroll::Closest), cx); } self.select_larger_syntax_node_stack = stack; } @@ -2633,7 +2656,7 @@ impl Editor { } } - self.update_selections(selections, true, cx); + self.update_selections(selections, Some(Autoscroll::Closest), cx); } pub fn show_next_diagnostic(&mut self, _: &ShowNextDiagnostic, cx: &mut ViewContext) { @@ -2679,7 +2702,7 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }], - true, + Some(Autoscroll::Center), cx, ); break; @@ -3007,7 +3030,7 @@ impl Editor { fn update_selections( &mut self, mut selections: Vec>, - autoscroll: bool, + autoscroll: Option, cx: &mut ViewContext, ) where T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug, @@ -3053,8 +3076,8 @@ impl Editor { } } - if autoscroll { - self.request_autoscroll(cx); + if let Some(autoscroll) = autoscroll { + self.request_autoscroll(autoscroll, cx); } self.pause_cursor_blinking(cx); @@ -3065,8 +3088,8 @@ impl Editor { }); } - fn request_autoscroll(&mut self, cx: &mut ViewContext) { - self.autoscroll_requested = true; + fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext) { + self.autoscroll_request = Some(autoscroll); cx.notify(); } @@ -3189,7 +3212,7 @@ impl Editor { fn fold_ranges(&mut self, ranges: Vec>, cx: &mut ViewContext) { if !ranges.is_empty() { self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); - self.autoscroll_requested = true; + self.request_autoscroll(Autoscroll::Closest, cx); cx.notify(); } } @@ -3198,7 +3221,7 @@ impl Editor { if !ranges.is_empty() { self.display_map .update(cx, |map, cx| map.unfold(ranges, cx)); - self.autoscroll_requested = true; + self.request_autoscroll(Autoscroll::Closest, cx); cx.notify(); } } @@ -4698,14 +4721,14 @@ mod tests { // Cut with three selections. Clipboard text is divided into three slices. view.update(cx, |view, cx| { - view.select_ranges(vec![0..7, 11..17, 22..27], false, cx); + view.select_ranges(vec![0..7, 11..17, 22..27], None, cx); view.cut(&Cut, cx); assert_eq!(view.display_text(cx), "two four six "); }); // Paste with three cursors. Each cursor pastes one slice of the clipboard text. view.update(cx, |view, cx| { - view.select_ranges(vec![4..4, 9..9, 13..13], false, cx); + view.select_ranges(vec![4..4, 9..9, 13..13], None, cx); view.paste(&Paste, cx); assert_eq!(view.display_text(cx), "two one✅ four three six five "); assert_eq!( @@ -4722,7 +4745,7 @@ mod tests { // match the number of slices in the clipboard, the entire clipboard text // is pasted at each cursor. view.update(cx, |view, cx| { - view.select_ranges(vec![0..0, 31..31], false, cx); + view.select_ranges(vec![0..0, 31..31], None, cx); view.handle_input(&Input("( ".into()), cx); view.paste(&Paste, cx); view.handle_input(&Input(") ".into()), cx); @@ -4733,7 +4756,7 @@ mod tests { }); view.update(cx, |view, cx| { - view.select_ranges(vec![0..0], false, cx); + view.select_ranges(vec![0..0], None, cx); view.handle_input(&Input("123\n4567\n89\n".into()), cx); assert_eq!( view.display_text(cx), diff --git a/crates/go_to_line/src/lib.rs b/crates/go_to_line/src/lib.rs index 2180b214d4d1f53a097ce9c951f980f79e0a6fee..f16740603908ccfc929f34fa49767f8751b175e3 100644 --- a/crates/go_to_line/src/lib.rs +++ b/crates/go_to_line/src/lib.rs @@ -1,5 +1,5 @@ use buffer::{Bias, Point}; -use editor::{Editor, EditorSettings}; +use editor::{Autoscroll, Editor, EditorSettings}; use gpui::{ action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, @@ -97,11 +97,9 @@ impl GoToLine { 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); + let buffer = active_editor.buffer().read(cx); + let point = buffer.clip_point(point, Bias::Left); + active_editor.select_ranges([point..point], Some(Autoscroll::Center), cx); }); cx.notify(); } From 085497669114fc2801a5a46fb58fc432a93d7e64 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 24 Nov 2021 15:23:45 -0700 Subject: [PATCH 3/7] Highlight the selected line when typing in the go to line dialog --- crates/editor/src/element.rs | 18 ++++++++++++++++++ crates/editor/src/lib.rs | 15 +++++++++++---- crates/go_to_line/src/lib.rs | 14 +++++++++++++- crates/theme/src/lib.rs | 2 ++ crates/zed/assets/themes/_base.toml | 1 + crates/zed/assets/themes/black.toml | 1 + crates/zed/assets/themes/dark.toml | 1 + crates/zed/assets/themes/light.toml | 1 + 8 files changed, 48 insertions(+), 5 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 489f6f0a408f8e885c22b10abc9371ddd7e1312e..feab5da26b4c27fb3973fade0201c06e18a02fa5 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -263,6 +263,20 @@ impl EditorElement { }); } } + + if let Some(highlighted_row) = layout.highlighted_row { + let origin = vec2f( + bounds.origin_x(), + bounds.origin_y() + (layout.line_height * highlighted_row as f32) - scroll_top, + ); + let size = vec2f(bounds.width(), layout.line_height); + cx.scene.push_quad(Quad { + bounds: RectF::new(origin, size), + background: Some(style.highlighted_line_background), + border: Border::default(), + corner_radius: 0., + }); + } } // Draw block backgrounds @@ -729,7 +743,9 @@ impl Element for EditorElement { let mut selections = HashMap::new(); let mut active_rows = BTreeMap::new(); + let mut highlighted_row = None; self.update_view(cx.app, |view, cx| { + highlighted_row = view.highlighted_row(); for selection_set_id in view.active_selection_sets(cx).collect::>() { let mut set = Vec::new(); for selection in view.selections_in_range( @@ -786,6 +802,7 @@ impl Element for EditorElement { snapshot, style: self.settings.style.clone(), active_rows, + highlighted_row, line_layouts, line_number_layouts, block_layouts, @@ -915,6 +932,7 @@ pub struct LayoutState { style: EditorStyle, snapshot: Snapshot, active_rows: BTreeMap, + highlighted_row: Option, line_layouts: Vec, line_number_layouts: Vec>, block_layouts: Vec<(Range, BlockStyle)>, diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 1dee47ca826192dfc16ac05b88d566fab5737e2a..340ad60081909b1cb6d663b7e2e409908f2005da 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -351,6 +351,7 @@ pub struct Editor { blinking_paused: bool, mode: EditorMode, placeholder_text: Option>, + highlighted_row: Option, } pub struct Snapshot { @@ -485,6 +486,7 @@ impl Editor { blinking_paused: false, mode: EditorMode::Full, placeholder_text: None, + highlighted_row: None, } } @@ -3248,15 +3250,19 @@ impl Editor { .text() } - // pub fn font_size(&self) -> f32 { - // self.settings.font_size - // } - pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) -> bool { self.display_map .update(cx, |map, cx| map.set_wrap_width(Some(width), cx)) } + pub fn set_highlighted_row(&mut self, row: Option) { + self.highlighted_row = row; + } + + pub fn highlighted_row(&mut self) -> Option { + self.highlighted_row + } + fn next_blink_epoch(&mut self) -> usize { self.blink_epoch += 1; self.blink_epoch @@ -3426,6 +3432,7 @@ impl EditorSettings { background: Default::default(), gutter_background: Default::default(), active_line_background: Default::default(), + highlighted_line_background: Default::default(), line_number: Default::default(), line_number_active: Default::default(), selection: Default::default(), diff --git a/crates/go_to_line/src/lib.rs b/crates/go_to_line/src/lib.rs index f16740603908ccfc929f34fa49767f8751b175e3..faccdebd0078739b15d524c956fba73f93d89d08 100644 --- a/crates/go_to_line/src/lib.rs +++ b/crates/go_to_line/src/lib.rs @@ -95,11 +95,17 @@ impl GoToLine { 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))) { + if let Some(point) = row.map(|row| { + Point::new( + row.saturating_sub(1), + column.map(|column| column.saturating_sub(1)).unwrap_or(0), + ) + }) { self.active_editor.update(cx, |active_editor, cx| { let buffer = active_editor.buffer().read(cx); let point = buffer.clip_point(point, Bias::Left); active_editor.select_ranges([point..point], Some(Autoscroll::Center), cx); + active_editor.set_highlighted_row(Some(point.row)); }); cx.notify(); } @@ -111,6 +117,12 @@ impl GoToLine { impl Entity for GoToLine { type Event = Event; + + fn release(&mut self, cx: &mut MutableAppContext) { + self.active_editor.update(cx, |editor, cx| { + editor.set_highlighted_row(None); + }) + } } impl View for GoToLine { diff --git a/crates/theme/src/lib.rs b/crates/theme/src/lib.rs index 133475426cc188fcb0d7ac8e252ed26abe2b1136..920ba7e7c99dc51ef98c9b490ba873eab9e4927f 100644 --- a/crates/theme/src/lib.rs +++ b/crates/theme/src/lib.rs @@ -223,6 +223,7 @@ pub struct EditorStyle { pub selection: SelectionStyle, pub gutter_background: Color, pub active_line_background: Color, + pub highlighted_line_background: Color, pub line_number: Color, pub line_number_active: Color, pub guest_selections: Vec, @@ -286,6 +287,7 @@ impl InputEditorStyle { selection: self.selection, gutter_background: Default::default(), active_line_background: Default::default(), + highlighted_line_background: Default::default(), line_number: Default::default(), line_number_active: Default::default(), guest_selections: Default::default(), diff --git a/crates/zed/assets/themes/_base.toml b/crates/zed/assets/themes/_base.toml index 16861b74b67946ce40bf093ef0ff0f91b50467b0..cb53226103e74dc83abefa88bd4f245e4c56fe48 100644 --- a/crates/zed/assets/themes/_base.toml +++ b/crates/zed/assets/themes/_base.toml @@ -231,6 +231,7 @@ text = "$text.1" background = "$surface.1" gutter_background = "$surface.1" active_line_background = "$state.active_line" +highlighted_line_background = "$state.highlighted_line" line_number = "$text.2.color" line_number_active = "$text.0.color" selection = "$selection.host" diff --git a/crates/zed/assets/themes/black.toml b/crates/zed/assets/themes/black.toml index d37b7905be476c8499a46e43e7f30b3e551e2385..ec51391111e67ecb9c8f8e5394cf4ae5fca55da1 100644 --- a/crates/zed/assets/themes/black.toml +++ b/crates/zed/assets/themes/black.toml @@ -37,6 +37,7 @@ bad = "#b7372e" [state] active_line = "#00000033" +highlighted_line = "#faca5033" hover = "#00000033" [editor.syntax] diff --git a/crates/zed/assets/themes/dark.toml b/crates/zed/assets/themes/dark.toml index 694e3469111890d317c1528c04143b5e36a8d37f..15850f286ab3c0293b261ae987b5ea4af8259064 100644 --- a/crates/zed/assets/themes/dark.toml +++ b/crates/zed/assets/themes/dark.toml @@ -37,6 +37,7 @@ bad = "#b7372e" [state] active_line = "#00000022" +highlighted_line = "#faca5033" hover = "#00000033" [editor.syntax] diff --git a/crates/zed/assets/themes/light.toml b/crates/zed/assets/themes/light.toml index e2bfbfb650e5c704ac306283cee949547a1a67eb..5a893368c3acc1a5f72cc194edd1595c5d63851e 100644 --- a/crates/zed/assets/themes/light.toml +++ b/crates/zed/assets/themes/light.toml @@ -37,6 +37,7 @@ bad = "#b7372e" [state] active_line = "#00000008" +highlighted_line = "#faca5033" hover = "#0000000D" [editor.syntax] From 8c0541b4550d162095af7f76199c390339bba239 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 24 Nov 2021 15:24:27 -0700 Subject: [PATCH 4/7] Fix warnings --- crates/go_to_line/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/go_to_line/src/lib.rs b/crates/go_to_line/src/lib.rs index faccdebd0078739b15d524c956fba73f93d89d08..633220f683bfb76b4db1f0588370f926acb6da25 100644 --- a/crates/go_to_line/src/lib.rs +++ b/crates/go_to_line/src/lib.rs @@ -119,7 +119,7 @@ impl Entity for GoToLine { type Event = Event; fn release(&mut self, cx: &mut MutableAppContext) { - self.active_editor.update(cx, |editor, cx| { + self.active_editor.update(cx, |editor, _| { editor.set_highlighted_row(None); }) } @@ -130,7 +130,7 @@ impl View for GoToLine { "GoToLine" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Align::new( ConstrainedBox::new( Container::new(ChildView::new(self.line_editor.id()).boxed()).boxed(), From 1e49b56626247522779ff8272ecaf51a2efb64d5 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 24 Nov 2021 15:43:48 -0700 Subject: [PATCH 5/7] Restore scroll position and selections when cancelling go-to-line But preserve the line when confirming. --- crates/editor/src/lib.rs | 9 +++++++-- crates/go_to_line/src/lib.rs | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 340ad60081909b1cb6d663b7e2e409908f2005da..46a69c7ee61a70bd2f7fbe1d37bafbd3f9d6c5b2 100644 --- a/crates/editor/src/lib.rs +++ b/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) { + pub fn set_scroll_position(&mut self, scroll_position: Vector2F, cx: &mut ViewContext) { 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) -> 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( + pub fn update_selections( &mut self, mut selections: Vec>, autoscroll: Option, diff --git a/crates/go_to_line/src/lib.rs b/crates/go_to_line/src/lib.rs index 633220f683bfb76b4db1f0588370f926acb6da25..35d8469d97bc7118870a5192ab5a429920d25a13 100644 --- a/crates/go_to_line/src/lib.rs +++ b/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, line_editor: ViewHandle, active_editor: ViewHandle, + restore_state: Option, +} + +struct RestoreState { + scroll_position: Vector2F, + selections: Vec>, } 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::(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.restore_state.take(); + cx.emit(Event::Dismissed); + } + fn on_event( workspace: &mut Workspace, _: ViewHandle, @@ -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); + } }) } } From a07fe3aa587e65a47121f3953a842ce8defb252c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 24 Nov 2021 16:16:29 -0700 Subject: [PATCH 6/7] Improve styling of the go to line modal --- crates/go_to_line/src/lib.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/go_to_line/src/lib.rs b/crates/go_to_line/src/lib.rs index 35d8469d97bc7118870a5192ab5a429920d25a13..a9ac1700d73a4490ed26f3f52375782461c6a562 100644 --- a/crates/go_to_line/src/lib.rs +++ b/crates/go_to_line/src/lib.rs @@ -1,8 +1,8 @@ use buffer::{Bias, Point, Selection}; use editor::{Autoscroll, Editor, EditorSettings}; use gpui::{ - action, elements::*, geometry::vector::Vector2F, keymap::Binding, Entity, MutableAppContext, - RenderContext, View, ViewContext, ViewHandle, + action, elements::*, geometry::vector::Vector2F, keymap::Binding, Axis, Entity, + MutableAppContext, RenderContext, View, ViewContext, ViewHandle, }; use postage::watch; use workspace::{Settings, Workspace}; @@ -50,7 +50,7 @@ impl GoToLine { let settings = settings.borrow(); EditorSettings { tab_size: settings.tab_size, - style: settings.theme.editor.clone(), + style: settings.theme.selector.input_editor.as_editor(), } } }, @@ -159,12 +159,19 @@ impl View for GoToLine { } fn render(&mut self, _: &mut RenderContext) -> ElementBox { + let theme = &self.settings.borrow().theme.selector; + Align::new( ConstrainedBox::new( - Container::new(ChildView::new(self.line_editor.id()).boxed()).boxed(), + Flex::new(Axis::Vertical) + .with_child( + Container::new(ChildView::new(self.line_editor.id()).boxed()) + .with_style(theme.container) + .boxed(), + ) + .boxed(), ) .with_max_width(500.0) - .with_max_height(420.0) .boxed(), ) .top() From f7532c785edf3b2bc677616848746a7cdcc9a11a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 24 Nov 2021 16:52:18 -0700 Subject: [PATCH 7/7] Render the current line, column, and line count in go to line dialog --- crates/go_to_line/src/lib.rs | 48 +++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/crates/go_to_line/src/lib.rs b/crates/go_to_line/src/lib.rs index a9ac1700d73a4490ed26f3f52375782461c6a562..266d8f433a32830ef0c489aee68eba72e2b78a00 100644 --- a/crates/go_to_line/src/lib.rs +++ b/crates/go_to_line/src/lib.rs @@ -25,6 +25,8 @@ pub struct GoToLine { line_editor: ViewHandle, active_editor: ViewHandle, restore_state: Option, + cursor_point: Point, + max_point: Point, } struct RestoreState { @@ -60,11 +62,17 @@ impl GoToLine { cx.subscribe(&line_editor, Self::on_line_editor_event) .detach(); - let restore_state = active_editor.update(cx, |editor, cx| { - Some(RestoreState { + let (restore_state, cursor_point, max_point) = active_editor.update(cx, |editor, cx| { + let restore_state = Some(RestoreState { scroll_position: editor.scroll_position(cx), selections: editor.selections::(cx).collect(), - }) + }); + + ( + restore_state, + editor.newest_selection(cx).head(), + editor.buffer().read(cx).max_point(), + ) }); Self { @@ -72,6 +80,8 @@ impl GoToLine { line_editor, active_editor, restore_state, + cursor_point, + max_point, } } @@ -115,7 +125,7 @@ impl GoToLine { 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 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| { @@ -161,15 +171,31 @@ impl View for GoToLine { fn render(&mut self, _: &mut RenderContext) -> ElementBox { let theme = &self.settings.borrow().theme.selector; + let label = format!( + "{},{} of {} lines", + self.cursor_point.row + 1, + self.cursor_point.column + 1, + self.max_point.row + 1 + ); + Align::new( ConstrainedBox::new( - Flex::new(Axis::Vertical) - .with_child( - Container::new(ChildView::new(self.line_editor.id()).boxed()) - .with_style(theme.container) - .boxed(), - ) - .boxed(), + Container::new( + Flex::new(Axis::Vertical) + .with_child( + Container::new(ChildView::new(self.line_editor.id()).boxed()) + .with_style(theme.input_editor.container) + .boxed(), + ) + .with_child( + Container::new(Label::new(label, theme.empty.label.clone()).boxed()) + .with_style(theme.empty.container) + .boxed(), + ) + .boxed(), + ) + .with_style(theme.container) + .boxed(), ) .with_max_width(500.0) .boxed(),