From 139bcb8304c47ac89a30961fd6843ff26432c2c0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 14:33:02 -0700 Subject: [PATCH 01/16] Rename `foo/mod.rs` files too `foo.rs` Co-Authored-By: Nathan Sobo --- gpui/src/{elements/new.rs => elements.rs} | 54 +++++++++++++++++- gpui/src/elements/mod.rs | 56 ------------------- gpui/src/{platform/mod.rs => platform.rs} | 0 gpui/src/platform/{mac/mod.rs => mac.rs} | 0 zed/src/{editor/mod.rs => editor.rs} | 0 zed/src/editor/{buffer/mod.rs => buffer.rs} | 0 .../{display_map/mod.rs => display_map.rs} | 0 zed/src/{sum_tree/mod.rs => sum_tree.rs} | 0 8 files changed, 52 insertions(+), 58 deletions(-) rename gpui/src/{elements/new.rs => elements.rs} (86%) delete mode 100644 gpui/src/elements/mod.rs rename gpui/src/{platform/mod.rs => platform.rs} (100%) rename gpui/src/platform/{mac/mod.rs => mac.rs} (100%) rename zed/src/{editor/mod.rs => editor.rs} (100%) rename zed/src/editor/{buffer/mod.rs => buffer.rs} (100%) rename zed/src/editor/{display_map/mod.rs => display_map.rs} (100%) rename zed/src/{sum_tree/mod.rs => sum_tree.rs} (100%) diff --git a/gpui/src/elements/new.rs b/gpui/src/elements.rs similarity index 86% rename from gpui/src/elements/new.rs rename to gpui/src/elements.rs index e45a71e16a421db141e4e00ddae45c961bf0d42c..f78a3f999d34e6af9b056d934f5d1bbc6a25d028 100644 --- a/gpui/src/elements/new.rs +++ b/gpui/src/elements.rs @@ -1,7 +1,36 @@ +mod align; +mod canvas; +mod constrained_box; +mod container; +mod empty; +mod event_handler; +mod flex; +mod label; +mod line_box; +mod mouse_event_handler; +mod stack; +mod svg; +mod uniform_list; + +pub use crate::presenter::ChildView; +pub use align::*; +pub use canvas::*; +pub use constrained_box::*; +pub use container::*; +pub use empty::*; +pub use event_handler::*; +pub use flex::*; +pub use label::*; +pub use line_box::*; +pub use mouse_event_handler::*; +pub use stack::*; +pub use svg::*; +pub use uniform_list::*; + use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, AfterLayoutContext, DebugContext, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, + json, AfterLayoutContext, AppContext, DebugContext, Event, EventContext, LayoutContext, + PaintContext, SizeConstraint, }; use core::panic; use json::ToJson; @@ -268,3 +297,24 @@ impl ElementBox { value } } + +pub trait ParentElement<'a>: Extend + Sized { + fn add_children(&mut self, children: impl IntoIterator) { + self.extend(children); + } + + fn add_child(&mut self, child: ElementBox) { + self.add_children(Some(child)); + } + + fn with_children(mut self, children: impl IntoIterator) -> Self { + self.add_children(children); + self + } + + fn with_child(self, child: ElementBox) -> Self { + self.with_children(Some(child)) + } +} + +impl<'a, T> ParentElement<'a> for T where T: Extend {} diff --git a/gpui/src/elements/mod.rs b/gpui/src/elements/mod.rs deleted file mode 100644 index ab56cf280258a3cf0430c53d61a653c549e83631..0000000000000000000000000000000000000000 --- a/gpui/src/elements/mod.rs +++ /dev/null @@ -1,56 +0,0 @@ -mod align; -mod canvas; -mod constrained_box; -mod container; -mod empty; -mod event_handler; -mod flex; -mod label; -mod line_box; -mod mouse_event_handler; -mod new; -mod stack; -mod svg; -mod uniform_list; - -pub use crate::presenter::ChildView; -pub use align::*; -pub use canvas::*; -pub use constrained_box::*; -pub use container::*; -pub use empty::*; -pub use event_handler::*; -pub use flex::*; -pub use label::*; -pub use line_box::*; -pub use mouse_event_handler::*; -pub use new::*; -pub use stack::*; -pub use svg::*; -pub use uniform_list::*; - -use crate::{ - AfterLayoutContext, AppContext, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, -}; - -pub trait ParentElement<'a>: Extend + Sized { - fn add_children(&mut self, children: impl IntoIterator) { - self.extend(children); - } - - fn add_child(&mut self, child: ElementBox) { - self.add_children(Some(child)); - } - - fn with_children(mut self, children: impl IntoIterator) -> Self { - self.add_children(children); - self - } - - fn with_child(self, child: ElementBox) -> Self { - self.with_children(Some(child)) - } -} - -impl<'a, T> ParentElement<'a> for T where T: Extend {} diff --git a/gpui/src/platform/mod.rs b/gpui/src/platform.rs similarity index 100% rename from gpui/src/platform/mod.rs rename to gpui/src/platform.rs diff --git a/gpui/src/platform/mac/mod.rs b/gpui/src/platform/mac.rs similarity index 100% rename from gpui/src/platform/mac/mod.rs rename to gpui/src/platform/mac.rs diff --git a/zed/src/editor/mod.rs b/zed/src/editor.rs similarity index 100% rename from zed/src/editor/mod.rs rename to zed/src/editor.rs diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer.rs similarity index 100% rename from zed/src/editor/buffer/mod.rs rename to zed/src/editor/buffer.rs diff --git a/zed/src/editor/display_map/mod.rs b/zed/src/editor/display_map.rs similarity index 100% rename from zed/src/editor/display_map/mod.rs rename to zed/src/editor/display_map.rs diff --git a/zed/src/sum_tree/mod.rs b/zed/src/sum_tree.rs similarity index 100% rename from zed/src/sum_tree/mod.rs rename to zed/src/sum_tree.rs From 90f35546d3fcfd99f17556cb4e6e7f9d509fc931 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 14:41:39 -0700 Subject: [PATCH 02/16] Rename BufferView -> Editor * BufferElement -> EditorElement Co-Authored-By: Nathan Sobo --- zed/src/editor.rs | 4090 +++++++++++++++- zed/src/editor/buffer_view.rs | 4118 ----------------- .../editor/{buffer_element.rs => element.rs} | 20 +- zed/src/file_finder.rs | 19 +- zed/src/workspace.rs | 12 +- 5 files changed, 4110 insertions(+), 4149 deletions(-) delete mode 100644 zed/src/editor/buffer_view.rs rename zed/src/editor/{buffer_element.rs => element.rs} (98%) diff --git a/zed/src/editor.rs b/zed/src/editor.rs index dc81ffbfbc8eab82a27496e0d4007462a593210c..08ba35d86bfaeb27513f0ff71f552b1ce8df5bd7 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -1,19 +1,4099 @@ mod buffer; -mod buffer_element; -pub mod buffer_view; pub mod display_map; +mod element; pub mod movement; +use crate::{ + settings::{Settings, StyleId}, + util::post_inc, + workspace, + worktree::FileHandle, +}; +use anyhow::Result; pub use buffer::*; -pub use buffer_element::*; -pub use buffer_view::*; pub use display_map::DisplayPoint; use display_map::*; +pub use element::*; +use gpui::{ + color::ColorU, fonts::Properties as FontProperties, geometry::vector::Vector2F, + keymap::Binding, text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, + FontCache, ModelHandle, MutableAppContext, Task, TextLayoutCache, View, ViewContext, + WeakViewHandle, +}; +use parking_lot::Mutex; +use postage::watch; +use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; +use smol::Timer; use std::{ - cmp, + cmp::{self, Ordering}, + fmt::Write, + iter::FromIterator, + mem, ops::{Range, RangeInclusive}, + path::Path, + sync::Arc, + time::Duration, }; +const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); + +pub fn init(app: &mut MutableAppContext) { + app.add_bindings(vec![ + Binding::new("escape", "buffer:cancel", Some("BufferView")), + Binding::new("backspace", "buffer:backspace", Some("BufferView")), + Binding::new("ctrl-h", "buffer:backspace", Some("BufferView")), + Binding::new("delete", "buffer:delete", Some("BufferView")), + Binding::new("ctrl-d", "buffer:delete", Some("BufferView")), + Binding::new("enter", "buffer:newline", Some("BufferView")), + Binding::new("tab", "buffer:insert", Some("BufferView")).with_arg("\t".to_string()), + Binding::new("ctrl-shift-K", "buffer:delete_line", Some("BufferView")), + Binding::new( + "alt-backspace", + "buffer:delete_to_previous_word_boundary", + Some("BufferView"), + ), + Binding::new( + "alt-delete", + "buffer:delete_to_next_word_boundary", + Some("BufferView"), + ), + Binding::new( + "cmd-backspace", + "buffer:delete_to_beginning_of_line", + Some("BufferView"), + ), + Binding::new( + "cmd-delete", + "buffer:delete_to_end_of_line", + Some("BufferView"), + ), + Binding::new("cmd-shift-D", "buffer:duplicate_line", Some("BufferView")), + Binding::new("ctrl-cmd-up", "buffer:move_line_up", Some("BufferView")), + Binding::new("ctrl-cmd-down", "buffer:move_line_down", Some("BufferView")), + Binding::new("cmd-x", "buffer:cut", Some("BufferView")), + Binding::new("cmd-c", "buffer:copy", Some("BufferView")), + Binding::new("cmd-v", "buffer:paste", Some("BufferView")), + Binding::new("cmd-z", "buffer:undo", Some("BufferView")), + Binding::new("cmd-shift-Z", "buffer:redo", Some("BufferView")), + Binding::new("up", "buffer:move_up", Some("BufferView")), + Binding::new("down", "buffer:move_down", Some("BufferView")), + Binding::new("left", "buffer:move_left", Some("BufferView")), + Binding::new("right", "buffer:move_right", Some("BufferView")), + Binding::new("ctrl-p", "buffer:move_up", Some("BufferView")), + Binding::new("ctrl-n", "buffer:move_down", Some("BufferView")), + Binding::new("ctrl-b", "buffer:move_left", Some("BufferView")), + Binding::new("ctrl-f", "buffer:move_right", Some("BufferView")), + Binding::new( + "alt-left", + "buffer:move_to_previous_word_boundary", + Some("BufferView"), + ), + Binding::new( + "alt-right", + "buffer:move_to_next_word_boundary", + Some("BufferView"), + ), + Binding::new( + "cmd-left", + "buffer:move_to_beginning_of_line", + Some("BufferView"), + ), + Binding::new( + "ctrl-a", + "buffer:move_to_beginning_of_line", + Some("BufferView"), + ), + Binding::new( + "cmd-right", + "buffer:move_to_end_of_line", + Some("BufferView"), + ), + Binding::new("ctrl-e", "buffer:move_to_end_of_line", Some("BufferView")), + Binding::new("cmd-up", "buffer:move_to_beginning", Some("BufferView")), + Binding::new("cmd-down", "buffer:move_to_end", Some("BufferView")), + Binding::new("shift-up", "buffer:select_up", Some("BufferView")), + Binding::new("shift-down", "buffer:select_down", Some("BufferView")), + Binding::new("shift-left", "buffer:select_left", Some("BufferView")), + Binding::new("shift-right", "buffer:select_right", Some("BufferView")), + Binding::new( + "alt-shift-left", + "buffer:select_to_previous_word_boundary", + Some("BufferView"), + ), + Binding::new( + "alt-shift-right", + "buffer:select_to_next_word_boundary", + Some("BufferView"), + ), + Binding::new( + "cmd-shift-left", + "buffer:select_to_beginning_of_line", + Some("BufferView"), + ) + .with_arg(true), + Binding::new( + "ctrl-shift-A", + "buffer:select_to_beginning_of_line", + Some("BufferView"), + ) + .with_arg(true), + Binding::new( + "cmd-shift-right", + "buffer:select_to_end_of_line", + Some("BufferView"), + ), + Binding::new( + "ctrl-shift-E", + "buffer:select_to_end_of_line", + Some("BufferView"), + ), + Binding::new( + "cmd-shift-up", + "buffer:select_to_beginning", + Some("BufferView"), + ), + Binding::new("cmd-shift-down", "buffer:select_to_end", Some("BufferView")), + Binding::new("cmd-a", "buffer:select_all", Some("BufferView")), + Binding::new("cmd-l", "buffer:select_line", Some("BufferView")), + Binding::new( + "cmd-shift-L", + "buffer:split_selection_into_lines", + Some("BufferView"), + ), + Binding::new( + "cmd-alt-up", + "buffer:add_selection_above", + Some("BufferView"), + ), + Binding::new( + "cmd-alt-down", + "buffer:add_selection_below", + Some("BufferView"), + ), + Binding::new( + "alt-up", + "buffer:select_larger_syntax_node", + Some("BufferView"), + ), + Binding::new( + "alt-down", + "buffer:select_smaller_syntax_node", + Some("BufferView"), + ), + Binding::new( + "ctrl-m", + "buffer:move_to_enclosing_bracket", + Some("BufferView"), + ), + Binding::new("pageup", "buffer:page_up", Some("BufferView")), + Binding::new("pagedown", "buffer:page_down", Some("BufferView")), + Binding::new("alt-cmd-[", "buffer:fold", Some("BufferView")), + Binding::new("alt-cmd-]", "buffer:unfold", Some("BufferView")), + Binding::new( + "alt-cmd-f", + "buffer:fold_selected_ranges", + Some("BufferView"), + ), + ]); + + app.add_action("buffer:scroll", Editor::scroll); + app.add_action("buffer:select", Editor::select); + app.add_action("buffer:cancel", Editor::cancel); + app.add_action("buffer:insert", Editor::insert); + app.add_action("buffer:newline", Editor::newline); + app.add_action("buffer:backspace", Editor::backspace); + app.add_action("buffer:delete", Editor::delete); + app.add_action("buffer:delete_line", Editor::delete_line); + app.add_action( + "buffer:delete_to_previous_word_boundary", + Editor::delete_to_previous_word_boundary, + ); + app.add_action( + "buffer:delete_to_next_word_boundary", + Editor::delete_to_next_word_boundary, + ); + app.add_action( + "buffer:delete_to_beginning_of_line", + Editor::delete_to_beginning_of_line, + ); + app.add_action( + "buffer:delete_to_end_of_line", + Editor::delete_to_end_of_line, + ); + app.add_action("buffer:duplicate_line", Editor::duplicate_line); + app.add_action("buffer:move_line_up", Editor::move_line_up); + app.add_action("buffer:move_line_down", Editor::move_line_down); + app.add_action("buffer:cut", Editor::cut); + app.add_action("buffer:copy", Editor::copy); + app.add_action("buffer:paste", Editor::paste); + app.add_action("buffer:undo", Editor::undo); + app.add_action("buffer:redo", Editor::redo); + app.add_action("buffer:move_up", Editor::move_up); + app.add_action("buffer:move_down", Editor::move_down); + app.add_action("buffer:move_left", Editor::move_left); + app.add_action("buffer:move_right", Editor::move_right); + app.add_action( + "buffer:move_to_previous_word_boundary", + Editor::move_to_previous_word_boundary, + ); + app.add_action( + "buffer:move_to_next_word_boundary", + Editor::move_to_next_word_boundary, + ); + app.add_action( + "buffer:move_to_beginning_of_line", + Editor::move_to_beginning_of_line, + ); + app.add_action("buffer:move_to_end_of_line", Editor::move_to_end_of_line); + app.add_action("buffer:move_to_beginning", Editor::move_to_beginning); + app.add_action("buffer:move_to_end", Editor::move_to_end); + app.add_action("buffer:select_up", Editor::select_up); + app.add_action("buffer:select_down", Editor::select_down); + app.add_action("buffer:select_left", Editor::select_left); + app.add_action("buffer:select_right", Editor::select_right); + app.add_action( + "buffer:select_to_previous_word_boundary", + Editor::select_to_previous_word_boundary, + ); + app.add_action( + "buffer:select_to_next_word_boundary", + Editor::select_to_next_word_boundary, + ); + app.add_action( + "buffer:select_to_beginning_of_line", + Editor::select_to_beginning_of_line, + ); + app.add_action( + "buffer:select_to_end_of_line", + Editor::select_to_end_of_line, + ); + app.add_action("buffer:select_to_beginning", Editor::select_to_beginning); + app.add_action("buffer:select_to_end", Editor::select_to_end); + app.add_action("buffer:select_all", Editor::select_all); + app.add_action("buffer:select_line", Editor::select_line); + app.add_action( + "buffer:split_selection_into_lines", + Editor::split_selection_into_lines, + ); + app.add_action("buffer:add_selection_above", Editor::add_selection_above); + app.add_action("buffer:add_selection_below", Editor::add_selection_below); + app.add_action( + "buffer:select_larger_syntax_node", + Editor::select_larger_syntax_node, + ); + app.add_action( + "buffer:select_smaller_syntax_node", + Editor::select_smaller_syntax_node, + ); + app.add_action( + "buffer:move_to_enclosing_bracket", + Editor::move_to_enclosing_bracket, + ); + app.add_action("buffer:page_up", Editor::page_up); + app.add_action("buffer:page_down", Editor::page_down); + app.add_action("buffer:fold", Editor::fold); + app.add_action("buffer:unfold", Editor::unfold); + app.add_action("buffer:fold_selected_ranges", Editor::fold_selected_ranges); +} + +pub enum SelectAction { + Begin { + position: DisplayPoint, + add: bool, + }, + Update { + position: DisplayPoint, + scroll_position: Vector2F, + }, + End, +} + +pub struct Editor { + handle: WeakViewHandle, + buffer: ModelHandle, + display_map: DisplayMap, + selection_set_id: SelectionSetId, + pending_selection: Option, + next_selection_id: usize, + add_selections_state: Option, + select_larger_syntax_node_stack: Vec>, + scroll_position: Mutex, + autoscroll_requested: Mutex, + settings: watch::Receiver, + focused: bool, + cursors_visible: bool, + blink_epoch: usize, + blinking_paused: bool, + single_line: bool, +} + +struct AddSelectionsState { + above: bool, + stack: Vec, +} + +#[derive(Serialize, Deserialize)] +struct ClipboardSelection { + len: usize, + is_entire_line: bool, +} + +impl Editor { + pub fn single_line(settings: watch::Receiver, ctx: &mut ViewContext) -> Self { + let buffer = ctx.add_model(|ctx| Buffer::new(0, String::new(), ctx)); + let mut view = Self::for_buffer(buffer, settings, ctx); + view.single_line = true; + view + } + + pub fn for_buffer( + buffer: ModelHandle, + settings: watch::Receiver, + ctx: &mut ViewContext, + ) -> Self { + ctx.observe_model(&buffer, Self::on_buffer_changed); + ctx.subscribe_to_model(&buffer, Self::on_buffer_event); + let display_map = DisplayMap::new(buffer.clone(), settings.borrow().tab_size, ctx.as_ref()); + + let mut next_selection_id = 0; + let (selection_set_id, _) = buffer.update(ctx, |buffer, ctx| { + buffer.add_selection_set( + vec![Selection { + id: post_inc(&mut next_selection_id), + start: buffer.anchor_before(0), + end: buffer.anchor_before(0), + reversed: false, + goal: SelectionGoal::None, + }], + Some(ctx), + ) + }); + Self { + handle: ctx.handle().downgrade(), + buffer, + display_map, + selection_set_id, + pending_selection: None, + next_selection_id, + add_selections_state: None, + select_larger_syntax_node_stack: Vec::new(), + scroll_position: Mutex::new(Vector2F::zero()), + autoscroll_requested: Mutex::new(false), + settings, + focused: false, + cursors_visible: false, + blink_epoch: 0, + blinking_paused: false, + single_line: false, + } + } + + pub fn buffer(&self) -> &ModelHandle { + &self.buffer + } + + pub fn is_gutter_visible(&self) -> bool { + !self.single_line + } + + fn scroll(&mut self, scroll_position: &Vector2F, ctx: &mut ViewContext) { + *self.scroll_position.lock() = *scroll_position; + ctx.notify(); + } + + pub fn scroll_position(&self) -> Vector2F { + *self.scroll_position.lock() + } + + pub fn clamp_scroll_left(&self, max: f32) { + let mut scroll_position = self.scroll_position.lock(); + let scroll_left = scroll_position.x(); + scroll_position.set_x(scroll_left.min(max)); + } + + pub fn autoscroll_vertically( + &self, + viewport_height: f32, + line_height: f32, + app: &AppContext, + ) -> bool { + let mut scroll_position = self.scroll_position.lock(); + let scroll_top = scroll_position.y(); + scroll_position.set_y(scroll_top.min(self.max_point(app).row().saturating_sub(1) as f32)); + + let mut autoscroll_requested = self.autoscroll_requested.lock(); + if *autoscroll_requested { + *autoscroll_requested = false; + } else { + return false; + } + + let visible_lines = viewport_height / line_height; + let first_cursor_top = self + .selections(app) + .first() + .unwrap() + .head() + .to_display_point(&self.display_map, app) + .row() as f32; + let last_cursor_bottom = self + .selections(app) + .last() + .unwrap() + .head() + .to_display_point(&self.display_map, app) + .row() as f32 + + 1.0; + + let margin = ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0) + .floor() + .min(3.0); + 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); + } else if target_bottom >= end_row { + scroll_position.set_y(target_bottom - visible_lines); + } + + true + } + + pub fn autoscroll_horizontally( + &self, + start_row: u32, + viewport_width: f32, + scroll_width: f32, + max_glyph_width: f32, + layouts: &[text_layout::Line], + ctx: &AppContext, + ) { + let mut target_left = std::f32::INFINITY; + let mut target_right = 0.0_f32; + for selection in self.selections(ctx) { + let head = selection.head().to_display_point(&self.display_map, ctx); + let start_column = head.column().saturating_sub(3); + let end_column = cmp::min( + self.display_map.line_len(head.row(), ctx), + head.column() + 3, + ); + target_left = target_left + .min(layouts[(head.row() - start_row) as usize].x_for_index(start_column as usize)); + target_right = target_right.max( + layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize) + + max_glyph_width, + ); + } + target_right = target_right.min(scroll_width); + + if target_right - target_left > viewport_width { + return; + } + + let mut scroll_position = self.scroll_position.lock(); + let scroll_left = scroll_position.x() * max_glyph_width; + let scroll_right = scroll_left + viewport_width; + + if target_left < scroll_left { + scroll_position.set_x(target_left / max_glyph_width); + } else if target_right > scroll_right { + scroll_position.set_x((target_right - viewport_width) / max_glyph_width); + } + } + + fn select(&mut self, arg: &SelectAction, ctx: &mut ViewContext) { + match arg { + SelectAction::Begin { position, add } => self.begin_selection(*position, *add, ctx), + SelectAction::Update { + position, + scroll_position, + } => self.update_selection(*position, *scroll_position, ctx), + SelectAction::End => self.end_selection(ctx), + } + } + + fn begin_selection(&mut self, position: DisplayPoint, add: bool, ctx: &mut ViewContext) { + if !self.focused { + ctx.focus_self(); + ctx.emit(Event::Activate); + } + + let cursor = self + .display_map + .anchor_before(position, Bias::Left, ctx.as_ref()); + let selection = Selection { + id: post_inc(&mut self.next_selection_id), + start: cursor.clone(), + end: cursor, + reversed: false, + goal: SelectionGoal::None, + }; + + if !add { + self.update_selections(Vec::new(), false, ctx); + } + self.pending_selection = Some(selection); + + ctx.notify(); + } + + fn update_selection( + &mut self, + position: DisplayPoint, + scroll_position: Vector2F, + ctx: &mut ViewContext, + ) { + let buffer = self.buffer.read(ctx); + let cursor = self + .display_map + .anchor_before(position, Bias::Left, ctx.as_ref()); + if let Some(selection) = self.pending_selection.as_mut() { + selection.set_head(buffer, cursor); + } else { + log::error!("update_selection dispatched with no pending selection"); + return; + } + + *self.scroll_position.lock() = scroll_position; + + ctx.notify(); + } + + fn end_selection(&mut self, ctx: &mut ViewContext) { + if let Some(selection) = self.pending_selection.take() { + let ix = self.selection_insertion_index(&selection.start, ctx.as_ref()); + let mut selections = self.selections(ctx.as_ref()).to_vec(); + selections.insert(ix, selection); + self.update_selections(selections, false, ctx); + } else { + log::error!("end_selection dispatched with no pending selection"); + } + } + + pub fn is_selecting(&self) -> bool { + self.pending_selection.is_some() + } + + pub fn cancel(&mut self, _: &(), ctx: &mut ViewContext) { + let selections = self.selections(ctx.as_ref()); + if let Some(pending_selection) = self.pending_selection.take() { + if selections.is_empty() { + self.update_selections(vec![pending_selection], true, ctx); + } + } else { + let mut oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); + if selections.len() == 1 { + oldest_selection.start = oldest_selection.head().clone(); + oldest_selection.end = oldest_selection.head().clone(); + } + self.update_selections(vec![oldest_selection], true, ctx); + } + } + + fn select_ranges(&mut self, ranges: I, autoscroll: bool, ctx: &mut ViewContext) + where + I: IntoIterator>, + T: ToOffset, + { + let buffer = self.buffer.read(ctx); + let mut selections = Vec::new(); + for range in ranges { + let mut start = range.start.to_offset(buffer); + let mut end = range.end.to_offset(buffer); + let reversed = if start > end { + mem::swap(&mut start, &mut end); + true + } else { + false + }; + selections.push(Selection { + id: post_inc(&mut self.next_selection_id), + start: buffer.anchor_before(start), + end: buffer.anchor_before(end), + reversed, + goal: SelectionGoal::None, + }); + } + self.update_selections(selections, autoscroll, ctx); + } + + #[cfg(test)] + fn select_display_ranges<'a, T>(&mut self, ranges: T, ctx: &mut ViewContext) -> Result<()> + where + T: IntoIterator>, + { + let mut selections = Vec::new(); + for range in ranges { + let mut start = range.start; + let mut end = range.end; + let reversed = if start > end { + mem::swap(&mut start, &mut end); + true + } else { + false + }; + + selections.push(Selection { + id: post_inc(&mut self.next_selection_id), + start: self + .display_map + .anchor_before(start, Bias::Left, ctx.as_ref()), + end: self + .display_map + .anchor_before(end, Bias::Left, ctx.as_ref()), + reversed, + goal: SelectionGoal::None, + }); + } + self.update_selections(selections, false, ctx); + Ok(()) + } + + pub fn insert(&mut self, text: &String, ctx: &mut ViewContext) { + let mut old_selections = SmallVec::<[_; 32]>::new(); + { + let buffer = self.buffer.read(ctx); + for selection in self.selections(ctx.as_ref()) { + let start = selection.start.to_offset(buffer); + let end = selection.end.to_offset(buffer); + old_selections.push((selection.id, start..end)); + } + } + + self.start_transaction(ctx); + let mut new_selections = Vec::new(); + self.buffer.update(ctx, |buffer, ctx| { + let edit_ranges = old_selections.iter().map(|(_, range)| range.clone()); + if let Err(error) = buffer.edit(edit_ranges, text.as_str(), Some(ctx)) { + log::error!("error inserting text: {}", error); + }; + let text_len = text.len() as isize; + let mut delta = 0_isize; + new_selections = old_selections + .into_iter() + .map(|(id, range)| { + let start = range.start as isize; + let end = range.end as isize; + let anchor = buffer.anchor_before((start + delta + text_len) as usize); + let deleted_count = end - start; + delta += text_len - deleted_count; + Selection { + id, + start: anchor.clone(), + end: anchor, + reversed: false, + goal: SelectionGoal::None, + } + }) + .collect(); + }); + + self.update_selections(new_selections, true, ctx); + self.end_transaction(ctx); + } + + fn newline(&mut self, _: &(), ctx: &mut ViewContext) { + if self.single_line { + ctx.propagate_action(); + } else { + self.insert(&"\n".into(), ctx); + } + } + + pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + let range = selection.point_range(buffer); + if range.start == range.end { + let head = selection + .head() + .to_display_point(&self.display_map, ctx.as_ref()); + let cursor = self.display_map.anchor_before( + movement::left(&self.display_map, head, ctx.as_ref()).unwrap(), + Bias::Left, + ctx.as_ref(), + ); + selection.set_head(&buffer, cursor); + selection.goal = SelectionGoal::None; + } + } + } + + self.update_selections(selections, true, ctx); + self.insert(&String::new(), ctx); + self.end_transaction(ctx); + } + + pub fn delete(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + let range = selection.point_range(buffer); + if range.start == range.end { + let head = selection + .head() + .to_display_point(&self.display_map, ctx.as_ref()); + let cursor = self.display_map.anchor_before( + movement::right(&self.display_map, head, ctx.as_ref()).unwrap(), + Bias::Right, + ctx.as_ref(), + ); + selection.set_head(&buffer, cursor); + selection.goal = SelectionGoal::None; + } + } + } + + self.update_selections(selections, true, ctx); + self.insert(&String::new(), ctx); + self.end_transaction(ctx); + } + + pub fn delete_line(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + + let mut new_cursors = Vec::new(); + let mut edit_ranges = Vec::new(); + + let mut selections = self.selections(app).iter().peekable(); + while let Some(selection) = selections.next() { + let (mut rows, _) = + selection.buffer_rows_for_display_rows(false, &self.display_map, app); + let goal_display_column = selection + .head() + .to_display_point(&self.display_map, app) + .column(); + + // Accumulate contiguous regions of rows that we want to delete. + while let Some(next_selection) = selections.peek() { + let (next_rows, _) = + next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); + if next_rows.start <= rows.end { + rows.end = next_rows.end; + selections.next().unwrap(); + } else { + break; + } + } + + let mut edit_start = Point::new(rows.start, 0).to_offset(buffer); + let edit_end; + let cursor_buffer_row; + if buffer.max_point().row >= rows.end { + // If there's a line after the range, delete the \n from the end of the row range + // and position the cursor on the next line. + edit_end = Point::new(rows.end, 0).to_offset(buffer); + cursor_buffer_row = rows.end; + } else { + // If there isn't a line after the range, delete the \n from the line before the + // start of the row range and position the cursor there. + edit_start = edit_start.saturating_sub(1); + edit_end = buffer.len(); + cursor_buffer_row = rows.start.saturating_sub(1); + } + + let mut cursor = + Point::new(cursor_buffer_row, 0).to_display_point(&self.display_map, app); + *cursor.column_mut() = cmp::min( + goal_display_column, + self.display_map.line_len(cursor.row(), app), + ); + + new_cursors.push(( + selection.id, + cursor.to_buffer_point(&self.display_map, Bias::Left, app), + )); + edit_ranges.push(edit_start..edit_end); + } + + new_cursors.sort_unstable_by_key(|(_, range)| range.clone()); + let new_selections = new_cursors + .into_iter() + .map(|(id, cursor)| { + let anchor = buffer.anchor_before(cursor); + Selection { + id, + start: anchor.clone(), + end: anchor, + reversed: false, + goal: SelectionGoal::None, + } + }) + .collect(); + self.buffer + .update(ctx, |buffer, ctx| buffer.edit(edit_ranges, "", Some(ctx))) + .unwrap(); + self.update_selections(new_selections, true, ctx); + self.end_transaction(ctx); + } + + pub fn duplicate_line(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + // Temporarily bias selections right to allow newly duplicate lines to push them down + // when the selections are at the beginning of a line. + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + selection.start = selection.start.bias_right(buffer); + selection.end = selection.end.bias_right(buffer); + } + } + self.update_selections(selections.clone(), false, ctx); + + let app = ctx.as_ref(); + let buffer = self.buffer.read(ctx); + + let mut edits = Vec::new(); + let mut selections_iter = selections.iter_mut().peekable(); + while let Some(selection) = selections_iter.next() { + // Avoid duplicating the same lines twice. + let (mut rows, _) = + selection.buffer_rows_for_display_rows(false, &self.display_map, app); + while let Some(next_selection) = selections_iter.peek() { + let (next_rows, _) = + next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); + if next_rows.start <= rows.end - 1 { + rows.end = next_rows.end; + selections_iter.next().unwrap(); + } else { + break; + } + } + + // Copy the text from the selected row region and splice it at the start of the region. + let start = Point::new(rows.start, 0); + let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1)); + let text = buffer + .text_for_range(start..end) + .chain(Some("\n")) + .collect::(); + edits.push((start, text)); + } + + self.buffer.update(ctx, |buffer, ctx| { + for (offset, text) in edits.into_iter().rev() { + buffer.edit(Some(offset..offset), text, Some(ctx)).unwrap(); + } + }); + + // Restore bias on selections. + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + selection.start = selection.start.bias_left(buffer); + selection.end = selection.end.bias_left(buffer); + } + self.update_selections(selections, true, ctx); + + self.end_transaction(ctx); + } + + pub fn move_line_up(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + + let app = ctx.as_ref(); + let buffer = self.buffer.read(ctx); + + let mut edits = Vec::new(); + let mut new_selection_ranges = Vec::new(); + let mut old_folds = Vec::new(); + let mut new_folds = Vec::new(); + + let mut selections = self.selections(app).iter().peekable(); + let mut contiguous_selections = Vec::new(); + while let Some(selection) = selections.next() { + // Accumulate contiguous regions of rows that we want to move. + contiguous_selections.push(selection.point_range(buffer)); + let (mut buffer_rows, mut display_rows) = + selection.buffer_rows_for_display_rows(false, &self.display_map, app); + while let Some(next_selection) = selections.peek() { + let (next_buffer_rows, next_display_rows) = + next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); + if next_buffer_rows.start <= buffer_rows.end { + buffer_rows.end = next_buffer_rows.end; + display_rows.end = next_display_rows.end; + contiguous_selections.push(next_selection.point_range(buffer)); + selections.next().unwrap(); + } else { + break; + } + } + + // Cut the text from the selected rows and paste it at the start of the previous line. + if display_rows.start != 0 { + let start = Point::new(buffer_rows.start, 0).to_offset(buffer); + let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1)) + .to_offset(buffer); + + let prev_row_display_start = DisplayPoint::new(display_rows.start - 1, 0); + let prev_row_start = + prev_row_display_start.to_buffer_offset(&self.display_map, Bias::Left, app); + + let mut text = String::new(); + text.extend(buffer.text_for_range(start..end)); + text.push('\n'); + edits.push((prev_row_start..prev_row_start, text)); + edits.push((start - 1..end, String::new())); + + let row_delta = buffer_rows.start + - prev_row_display_start + .to_buffer_point(&self.display_map, Bias::Left, app) + .row; + + // Move selections up. + for range in &mut contiguous_selections { + range.start.row -= row_delta; + range.end.row -= row_delta; + } + + // Move folds up. + old_folds.push(start..end); + for fold in self.display_map.folds_in_range(start..end, app) { + let mut start = fold.start.to_point(buffer); + let mut end = fold.end.to_point(buffer); + start.row -= row_delta; + end.row -= row_delta; + new_folds.push(start..end); + } + } + + new_selection_ranges.extend(contiguous_selections.drain(..)); + } + + self.unfold_ranges(old_folds, ctx); + self.buffer.update(ctx, |buffer, ctx| { + for (range, text) in edits.into_iter().rev() { + buffer.edit(Some(range), text, Some(ctx)).unwrap(); + } + }); + self.fold_ranges(new_folds, ctx); + self.select_ranges(new_selection_ranges, true, ctx); + + self.end_transaction(ctx); + } + + pub fn move_line_down(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + + let app = ctx.as_ref(); + let buffer = self.buffer.read(ctx); + + let mut edits = Vec::new(); + let mut new_selection_ranges = Vec::new(); + let mut old_folds = Vec::new(); + let mut new_folds = Vec::new(); + + let mut selections = self.selections(app).iter().peekable(); + let mut contiguous_selections = Vec::new(); + while let Some(selection) = selections.next() { + // Accumulate contiguous regions of rows that we want to move. + contiguous_selections.push(selection.point_range(buffer)); + let (mut buffer_rows, mut display_rows) = + selection.buffer_rows_for_display_rows(false, &self.display_map, app); + while let Some(next_selection) = selections.peek() { + let (next_buffer_rows, next_display_rows) = + next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); + if next_buffer_rows.start <= buffer_rows.end { + buffer_rows.end = next_buffer_rows.end; + display_rows.end = next_display_rows.end; + contiguous_selections.push(next_selection.point_range(buffer)); + selections.next().unwrap(); + } else { + break; + } + } + + // Cut the text from the selected rows and paste it at the end of the next line. + if display_rows.end <= self.display_map.max_point(app).row() { + let start = Point::new(buffer_rows.start, 0).to_offset(buffer); + let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1)) + .to_offset(buffer); + + let next_row_display_end = DisplayPoint::new( + display_rows.end, + self.display_map.line_len(display_rows.end, app), + ); + let next_row_end = + next_row_display_end.to_buffer_offset(&self.display_map, Bias::Right, app); + + let mut text = String::new(); + text.push('\n'); + text.extend(buffer.text_for_range(start..end)); + edits.push((start..end + 1, String::new())); + edits.push((next_row_end..next_row_end, text)); + + let row_delta = next_row_display_end + .to_buffer_point(&self.display_map, Bias::Right, app) + .row + - buffer_rows.end + + 1; + + // Move selections down. + for range in &mut contiguous_selections { + range.start.row += row_delta; + range.end.row += row_delta; + } + + // Move folds down. + old_folds.push(start..end); + for fold in self.display_map.folds_in_range(start..end, app) { + let mut start = fold.start.to_point(buffer); + let mut end = fold.end.to_point(buffer); + start.row += row_delta; + end.row += row_delta; + new_folds.push(start..end); + } + } + + new_selection_ranges.extend(contiguous_selections.drain(..)); + } + + self.unfold_ranges(old_folds, ctx); + self.buffer.update(ctx, |buffer, ctx| { + for (range, text) in edits.into_iter().rev() { + buffer.edit(Some(range), text, Some(ctx)).unwrap(); + } + }); + self.fold_ranges(new_folds, ctx); + self.select_ranges(new_selection_ranges, true, ctx); + + self.end_transaction(ctx); + } + + pub fn cut(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + let mut text = String::new(); + let mut selections = self.selections(ctx.as_ref()).to_vec(); + let mut clipboard_selections = Vec::with_capacity(selections.len()); + { + let buffer = self.buffer.read(ctx); + let max_point = buffer.max_point(); + for selection in &mut selections { + let mut start = selection.start.to_point(buffer); + let mut end = selection.end.to_point(buffer); + let is_entire_line = start == end; + if is_entire_line { + start = Point::new(start.row, 0); + end = cmp::min(max_point, Point::new(start.row + 1, 0)); + selection.start = buffer.anchor_before(start); + selection.end = buffer.anchor_before(end); + } + let mut len = 0; + for chunk in buffer.text_for_range(start..end) { + text.push_str(chunk); + len += chunk.len(); + } + clipboard_selections.push(ClipboardSelection { + len, + is_entire_line, + }); + } + } + self.update_selections(selections, true, ctx); + self.insert(&String::new(), ctx); + self.end_transaction(ctx); + + ctx.as_mut() + .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); + } + + pub fn copy(&mut self, _: &(), ctx: &mut ViewContext) { + let buffer = self.buffer.read(ctx); + let max_point = buffer.max_point(); + let mut text = String::new(); + let selections = self.selections(ctx.as_ref()); + let mut clipboard_selections = Vec::with_capacity(selections.len()); + for selection in selections { + let mut start = selection.start.to_point(buffer); + let mut end = selection.end.to_point(buffer); + let is_entire_line = start == end; + if is_entire_line { + start = Point::new(start.row, 0); + end = cmp::min(max_point, Point::new(start.row + 1, 0)); + } + let mut len = 0; + for chunk in buffer.text_for_range(start..end) { + text.push_str(chunk); + len += chunk.len(); + } + clipboard_selections.push(ClipboardSelection { + len, + is_entire_line, + }); + } + + ctx.as_mut() + .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); + } + + pub fn paste(&mut self, _: &(), ctx: &mut ViewContext) { + if let Some(item) = ctx.as_mut().read_from_clipboard() { + let clipboard_text = item.text(); + if let Some(mut clipboard_selections) = item.metadata::>() { + let selections = self.selections(ctx.as_ref()).to_vec(); + if clipboard_selections.len() != selections.len() { + let merged_selection = ClipboardSelection { + len: clipboard_selections.iter().map(|s| s.len).sum(), + is_entire_line: clipboard_selections.iter().all(|s| s.is_entire_line), + }; + clipboard_selections.clear(); + clipboard_selections.push(merged_selection); + } + + self.start_transaction(ctx); + let mut new_selections = Vec::with_capacity(selections.len()); + let mut clipboard_chars = clipboard_text.chars().cycle(); + for (selection, clipboard_selection) in + selections.iter().zip(clipboard_selections.iter().cycle()) + { + let to_insert = + String::from_iter(clipboard_chars.by_ref().take(clipboard_selection.len)); + + self.buffer.update(ctx, |buffer, ctx| { + let selection_start = selection.start.to_point(buffer); + let selection_end = selection.end.to_point(buffer); + + // If the corresponding selection was empty when this slice of the + // clipboard text was written, then the entire line containing the + // selection was copied. If this selection is also currently empty, + // then paste the line before the current line of the buffer. + let new_selection_start = selection.end.bias_right(buffer); + if selection_start == selection_end && clipboard_selection.is_entire_line { + let line_start = Point::new(selection_start.row, 0); + buffer + .edit(Some(line_start..line_start), to_insert, Some(ctx)) + .unwrap(); + } else { + buffer + .edit(Some(&selection.start..&selection.end), to_insert, Some(ctx)) + .unwrap(); + }; + + let new_selection_start = new_selection_start.bias_left(buffer); + new_selections.push(Selection { + id: selection.id, + start: new_selection_start.clone(), + end: new_selection_start, + reversed: false, + goal: SelectionGoal::None, + }); + }); + } + self.update_selections(new_selections, true, ctx); + self.end_transaction(ctx); + } else { + self.insert(clipboard_text, ctx); + } + } + } + + pub fn undo(&mut self, _: &(), ctx: &mut ViewContext) { + self.buffer + .update(ctx, |buffer, ctx| buffer.undo(Some(ctx))); + } + + pub fn redo(&mut self, _: &(), ctx: &mut ViewContext) { + self.buffer + .update(ctx, |buffer, ctx| buffer.redo(Some(ctx))); + } + + pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + for selection in &mut selections { + let start = selection.start.to_display_point(&self.display_map, app); + let end = selection.end.to_display_point(&self.display_map, app); + + if start != end { + selection.end = selection.start.clone(); + } else { + let cursor = self.display_map.anchor_before( + movement::left(&self.display_map, start, app).unwrap(), + Bias::Left, + app, + ); + selection.start = cursor.clone(); + selection.end = cursor; + } + selection.reversed = false; + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + let head = selection + .head() + .to_display_point(&self.display_map, ctx.as_ref()); + let cursor = self.display_map.anchor_before( + movement::left(&self.display_map, head, ctx.as_ref()).unwrap(), + Bias::Left, + ctx.as_ref(), + ); + selection.set_head(&buffer, cursor); + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let app = ctx.as_ref(); + for selection in &mut selections { + let start = selection.start.to_display_point(&self.display_map, app); + let end = selection.end.to_display_point(&self.display_map, app); + + if start != end { + selection.start = selection.end.clone(); + } else { + let cursor = self.display_map.anchor_before( + movement::right(&self.display_map, end, app).unwrap(), + Bias::Right, + app, + ); + selection.start = cursor.clone(); + selection.end = cursor; + } + selection.reversed = false; + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + for selection in &mut selections { + let head = selection + .head() + .to_display_point(&self.display_map, ctx.as_ref()); + let cursor = self.display_map.anchor_before( + movement::right(&self.display_map, head, app).unwrap(), + Bias::Right, + app, + ); + selection.set_head(&buffer, cursor); + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn move_up(&mut self, _: &(), ctx: &mut ViewContext) { + if self.single_line { + ctx.propagate_action(); + } else { + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let app = ctx.as_ref(); + for selection in &mut selections { + let start = selection.start.to_display_point(&self.display_map, app); + let end = selection.end.to_display_point(&self.display_map, app); + if start != end { + selection.goal = SelectionGoal::None; + } + + let (start, goal) = + movement::up(&self.display_map, start, selection.goal, app).unwrap(); + let cursor = self.display_map.anchor_before(start, Bias::Left, app); + selection.start = cursor.clone(); + selection.end = cursor; + selection.goal = goal; + selection.reversed = false; + } + } + self.update_selections(selections, true, ctx); + } + } + + pub fn select_up(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let (head, goal) = + movement::up(&self.display_map, head, selection.goal, app).unwrap(); + selection.set_head( + &buffer, + self.display_map.anchor_before(head, Bias::Left, app), + ); + selection.goal = goal; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn move_down(&mut self, _: &(), ctx: &mut ViewContext) { + if self.single_line { + ctx.propagate_action(); + } else { + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let app = ctx.as_ref(); + for selection in &mut selections { + let start = selection.start.to_display_point(&self.display_map, app); + let end = selection.end.to_display_point(&self.display_map, app); + if start != end { + selection.goal = SelectionGoal::None; + } + + let (start, goal) = + movement::down(&self.display_map, end, selection.goal, app).unwrap(); + let cursor = self.display_map.anchor_before(start, Bias::Right, app); + selection.start = cursor.clone(); + selection.end = cursor; + selection.goal = goal; + selection.reversed = false; + } + } + self.update_selections(selections, true, ctx); + } + } + + pub fn select_down(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.as_ref()).to_vec(); + { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let (head, goal) = + movement::down(&self.display_map, head, selection.goal, app).unwrap(); + selection.set_head( + &buffer, + self.display_map.anchor_before(head, Bias::Right, app), + ); + selection.goal = goal; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn move_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = movement::prev_word_boundary(&self.display_map, head, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.start = anchor.clone(); + selection.end = anchor; + selection.reversed = false; + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn select_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = movement::prev_word_boundary(&self.display_map, head, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.set_head(buffer, anchor); + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn delete_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + self.select_to_previous_word_boundary(&(), ctx); + self.backspace(&(), ctx); + self.end_transaction(ctx); + } + + pub fn move_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = movement::next_word_boundary(&self.display_map, head, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.start = anchor.clone(); + selection.end = anchor; + selection.reversed = false; + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn select_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = movement::next_word_boundary(&self.display_map, head, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.set_head(buffer, anchor); + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn delete_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + self.select_to_next_word_boundary(&(), ctx); + self.delete(&(), ctx); + self.end_transaction(ctx); + } + + pub fn move_to_beginning_of_line(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = + movement::line_beginning(&self.display_map, head, true, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.start = anchor.clone(); + selection.end = anchor; + selection.reversed = false; + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn select_to_beginning_of_line( + &mut self, + toggle_indent: &bool, + ctx: &mut ViewContext, + ) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = + movement::line_beginning(&self.display_map, head, *toggle_indent, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.set_head(buffer, anchor); + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn delete_to_beginning_of_line(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + self.select_to_beginning_of_line(&false, ctx); + self.backspace(&(), ctx); + self.end_transaction(ctx); + } + + pub fn move_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = movement::line_end(&self.display_map, head, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.start = anchor.clone(); + selection.end = anchor; + selection.reversed = false; + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn select_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let mut selections = self.selections(app).to_vec(); + { + let buffer = self.buffer.read(ctx); + for selection in &mut selections { + let head = selection.head().to_display_point(&self.display_map, app); + let new_head = movement::line_end(&self.display_map, head, app).unwrap(); + let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); + selection.set_head(buffer, anchor); + selection.goal = SelectionGoal::None; + } + } + self.update_selections(selections, true, ctx); + } + + pub fn delete_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { + self.start_transaction(ctx); + self.select_to_end_of_line(&(), ctx); + self.delete(&(), ctx); + self.end_transaction(ctx); + } + + pub fn move_to_beginning(&mut self, _: &(), ctx: &mut ViewContext) { + let buffer = self.buffer.read(ctx); + let cursor = buffer.anchor_before(Point::new(0, 0)); + let selection = Selection { + id: post_inc(&mut self.next_selection_id), + start: cursor.clone(), + end: cursor, + reversed: false, + goal: SelectionGoal::None, + }; + self.update_selections(vec![selection], true, ctx); + } + + pub fn select_to_beginning(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone(); + selection.set_head(self.buffer.read(ctx), Anchor::Start); + self.update_selections(vec![selection], true, ctx); + } + + pub fn move_to_end(&mut self, _: &(), ctx: &mut ViewContext) { + let buffer = self.buffer.read(ctx); + let cursor = buffer.anchor_before(buffer.max_point()); + let selection = Selection { + id: post_inc(&mut self.next_selection_id), + start: cursor.clone(), + end: cursor, + reversed: false, + goal: SelectionGoal::None, + }; + self.update_selections(vec![selection], true, ctx); + } + + pub fn select_to_end(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone(); + selection.set_head(self.buffer.read(ctx), Anchor::End); + self.update_selections(vec![selection], true, ctx); + } + + pub fn select_all(&mut self, _: &(), ctx: &mut ViewContext) { + let selection = Selection { + id: post_inc(&mut self.next_selection_id), + start: Anchor::Start, + end: Anchor::End, + reversed: false, + goal: SelectionGoal::None, + }; + self.update_selections(vec![selection], false, ctx); + } + + pub fn select_line(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + let mut selections = self.selections(app).to_vec(); + let max_point = buffer.max_point(); + for selection in &mut selections { + let (rows, _) = selection.buffer_rows_for_display_rows(true, &self.display_map, app); + selection.start = buffer.anchor_before(Point::new(rows.start, 0)); + selection.end = buffer.anchor_before(cmp::min(max_point, Point::new(rows.end, 0))); + selection.reversed = false; + } + self.update_selections(selections, true, ctx); + } + + pub fn split_selection_into_lines(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + + let mut to_unfold = Vec::new(); + let mut new_selections = Vec::new(); + for selection in self.selections(app) { + let range = selection.point_range(buffer).sorted(); + if range.start.row != range.end.row { + new_selections.push(Selection { + id: post_inc(&mut self.next_selection_id), + start: selection.start.clone(), + end: selection.start.clone(), + reversed: false, + goal: SelectionGoal::None, + }); + } + for row in range.start.row + 1..range.end.row { + let cursor = buffer.anchor_before(Point::new(row, buffer.line_len(row))); + new_selections.push(Selection { + id: post_inc(&mut self.next_selection_id), + start: cursor.clone(), + end: cursor, + reversed: false, + goal: SelectionGoal::None, + }); + } + new_selections.push(Selection { + id: selection.id, + start: selection.end.clone(), + end: selection.end.clone(), + reversed: false, + goal: SelectionGoal::None, + }); + to_unfold.push(range); + } + self.unfold_ranges(to_unfold, ctx); + self.update_selections(new_selections, true, ctx); + } + + pub fn add_selection_above(&mut self, _: &(), ctx: &mut ViewContext) { + self.add_selection(true, ctx); + } + + pub fn add_selection_below(&mut self, _: &(), ctx: &mut ViewContext) { + self.add_selection(false, ctx); + } + + fn add_selection(&mut self, above: bool, ctx: &mut ViewContext) { + let app = ctx.as_ref(); + + let mut selections = self.selections(app).to_vec(); + let mut state = self.add_selections_state.take().unwrap_or_else(|| { + let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); + let range = oldest_selection + .display_range(&self.display_map, app) + .sorted(); + let columns = cmp::min(range.start.column(), range.end.column()) + ..cmp::max(range.start.column(), range.end.column()); + + selections.clear(); + let mut stack = Vec::new(); + for row in range.start.row()..=range.end.row() { + if let Some(selection) = + self.build_columnar_selection(row, &columns, oldest_selection.reversed, app) + { + stack.push(selection.id); + selections.push(selection); + } + } + + if above { + stack.reverse(); + } + + AddSelectionsState { above, stack } + }); + + let last_added_selection = *state.stack.last().unwrap(); + let mut new_selections = Vec::new(); + if above == state.above { + let end_row = if above { + 0 + } else { + self.display_map.max_point(app).row() + }; + + 'outer: for selection in selections { + if selection.id == last_added_selection { + let range = selection.display_range(&self.display_map, app).sorted(); + debug_assert_eq!(range.start.row(), range.end.row()); + let mut row = range.start.row(); + let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal + { + start..end + } else { + cmp::min(range.start.column(), range.end.column()) + ..cmp::max(range.start.column(), range.end.column()) + }; + + while row != end_row { + if above { + row -= 1; + } else { + row += 1; + } + + if let Some(new_selection) = + self.build_columnar_selection(row, &columns, selection.reversed, app) + { + state.stack.push(new_selection.id); + if above { + new_selections.push(new_selection); + new_selections.push(selection); + } else { + new_selections.push(selection); + new_selections.push(new_selection); + } + + continue 'outer; + } + } + } + + new_selections.push(selection); + } + } else { + new_selections = selections; + new_selections.retain(|s| s.id != last_added_selection); + state.stack.pop(); + } + + self.update_selections(new_selections, true, ctx); + if state.stack.len() > 1 { + self.add_selections_state = Some(state); + } + } + + pub fn select_larger_syntax_node(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + + let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); + let mut selected_larger_node = false; + let old_selections = self.selections(app).to_vec(); + let mut new_selections = Vec::new(); + for selection in &old_selections { + let old_range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer); + let mut new_range = old_range.clone(); + while let Some(containing_range) = buffer.range_for_syntax_ancestor(new_range.clone()) { + new_range = containing_range; + if !self.display_map.intersects_fold(new_range.start, app) + && !self.display_map.intersects_fold(new_range.end, app) + { + break; + } + } + + selected_larger_node |= new_range != old_range; + new_selections.push(Selection { + id: selection.id, + start: buffer.anchor_before(new_range.start), + end: buffer.anchor_before(new_range.end), + reversed: selection.reversed, + goal: SelectionGoal::None, + }); + } + + if selected_larger_node { + stack.push(old_selections); + self.update_selections(new_selections, true, ctx); + } + self.select_larger_syntax_node_stack = stack; + } + + pub fn select_smaller_syntax_node(&mut self, _: &(), ctx: &mut ViewContext) { + let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); + if let Some(selections) = stack.pop() { + self.update_selections(selections, true, ctx); + } + self.select_larger_syntax_node_stack = stack; + } + + pub fn move_to_enclosing_bracket(&mut self, _: &(), ctx: &mut ViewContext) { + let buffer = self.buffer.read(ctx.as_ref()); + let mut selections = self.selections(ctx.as_ref()).to_vec(); + for selection in &mut selections { + let selection_range = selection.offset_range(buffer); + if let Some((open_range, close_range)) = + buffer.enclosing_bracket_ranges(selection_range.clone()) + { + let close_range = close_range.to_inclusive(); + let destination = if close_range.contains(&selection_range.start) + && close_range.contains(&selection_range.end) + { + open_range.end + } else { + *close_range.start() + }; + selection.start = buffer.anchor_before(destination); + selection.end = selection.start.clone(); + } + } + + self.update_selections(selections, true, ctx); + } + + fn build_columnar_selection( + &mut self, + row: u32, + columns: &Range, + reversed: bool, + ctx: &AppContext, + ) -> Option { + let is_empty = columns.start == columns.end; + let line_len = self.display_map.line_len(row, ctx); + if columns.start < line_len || (is_empty && columns.start == line_len) { + let start = DisplayPoint::new(row, columns.start); + let end = DisplayPoint::new(row, cmp::min(columns.end, line_len)); + Some(Selection { + id: post_inc(&mut self.next_selection_id), + start: self.display_map.anchor_before(start, Bias::Left, ctx), + end: self.display_map.anchor_before(end, Bias::Left, ctx), + reversed, + goal: SelectionGoal::ColumnRange { + start: columns.start, + end: columns.end, + }, + }) + } else { + None + } + } + + pub fn selections_in_range<'a>( + &'a self, + range: Range, + app: &'a AppContext, + ) -> impl 'a + Iterator> { + let start = self.display_map.anchor_before(range.start, Bias::Left, app); + let start_index = self.selection_insertion_index(&start, app); + let pending_selection = self.pending_selection.as_ref().and_then(|s| { + let selection_range = s.display_range(&self.display_map, app); + if selection_range.start <= range.end || selection_range.end <= range.end { + Some(selection_range) + } else { + None + } + }); + self.selections(app)[start_index..] + .iter() + .map(move |s| s.display_range(&self.display_map, app)) + .take_while(move |r| r.start <= range.end || r.end <= range.end) + .chain(pending_selection) + } + + fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize { + let buffer = self.buffer.read(app); + let selections = self.selections(app); + match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) { + Ok(index) => index, + Err(index) => { + if index > 0 + && selections[index - 1].end.cmp(&start, buffer).unwrap() == Ordering::Greater + { + index - 1 + } else { + index + } + } + } + } + + fn selections<'a>(&self, app: &'a AppContext) -> &'a [Selection] { + self.buffer + .read(app) + .selections(self.selection_set_id) + .unwrap() + } + + fn update_selections( + &mut self, + mut selections: Vec, + autoscroll: bool, + ctx: &mut ViewContext, + ) { + // Merge overlapping selections. + let buffer = self.buffer.read(ctx); + let mut i = 1; + while i < selections.len() { + if selections[i - 1] + .end + .cmp(&selections[i].start, buffer) + .unwrap() + >= Ordering::Equal + { + let removed = selections.remove(i); + if removed.start.cmp(&selections[i - 1].start, buffer).unwrap() < Ordering::Equal { + selections[i - 1].start = removed.start; + } + if removed.end.cmp(&selections[i - 1].end, buffer).unwrap() > Ordering::Equal { + selections[i - 1].end = removed.end; + } + } else { + i += 1; + } + } + + self.buffer.update(ctx, |buffer, ctx| { + buffer + .update_selection_set(self.selection_set_id, selections, Some(ctx)) + .unwrap() + }); + self.pause_cursor_blinking(ctx); + + if autoscroll { + *self.autoscroll_requested.lock() = true; + ctx.notify(); + } + + self.add_selections_state = None; + self.select_larger_syntax_node_stack.clear(); + } + + fn start_transaction(&self, ctx: &mut ViewContext) { + self.buffer.update(ctx, |buffer, _| { + buffer + .start_transaction(Some(self.selection_set_id)) + .unwrap() + }); + } + + fn end_transaction(&self, ctx: &mut ViewContext) { + self.buffer.update(ctx, |buffer, ctx| { + buffer + .end_transaction(Some(self.selection_set_id), Some(ctx)) + .unwrap() + }); + } + + pub fn page_up(&mut self, _: &(), _: &mut ViewContext) { + log::info!("BufferView::page_up"); + } + + pub fn page_down(&mut self, _: &(), _: &mut ViewContext) { + log::info!("BufferView::page_down"); + } + + pub fn fold(&mut self, _: &(), ctx: &mut ViewContext) { + let mut fold_ranges = Vec::new(); + + let app = ctx.as_ref(); + for selection in self.selections(app) { + let range = selection.display_range(&self.display_map, app).sorted(); + let buffer_start_row = range + .start + .to_buffer_point(&self.display_map, Bias::Left, app) + .row; + + for row in (0..=range.end.row()).rev() { + if self.is_line_foldable(row, app) + && !self.display_map.is_line_folded(row, ctx.as_ref()) + { + let fold_range = self.foldable_range_for_line(row, app); + if fold_range.end.row >= buffer_start_row { + fold_ranges.push(fold_range); + if row <= range.start.row() { + break; + } + } + } + } + } + + self.fold_ranges(fold_ranges, ctx); + } + + pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext) { + let app = ctx.as_ref(); + let buffer = self.buffer.read(app); + let ranges = self + .selections(app) + .iter() + .map(|s| { + let range = s.display_range(&self.display_map, app).sorted(); + let mut start = range + .start + .to_buffer_point(&self.display_map, Bias::Left, app); + let mut end = range + .end + .to_buffer_point(&self.display_map, Bias::Left, app); + start.column = 0; + end.column = buffer.line_len(end.row); + start..end + }) + .collect::>(); + self.unfold_ranges(ranges, ctx); + } + + fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool { + let max_point = self.max_point(app); + if display_row >= max_point.row() { + false + } else { + let (start_indent, is_blank) = self.display_map.line_indent(display_row, app); + if is_blank { + false + } else { + for display_row in display_row + 1..=max_point.row() { + let (indent, is_blank) = self.display_map.line_indent(display_row, app); + if !is_blank { + return indent > start_indent; + } + } + false + } + } + } + + fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Range { + let max_point = self.max_point(app); + + let (start_indent, _) = self.display_map.line_indent(start_row, app); + let start = DisplayPoint::new(start_row, self.line_len(start_row, app)); + let mut end = None; + for row in start_row + 1..=max_point.row() { + let (indent, is_blank) = self.display_map.line_indent(row, app); + if !is_blank && indent <= start_indent { + end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, app))); + break; + } + } + + let end = end.unwrap_or(max_point); + return start.to_buffer_point(&self.display_map, Bias::Left, app) + ..end.to_buffer_point(&self.display_map, Bias::Left, app); + } + + pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext) { + let buffer = self.buffer.read(ctx); + let ranges = self + .selections(ctx.as_ref()) + .iter() + .map(|s| s.point_range(buffer).sorted()) + .collect(); + self.fold_ranges(ranges, ctx); + } + + fn fold_ranges(&mut self, ranges: Vec>, ctx: &mut ViewContext) { + if !ranges.is_empty() { + self.display_map.fold(ranges, ctx.as_ref()); + *self.autoscroll_requested.lock() = true; + ctx.notify(); + } + } + + fn unfold_ranges(&mut self, ranges: Vec>, ctx: &mut ViewContext) { + if !ranges.is_empty() { + self.display_map.unfold(ranges, ctx.as_ref()); + *self.autoscroll_requested.lock() = true; + ctx.notify(); + } + } + + pub fn line(&self, display_row: u32, ctx: &AppContext) -> String { + self.display_map.line(display_row, ctx) + } + + pub fn line_len(&self, display_row: u32, ctx: &AppContext) -> u32 { + self.display_map.line_len(display_row, ctx) + } + + pub fn longest_row(&self, ctx: &AppContext) -> u32 { + self.display_map.longest_row(ctx) + } + + pub fn max_point(&self, ctx: &AppContext) -> DisplayPoint { + self.display_map.max_point(ctx) + } + + pub fn text(&self, ctx: &AppContext) -> String { + self.display_map.text(ctx) + } + + pub fn font_size(&self) -> f32 { + self.settings.borrow().buffer_font_size + } + + pub fn font_ascent(&self, font_cache: &FontCache) -> f32 { + let settings = self.settings.borrow(); + let font_id = font_cache.default_font(settings.buffer_font_family); + let ascent = font_cache.metric(font_id, |m| m.ascent); + font_cache.scale_metric(ascent, font_id, settings.buffer_font_size) + } + + pub fn font_descent(&self, font_cache: &FontCache) -> f32 { + let settings = self.settings.borrow(); + let font_id = font_cache.default_font(settings.buffer_font_family); + let ascent = font_cache.metric(font_id, |m| m.descent); + font_cache.scale_metric(ascent, font_id, settings.buffer_font_size) + } + + pub fn line_height(&self, font_cache: &FontCache) -> f32 { + let settings = self.settings.borrow(); + let font_id = font_cache.default_font(settings.buffer_font_family); + font_cache.line_height(font_id, settings.buffer_font_size) + } + + pub fn em_width(&self, font_cache: &FontCache) -> f32 { + let settings = self.settings.borrow(); + let font_id = font_cache.default_font(settings.buffer_font_family); + font_cache.em_width(font_id, settings.buffer_font_size) + } + + // TODO: Can we make this not return a result? + pub fn max_line_number_width( + &self, + font_cache: &FontCache, + layout_cache: &TextLayoutCache, + app: &AppContext, + ) -> Result { + let settings = self.settings.borrow(); + let font_size = settings.buffer_font_size; + let font_id = + font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; + let digit_count = (self.buffer.read(app).row_count() as f32).log10().floor() as usize + 1; + + Ok(layout_cache + .layout_str( + "1".repeat(digit_count).as_str(), + font_size, + &[(digit_count, font_id, ColorU::black())], + ) + .width()) + } + + pub fn layout_line_numbers( + &self, + viewport_height: f32, + font_cache: &FontCache, + layout_cache: &TextLayoutCache, + ctx: &AppContext, + ) -> Result> { + let settings = self.settings.borrow(); + let font_size = settings.buffer_font_size; + let font_id = + font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; + + let start_row = self.scroll_position().y() as usize; + let end_row = cmp::min( + self.max_point(ctx).row() as usize, + start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize, + ); + let line_count = end_row - start_row + 1; + + let mut layouts = Vec::with_capacity(line_count); + let mut line_number = String::new(); + for buffer_row in self + .display_map + .snapshot(ctx) + .buffer_rows(start_row as u32) + .take(line_count) + { + line_number.clear(); + write!(&mut line_number, "{}", buffer_row + 1).unwrap(); + layouts.push(layout_cache.layout_str( + &line_number, + font_size, + &[(line_number.len(), font_id, ColorU::black())], + )); + } + + Ok(layouts) + } + + pub fn layout_lines( + &self, + mut rows: Range, + font_cache: &FontCache, + layout_cache: &TextLayoutCache, + ctx: &AppContext, + ) -> Result> { + rows.end = cmp::min(rows.end, self.display_map.max_point(ctx).row() + 1); + if rows.start >= rows.end { + return Ok(Vec::new()); + } + + let settings = self.settings.borrow(); + let font_size = settings.buffer_font_size; + let font_family = settings.buffer_font_family; + let mut prev_font_properties = FontProperties::new(); + let mut prev_font_id = font_cache + .select_font(font_family, &prev_font_properties) + .unwrap(); + + let mut layouts = Vec::with_capacity(rows.len()); + let mut line = String::new(); + let mut styles = Vec::new(); + let mut row = rows.start; + let mut snapshot = self.display_map.snapshot(ctx); + let chunks = snapshot.highlighted_chunks_for_rows(rows.clone()); + let theme = settings.theme.clone(); + + 'outer: for (chunk, style_ix) in chunks.chain(Some(("\n", StyleId::default()))) { + for (ix, line_chunk) in chunk.split('\n').enumerate() { + if ix > 0 { + layouts.push(layout_cache.layout_str(&line, font_size, &styles)); + line.clear(); + styles.clear(); + row += 1; + if row == rows.end { + break 'outer; + } + } + + if !line_chunk.is_empty() { + let (color, font_properties) = theme.syntax_style(style_ix); + // Avoid a lookup if the font properties match the previous ones. + let font_id = if font_properties == prev_font_properties { + prev_font_id + } else { + font_cache.select_font(font_family, &font_properties)? + }; + line.push_str(line_chunk); + styles.push((line_chunk.len(), font_id, color)); + prev_font_id = font_id; + prev_font_properties = font_properties; + } + } + } + + Ok(layouts) + } + + pub fn layout_line( + &self, + row: u32, + font_cache: &FontCache, + layout_cache: &TextLayoutCache, + app: &AppContext, + ) -> Result { + let settings = self.settings.borrow(); + let font_id = + font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; + + let line = self.line(row, app); + + Ok(layout_cache.layout_str( + &line, + settings.buffer_font_size, + &[(self.line_len(row, app) as usize, font_id, ColorU::black())], + )) + } + + fn next_blink_epoch(&mut self) -> usize { + self.blink_epoch += 1; + self.blink_epoch + } + + fn pause_cursor_blinking(&mut self, ctx: &mut ViewContext) { + self.cursors_visible = true; + ctx.notify(); + + let epoch = self.next_blink_epoch(); + ctx.spawn(|this, mut ctx| async move { + Timer::after(CURSOR_BLINK_INTERVAL).await; + this.update(&mut ctx, |this, ctx| { + this.resume_cursor_blinking(epoch, ctx); + }) + }) + .detach(); + } + + fn resume_cursor_blinking(&mut self, epoch: usize, ctx: &mut ViewContext) { + if epoch == self.blink_epoch { + self.blinking_paused = false; + self.blink_cursors(epoch, ctx); + } + } + + fn blink_cursors(&mut self, epoch: usize, ctx: &mut ViewContext) { + if epoch == self.blink_epoch && self.focused && !self.blinking_paused { + self.cursors_visible = !self.cursors_visible; + ctx.notify(); + + let epoch = self.next_blink_epoch(); + ctx.spawn(|this, mut ctx| async move { + Timer::after(CURSOR_BLINK_INTERVAL).await; + this.update(&mut ctx, |this, ctx| this.blink_cursors(epoch, ctx)); + }) + .detach(); + } + } + + pub fn cursors_visible(&self) -> bool { + self.cursors_visible + } + + fn on_buffer_changed(&mut self, _: ModelHandle, ctx: &mut ViewContext) { + ctx.notify(); + } + + fn on_buffer_event( + &mut self, + _: ModelHandle, + event: &buffer::Event, + ctx: &mut ViewContext, + ) { + match event { + buffer::Event::Edited => ctx.emit(Event::Edited), + buffer::Event::Dirtied => ctx.emit(Event::Dirtied), + buffer::Event::Saved => ctx.emit(Event::Saved), + buffer::Event::FileHandleChanged => ctx.emit(Event::FileHandleChanged), + buffer::Event::Reloaded => ctx.emit(Event::FileHandleChanged), + buffer::Event::Reparsed => {} + } + } +} + +pub enum Event { + Activate, + Edited, + Blurred, + Dirtied, + Saved, + FileHandleChanged, +} + +impl Entity for Editor { + type Event = Event; +} + +impl View for Editor { + fn render<'a>(&self, _: &AppContext) -> ElementBox { + EditorElement::new(self.handle.clone()).boxed() + } + + fn ui_name() -> &'static str { + "BufferView" + } + + fn on_focus(&mut self, ctx: &mut ViewContext) { + self.focused = true; + self.blink_cursors(self.blink_epoch, ctx); + } + + fn on_blur(&mut self, ctx: &mut ViewContext) { + self.focused = false; + self.cursors_visible = false; + ctx.emit(Event::Blurred); + ctx.notify(); + } +} + +impl workspace::Item for Buffer { + type View = Editor; + + fn file(&self) -> Option<&FileHandle> { + self.file() + } + + fn build_view( + handle: ModelHandle, + settings: watch::Receiver, + ctx: &mut ViewContext, + ) -> Self::View { + Editor::for_buffer(handle, settings, ctx) + } +} + +impl workspace::ItemView for Editor { + fn should_activate_item_on_event(event: &Self::Event) -> bool { + matches!(event, Event::Activate) + } + + fn should_update_tab_on_event(event: &Self::Event) -> bool { + matches!( + event, + Event::Saved | Event::Dirtied | Event::FileHandleChanged + ) + } + + fn title(&self, app: &AppContext) -> std::string::String { + let filename = self + .buffer + .read(app) + .file() + .and_then(|file| file.file_name(app)); + if let Some(name) = filename { + name.to_string_lossy().into() + } else { + "untitled".into() + } + } + + fn entry_id(&self, ctx: &AppContext) -> Option<(usize, Arc)> { + self.buffer.read(ctx).file().map(|file| file.entry_id()) + } + + fn clone_on_split(&self, ctx: &mut ViewContext) -> Option + where + Self: Sized, + { + let clone = Editor::for_buffer(self.buffer.clone(), self.settings.clone(), ctx); + *clone.scroll_position.lock() = *self.scroll_position.lock(); + Some(clone) + } + + fn save( + &mut self, + new_file: Option, + ctx: &mut ViewContext, + ) -> Task> { + self.buffer.update(ctx, |b, ctx| b.save(new_file, ctx)) + } + + fn is_dirty(&self, ctx: &AppContext) -> bool { + self.buffer.read(ctx).is_dirty() + } + + fn has_conflict(&self, ctx: &AppContext) -> bool { + self.buffer.read(ctx).has_conflict() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + editor::Point, + settings, + test::{build_app_state, sample_text}, + }; + use buffer::History; + use unindent::Unindent; + + #[gpui::test] + fn test_selection_with_mouse(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, buffer_view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + + buffer_view.update(app, |view, ctx| { + view.begin_selection(DisplayPoint::new(2, 2), false, ctx); + }); + + let view = buffer_view.read(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] + ); + + buffer_view.update(app, |view, ctx| { + view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); + }); + + let view = buffer_view.read(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + ); + + buffer_view.update(app, |view, ctx| { + view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); + }); + + let view = buffer_view.read(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] + ); + + buffer_view.update(app, |view, ctx| { + view.end_selection(ctx); + view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); + }); + + let view = buffer_view.read(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] + ); + + buffer_view.update(app, |view, ctx| { + view.begin_selection(DisplayPoint::new(3, 3), true, ctx); + view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx); + }); + + let view = buffer_view.read(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [ + DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0) + ] + ); + + buffer_view.update(app, |view, ctx| { + view.end_selection(ctx); + }); + + let view = buffer_view.read(app); + let selections = view + .selections_in_range( + DisplayPoint::zero()..view.max_point(app.as_ref()), + app.as_ref(), + ) + .collect::>(); + assert_eq!( + selections, + [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)] + ); + } + + #[gpui::test] + fn test_canceling_pending_selection(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + + view.update(app, |view, ctx| { + view.begin_selection(DisplayPoint::new(2, 2), false, ctx); + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] + ); + + view.update(app, |view, ctx| { + view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + ); + + view.update(app, |view, ctx| { + view.cancel(&(), ctx); + view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] + ); + } + + #[gpui::test] + fn test_cancel(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + + view.update(app, |view, ctx| { + view.begin_selection(DisplayPoint::new(3, 4), false, ctx); + view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); + view.end_selection(ctx); + + view.begin_selection(DisplayPoint::new(0, 1), true, ctx); + view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), ctx); + view.end_selection(ctx); + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1), + ] + ); + + view.update(app, |view, ctx| view.cancel(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)] + ); + + view.update(app, |view, ctx| view.cancel(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)] + ); + } + + #[gpui::test] + fn test_layout_line_numbers(app: &mut gpui::MutableAppContext) { + let layout_cache = TextLayoutCache::new(app.platform().fonts()); + let font_cache = app.font_cache().clone(); + + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); + + let settings = settings::channel(&font_cache).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + + let layouts = view + .read(app) + .layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref()) + .unwrap(); + assert_eq!(layouts.len(), 6); + } + + #[gpui::test] + fn test_fold(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| { + Buffer::new( + 0, + " + impl Foo { + // Hello! + + fn a() { + 1 + } + + fn b() { + 2 + } + + fn c() { + 3 + } + } + " + .unindent(), + ctx, + ) + }); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], ctx) + .unwrap(); + view.fold(&(), ctx); + assert_eq!( + view.text(ctx.as_ref()), + " + impl Foo { + // Hello! + + fn a() { + 1 + } + + fn b() {… + } + + fn c() {… + } + } + " + .unindent(), + ); + + view.fold(&(), ctx); + assert_eq!( + view.text(ctx.as_ref()), + " + impl Foo {… + } + " + .unindent(), + ); + + view.unfold(&(), ctx); + assert_eq!( + view.text(ctx.as_ref()), + " + impl Foo { + // Hello! + + fn a() { + 1 + } + + fn b() {… + } + + fn c() {… + } + } + " + .unindent(), + ); + + view.unfold(&(), ctx); + assert_eq!(view.text(ctx.as_ref()), buffer.read(ctx).text()); + }); + } + + #[gpui::test] + fn test_move_cursor(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + + buffer.update(app, |buffer, ctx| { + buffer + .edit( + vec![ + Point::new(1, 0)..Point::new(1, 0), + Point::new(1, 1)..Point::new(1, 1), + ], + "\t", + Some(ctx), + ) + .unwrap(); + }); + + view.update(app, |view, ctx| { + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] + ); + + view.move_down(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] + ); + + view.move_right(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] + ); + + view.move_left(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] + ); + + view.move_up(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] + ); + + view.move_to_end(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)] + ); + + view.move_to_beginning(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] + ); + + view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], ctx) + .unwrap(); + view.select_to_beginning(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)] + ); + + view.select_to_end(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)] + ); + }); + } + + #[gpui::test] + fn test_move_cursor_multibyte(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + + assert_eq!('ⓐ'.len_utf8(), 3); + assert_eq!('α'.len_utf8(), 2); + + view.update(app, |view, ctx| { + view.fold_ranges( + vec![ + Point::new(0, 6)..Point::new(0, 12), + Point::new(1, 2)..Point::new(1, 4), + Point::new(2, 4)..Point::new(2, 8), + ], + ctx, + ); + assert_eq!(view.text(ctx.as_ref()), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n"); + + view.move_right(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(0, "ⓐ".len())] + ); + view.move_right(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(0, "ⓐⓑ".len())] + ); + view.move_right(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(0, "ⓐⓑ…".len())] + ); + + view.move_down(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(1, "ab…".len())] + ); + view.move_left(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(1, "ab".len())] + ); + view.move_left(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(1, "a".len())] + ); + + view.move_down(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(2, "α".len())] + ); + view.move_right(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(2, "αβ".len())] + ); + view.move_right(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(2, "αβ…".len())] + ); + view.move_right(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(2, "αβ…ε".len())] + ); + + view.move_up(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(1, "ab…e".len())] + ); + view.move_up(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(0, "ⓐⓑ…ⓔ".len())] + ); + view.move_left(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(0, "ⓐⓑ…".len())] + ); + view.move_left(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(0, "ⓐⓑ".len())] + ); + view.move_left(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(0, "ⓐ".len())] + ); + }); + } + + #[gpui::test] + fn test_move_cursor_different_line_lengths(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], ctx) + .unwrap(); + + view.move_down(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(1, "abcd".len())] + ); + + view.move_down(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(2, "αβγ".len())] + ); + + view.move_down(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(3, "abcd".len())] + ); + + view.move_down(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())] + ); + + view.move_up(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(3, "abcd".len())] + ); + + view.move_up(&(), ctx); + assert_eq!( + view.selection_ranges(ctx.as_ref()), + &[empty_range(2, "αβγ".len())] + ); + }); + } + + #[gpui::test] + fn test_beginning_end_of_line(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "abc\n def", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), + ], + ctx, + ) + .unwrap(); + }); + + view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + ] + ); + + view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); + + view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + ] + ); + + view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + ] + ); + + // Moving to the end of line again is a no-op. + view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + ] + ); + + view.update(app, |view, ctx| { + view.move_left(&(), ctx); + view.select_to_beginning_of_line(&true, ctx); + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), + ] + ); + + view.update(app, |view, ctx| { + view.select_to_beginning_of_line(&true, ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0), + ] + ); + + view.update(app, |view, ctx| { + view.select_to_beginning_of_line(&true, ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), + ] + ); + + view.update(app, |view, ctx| view.select_to_end_of_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5), + ] + ); + + view.update(app, |view, ctx| view.delete_to_end_of_line(&(), ctx)); + assert_eq!(view.read(app).text(app.as_ref()), "ab\n de"); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), + ] + ); + + view.update(app, |view, ctx| view.delete_to_beginning_of_line(&(), ctx)); + assert_eq!(view.read(app).text(app.as_ref()), "\n"); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); + } + + #[gpui::test] + fn test_prev_next_word_boundary(app: &mut gpui::MutableAppContext) { + let buffer = + app.add_model(|ctx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11), + DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4), + ], + ctx, + ) + .unwrap(); + }); + + view.update(app, |view, ctx| { + view.move_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), + ] + ); + + view.update(app, |view, ctx| { + view.move_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), + DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), + ] + ); + + view.update(app, |view, ctx| { + view.move_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), + DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), + ] + ); + + view.update(app, |view, ctx| { + view.move_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); + + view.update(app, |view, ctx| { + view.move_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), + ] + ); + + view.update(app, |view, ctx| { + view.move_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23), + ] + ); + + view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), + ] + ); + + view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + ] + ); + + view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), + DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), + ] + ); + + view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), + ] + ); + + view.update(app, |view, ctx| { + view.move_right(&(), ctx); + view.select_to_previous_word_boundary(&(), ctx); + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), + ] + ); + + view.update(app, |view, ctx| { + view.select_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0), + ] + ); + + view.update(app, |view, ctx| view.select_to_next_word_boundary(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), + ] + ); + + view.update(app, |view, ctx| view.delete_to_next_word_boundary(&(), ctx)); + assert_eq!( + view.read(app).text(app.as_ref()), + "use std::s::{foo, bar}\n\n {az.qux()}" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10), + DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), + ] + ); + + view.update(app, |view, ctx| { + view.delete_to_previous_word_boundary(&(), ctx) + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "use std::::{foo, bar}\n\n az.qux()}" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), + DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), + ] + ); + } + + #[gpui::test] + fn test_backspace(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| { + Buffer::new( + 0, + "one two three\nfour five six\nseven eight nine\nten\n", + ctx, + ) + }); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + // an empty selection - the preceding character is deleted + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + // one character selected - it is deleted + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), + // a line suffix selected - it is deleted + DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0), + ], + ctx, + ) + .unwrap(); + view.backspace(&(), ctx); + }); + + assert_eq!( + buffer.read(app).text(), + "oe two three\nfou five six\nseven ten\n" + ); + } + + #[gpui::test] + fn test_delete(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| { + Buffer::new( + 0, + "one two three\nfour five six\nseven eight nine\nten\n", + ctx, + ) + }); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + // an empty selection - the following character is deleted + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + // one character selected - it is deleted + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), + // a line suffix selected - it is deleted + DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0), + ], + ctx, + ) + .unwrap(); + view.delete(&(), ctx); + }); + + assert_eq!( + buffer.read(app).text(), + "on two three\nfou five six\nseven ten\n" + ); + } + + #[gpui::test] + fn test_delete_line(app: &mut gpui::MutableAppContext) { + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + ], + ctx, + ) + .unwrap(); + view.delete_line(&(), ctx); + }); + assert_eq!(view.read(app).text(app.as_ref()), "ghi"); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1) + ] + ); + + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], ctx) + .unwrap(); + view.delete_line(&(), ctx); + }); + assert_eq!(view.read(app).text(app.as_ref()), "ghi\n"); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] + ); + } + + #[gpui::test] + fn test_duplicate_line(app: &mut gpui::MutableAppContext) { + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + ], + ctx, + ) + .unwrap(); + view.duplicate_line(&(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "abc\nabc\ndef\ndef\nghi\n\n" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), + DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), + DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0), + ] + ); + + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1), + ], + ctx, + ) + .unwrap(); + view.duplicate_line(&(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "abc\ndef\nghi\nabc\ndef\nghi\n" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1), + DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1), + ] + ); + } + + #[gpui::test] + fn test_move_line_up_down(app: &mut gpui::MutableAppContext) { + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(10, 5), ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.fold_ranges( + vec![ + Point::new(0, 2)..Point::new(1, 2), + Point::new(2, 3)..Point::new(4, 1), + Point::new(7, 0)..Point::new(8, 4), + ], + ctx, + ); + view.select_display_ranges( + &[ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), + DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2), + ], + ctx, + ) + .unwrap(); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj" + ); + + view.update(app, |view, ctx| view.move_line_up(&(), ctx)); + assert_eq!( + view.read(app).text(app.as_ref()), + "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), + DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) + ] + ); + + view.update(app, |view, ctx| view.move_line_down(&(), ctx)); + assert_eq!( + view.read(app).text(app.as_ref()), + "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), + DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) + ] + ); + + view.update(app, |view, ctx| view.move_line_down(&(), ctx)); + assert_eq!( + view.read(app).text(app.as_ref()), + "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), + DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) + ] + ); + + view.update(app, |view, ctx| view.move_line_up(&(), ctx)); + assert_eq!( + view.read(app).text(app.as_ref()), + "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), + DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) + ] + ); + } + + #[gpui::test] + fn test_clipboard(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let view = app + .add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)) + .1; + + // Cut with three selections. Clipboard text is divided into three slices. + view.update(app, |view, ctx| { + view.select_ranges(vec![0..4, 8..14, 19..24], false, ctx); + view.cut(&(), ctx); + }); + assert_eq!(view.read(app).text(app.as_ref()), "two four six "); + + // Paste with three cursors. Each cursor pastes one slice of the clipboard text. + view.update(app, |view, ctx| { + view.select_ranges(vec![4..4, 9..9, 13..13], false, ctx); + view.paste(&(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "two one four three six five " + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8), + DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19), + DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28) + ] + ); + + // Paste again but with only two cursors. Since the number of cursors doesn't + // match the number of slices in the clipboard, the entire clipboard text + // is pasted at each cursor. + view.update(app, |view, ctx| { + view.select_ranges(vec![0..0, 28..28], false, ctx); + view.insert(&"( ".to_string(), ctx); + view.paste(&(), ctx); + view.insert(&") ".to_string(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "( one three five ) two one four three six five ( one three five ) " + ); + + view.update(app, |view, ctx| { + view.select_ranges(vec![0..0], false, ctx); + view.insert(&"123\n4567\n89\n".to_string(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) " + ); + + // Cut with three selections, one of which is full-line. + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1), + ], + ctx, + ) + .unwrap(); + view.cut(&(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "13\n9\n( one three five ) two one four three six five ( one three five ) " + ); + + // Paste with three selections, noticing how the copied selection that was full-line + // gets inserted before the second cursor. + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3), + ], + ctx, + ) + .unwrap(); + view.paste(&(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) " + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3), + ] + ); + + // Copy with a single cursor only, which writes the whole line into the clipboard. + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], ctx) + .unwrap(); + view.copy(&(), ctx); + }); + + // Paste with three selections, noticing how the copied full-line selection is inserted + // before the empty selections but replaces the selection that is non-empty. + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2), + DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), + ], + ctx, + ) + .unwrap(); + view.paste(&(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "123\n123\n123\n67\n123\n9\n( 8ne three five ) two one four three six five ( one three five ) " + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[ + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1), + ] + ); + } + + #[gpui::test] + fn test_select_all(app: &mut gpui::MutableAppContext) { + let buffer = app.add_model(|ctx| Buffer::new(0, "abc\nde\nfgh", ctx)); + let settings = settings::channel(&app.font_cache()).unwrap().1; + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |b, ctx| b.select_all(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)] + ); + } + + #[gpui::test] + fn test_select_line(app: &mut gpui::MutableAppContext) { + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 5), ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2), + ], + ctx, + ) + .unwrap(); + view.select_line(&(), ctx); + }); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0), + DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0), + ] + ); + + view.update(app, |view, ctx| view.select_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0), + DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5), + ] + ); + + view.update(app, |view, ctx| view.select_line(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)] + ); + } + + #[gpui::test] + fn test_split_selection_into_lines(app: &mut gpui::MutableAppContext) { + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(9, 5), ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + view.update(app, |view, ctx| { + view.fold_ranges( + vec![ + Point::new(0, 2)..Point::new(1, 2), + Point::new(2, 3)..Point::new(4, 1), + Point::new(7, 0)..Point::new(8, 4), + ], + ctx, + ); + view.select_display_ranges( + &[ + DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4), + ], + ctx, + ) + .unwrap(); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "aa…bbb\nccc…eeee\nfffff\nggggg\n…i" + ); + + view.update(app, |view, ctx| view.split_selection_into_lines(&(), ctx)); + assert_eq!( + view.read(app).text(app.as_ref()), + "aa…bbb\nccc…eeee\nfffff\nggggg\n…i" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), + DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), + DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4) + ] + ); + + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)], ctx) + .unwrap(); + view.split_selection_into_lines(&(), ctx); + }); + assert_eq!( + view.read(app).text(app.as_ref()), + "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i" + ); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + [ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), + DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5), + DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5), + DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5), + DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5), + DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5), + DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0) + ] + ); + } + + #[gpui::test] + fn test_add_selection_above_below(app: &mut gpui::MutableAppContext) { + let settings = settings::channel(&app.font_cache()).unwrap().1; + let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", ctx)); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], ctx) + .unwrap(); + }); + view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) + ] + ); + + view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) + ] + ); + + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)] + ); + + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) + ] + ); + + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) + ] + ); + + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], ctx) + .unwrap(); + }); + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) + ] + ); + + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), + DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) + ] + ); + + view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] + ); + + view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] + ); + + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], ctx) + .unwrap(); + }); + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), + ] + ); + + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), + DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4), + ] + ); + + view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), + DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), + DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), + ] + ); + + view.update(app, |view, ctx| { + view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], ctx) + .unwrap(); + }); + view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1), + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), + ] + ); + + view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + assert_eq!( + view.read(app).selection_ranges(app.as_ref()), + vec![ + DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), + DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), + DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), + ] + ); + } + + #[gpui::test] + async fn test_select_larger_smaller_syntax_node(mut app: gpui::TestAppContext) { + let app_state = app.read(build_app_state); + let lang = app_state.language_registry.select_language("z.rs"); + let text = r#" + use mod1::mod2::{mod3, mod4}; + + fn fn_1(param1: bool, param2: &str) { + let var1 = "text"; + } + "# + .unindent(); + let buffer = app.add_model(|ctx| { + let history = History::new(text.into()); + Buffer::from_history(0, history, None, lang.cloned(), ctx) + }); + let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, app_state.settings, ctx)); + view.condition(&app, |view, ctx| !view.buffer.read(ctx).is_parsing()) + .await; + + view.update(&mut app, |view, ctx| { + view.select_display_ranges( + &[ + DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), + DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), + DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + ], + ctx, + ) + .unwrap(); + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), + DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), + DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), + DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] + ); + + // Trying to expand the selected syntax node one more time has no effect. + view.update(&mut app, |view, ctx| { + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] + ); + + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), + DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), + DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), + DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), + ] + ); + + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), + DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), + DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + ] + ); + + // Trying to shrink the selected syntax node one more time has no effect. + view.update(&mut app, |view, ctx| { + view.select_smaller_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), + DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), + DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), + ] + ); + + // Ensure that we keep expanding the selection if the larger selection starts or ends within + // a fold. + view.update(&mut app, |view, ctx| { + view.fold_ranges( + vec![ + Point::new(0, 21)..Point::new(0, 24), + Point::new(3, 20)..Point::new(3, 22), + ], + ctx, + ); + view.select_larger_syntax_node(&(), ctx); + }); + assert_eq!( + view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + &[ + DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), + DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), + DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23), + ] + ); + } + + impl Editor { + fn selection_ranges(&self, app: &AppContext) -> Vec> { + self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app) + .collect::>() + } + } + + fn empty_range(row: usize, column: usize) -> Range { + let point = DisplayPoint::new(row as u32, column as u32); + point..point + } +} + #[derive(Copy, Clone)] pub enum Bias { Left, diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs deleted file mode 100644 index 2381a22ad87c3441f71bfc3ac1bb495e79b11273..0000000000000000000000000000000000000000 --- a/zed/src/editor/buffer_view.rs +++ /dev/null @@ -1,4118 +0,0 @@ -use super::{ - buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point, - Selection, SelectionGoal, SelectionSetId, ToOffset, ToPoint, -}; -use crate::{ - settings::{Settings, StyleId}, - util::post_inc, - workspace, - worktree::FileHandle, -}; -use anyhow::Result; -use gpui::{ - color::ColorU, fonts::Properties as FontProperties, geometry::vector::Vector2F, - keymap::Binding, text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, - FontCache, ModelHandle, MutableAppContext, Task, TextLayoutCache, View, ViewContext, - WeakViewHandle, -}; -use parking_lot::Mutex; -use postage::watch; -use serde::{Deserialize, Serialize}; -use smallvec::SmallVec; -use smol::Timer; -use std::{ - cmp::{self, Ordering}, - fmt::Write, - iter::FromIterator, - mem, - ops::Range, - path::Path, - sync::Arc, - time::Duration, -}; - -const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); - -pub fn init(app: &mut MutableAppContext) { - app.add_bindings(vec![ - Binding::new("escape", "buffer:cancel", Some("BufferView")), - Binding::new("backspace", "buffer:backspace", Some("BufferView")), - Binding::new("ctrl-h", "buffer:backspace", Some("BufferView")), - Binding::new("delete", "buffer:delete", Some("BufferView")), - Binding::new("ctrl-d", "buffer:delete", Some("BufferView")), - Binding::new("enter", "buffer:newline", Some("BufferView")), - Binding::new("tab", "buffer:insert", Some("BufferView")).with_arg("\t".to_string()), - Binding::new("ctrl-shift-K", "buffer:delete_line", Some("BufferView")), - Binding::new( - "alt-backspace", - "buffer:delete_to_previous_word_boundary", - Some("BufferView"), - ), - Binding::new( - "alt-delete", - "buffer:delete_to_next_word_boundary", - Some("BufferView"), - ), - Binding::new( - "cmd-backspace", - "buffer:delete_to_beginning_of_line", - Some("BufferView"), - ), - Binding::new( - "cmd-delete", - "buffer:delete_to_end_of_line", - Some("BufferView"), - ), - Binding::new("cmd-shift-D", "buffer:duplicate_line", Some("BufferView")), - Binding::new("ctrl-cmd-up", "buffer:move_line_up", Some("BufferView")), - Binding::new("ctrl-cmd-down", "buffer:move_line_down", Some("BufferView")), - Binding::new("cmd-x", "buffer:cut", Some("BufferView")), - Binding::new("cmd-c", "buffer:copy", Some("BufferView")), - Binding::new("cmd-v", "buffer:paste", Some("BufferView")), - Binding::new("cmd-z", "buffer:undo", Some("BufferView")), - Binding::new("cmd-shift-Z", "buffer:redo", Some("BufferView")), - Binding::new("up", "buffer:move_up", Some("BufferView")), - Binding::new("down", "buffer:move_down", Some("BufferView")), - Binding::new("left", "buffer:move_left", Some("BufferView")), - Binding::new("right", "buffer:move_right", Some("BufferView")), - Binding::new("ctrl-p", "buffer:move_up", Some("BufferView")), - Binding::new("ctrl-n", "buffer:move_down", Some("BufferView")), - Binding::new("ctrl-b", "buffer:move_left", Some("BufferView")), - Binding::new("ctrl-f", "buffer:move_right", Some("BufferView")), - Binding::new( - "alt-left", - "buffer:move_to_previous_word_boundary", - Some("BufferView"), - ), - Binding::new( - "alt-right", - "buffer:move_to_next_word_boundary", - Some("BufferView"), - ), - Binding::new( - "cmd-left", - "buffer:move_to_beginning_of_line", - Some("BufferView"), - ), - Binding::new( - "ctrl-a", - "buffer:move_to_beginning_of_line", - Some("BufferView"), - ), - Binding::new( - "cmd-right", - "buffer:move_to_end_of_line", - Some("BufferView"), - ), - Binding::new("ctrl-e", "buffer:move_to_end_of_line", Some("BufferView")), - Binding::new("cmd-up", "buffer:move_to_beginning", Some("BufferView")), - Binding::new("cmd-down", "buffer:move_to_end", Some("BufferView")), - Binding::new("shift-up", "buffer:select_up", Some("BufferView")), - Binding::new("shift-down", "buffer:select_down", Some("BufferView")), - Binding::new("shift-left", "buffer:select_left", Some("BufferView")), - Binding::new("shift-right", "buffer:select_right", Some("BufferView")), - Binding::new( - "alt-shift-left", - "buffer:select_to_previous_word_boundary", - Some("BufferView"), - ), - Binding::new( - "alt-shift-right", - "buffer:select_to_next_word_boundary", - Some("BufferView"), - ), - Binding::new( - "cmd-shift-left", - "buffer:select_to_beginning_of_line", - Some("BufferView"), - ) - .with_arg(true), - Binding::new( - "ctrl-shift-A", - "buffer:select_to_beginning_of_line", - Some("BufferView"), - ) - .with_arg(true), - Binding::new( - "cmd-shift-right", - "buffer:select_to_end_of_line", - Some("BufferView"), - ), - Binding::new( - "ctrl-shift-E", - "buffer:select_to_end_of_line", - Some("BufferView"), - ), - Binding::new( - "cmd-shift-up", - "buffer:select_to_beginning", - Some("BufferView"), - ), - Binding::new("cmd-shift-down", "buffer:select_to_end", Some("BufferView")), - Binding::new("cmd-a", "buffer:select_all", Some("BufferView")), - Binding::new("cmd-l", "buffer:select_line", Some("BufferView")), - Binding::new( - "cmd-shift-L", - "buffer:split_selection_into_lines", - Some("BufferView"), - ), - Binding::new( - "cmd-alt-up", - "buffer:add_selection_above", - Some("BufferView"), - ), - Binding::new( - "cmd-alt-down", - "buffer:add_selection_below", - Some("BufferView"), - ), - Binding::new( - "alt-up", - "buffer:select_larger_syntax_node", - Some("BufferView"), - ), - Binding::new( - "alt-down", - "buffer:select_smaller_syntax_node", - Some("BufferView"), - ), - Binding::new( - "ctrl-m", - "buffer:move_to_enclosing_bracket", - Some("BufferView"), - ), - Binding::new("pageup", "buffer:page_up", Some("BufferView")), - Binding::new("pagedown", "buffer:page_down", Some("BufferView")), - Binding::new("alt-cmd-[", "buffer:fold", Some("BufferView")), - Binding::new("alt-cmd-]", "buffer:unfold", Some("BufferView")), - Binding::new( - "alt-cmd-f", - "buffer:fold_selected_ranges", - Some("BufferView"), - ), - ]); - - app.add_action("buffer:scroll", BufferView::scroll); - app.add_action("buffer:select", BufferView::select); - app.add_action("buffer:cancel", BufferView::cancel); - app.add_action("buffer:insert", BufferView::insert); - app.add_action("buffer:newline", BufferView::newline); - app.add_action("buffer:backspace", BufferView::backspace); - app.add_action("buffer:delete", BufferView::delete); - app.add_action("buffer:delete_line", BufferView::delete_line); - app.add_action( - "buffer:delete_to_previous_word_boundary", - BufferView::delete_to_previous_word_boundary, - ); - app.add_action( - "buffer:delete_to_next_word_boundary", - BufferView::delete_to_next_word_boundary, - ); - app.add_action( - "buffer:delete_to_beginning_of_line", - BufferView::delete_to_beginning_of_line, - ); - app.add_action( - "buffer:delete_to_end_of_line", - BufferView::delete_to_end_of_line, - ); - app.add_action("buffer:duplicate_line", BufferView::duplicate_line); - app.add_action("buffer:move_line_up", BufferView::move_line_up); - app.add_action("buffer:move_line_down", BufferView::move_line_down); - app.add_action("buffer:cut", BufferView::cut); - app.add_action("buffer:copy", BufferView::copy); - app.add_action("buffer:paste", BufferView::paste); - app.add_action("buffer:undo", BufferView::undo); - app.add_action("buffer:redo", BufferView::redo); - app.add_action("buffer:move_up", BufferView::move_up); - app.add_action("buffer:move_down", BufferView::move_down); - app.add_action("buffer:move_left", BufferView::move_left); - app.add_action("buffer:move_right", BufferView::move_right); - app.add_action( - "buffer:move_to_previous_word_boundary", - BufferView::move_to_previous_word_boundary, - ); - app.add_action( - "buffer:move_to_next_word_boundary", - BufferView::move_to_next_word_boundary, - ); - app.add_action( - "buffer:move_to_beginning_of_line", - BufferView::move_to_beginning_of_line, - ); - app.add_action( - "buffer:move_to_end_of_line", - BufferView::move_to_end_of_line, - ); - app.add_action("buffer:move_to_beginning", BufferView::move_to_beginning); - app.add_action("buffer:move_to_end", BufferView::move_to_end); - app.add_action("buffer:select_up", BufferView::select_up); - app.add_action("buffer:select_down", BufferView::select_down); - app.add_action("buffer:select_left", BufferView::select_left); - app.add_action("buffer:select_right", BufferView::select_right); - app.add_action( - "buffer:select_to_previous_word_boundary", - BufferView::select_to_previous_word_boundary, - ); - app.add_action( - "buffer:select_to_next_word_boundary", - BufferView::select_to_next_word_boundary, - ); - app.add_action( - "buffer:select_to_beginning_of_line", - BufferView::select_to_beginning_of_line, - ); - app.add_action( - "buffer:select_to_end_of_line", - BufferView::select_to_end_of_line, - ); - app.add_action( - "buffer:select_to_beginning", - BufferView::select_to_beginning, - ); - app.add_action("buffer:select_to_end", BufferView::select_to_end); - app.add_action("buffer:select_all", BufferView::select_all); - app.add_action("buffer:select_line", BufferView::select_line); - app.add_action( - "buffer:split_selection_into_lines", - BufferView::split_selection_into_lines, - ); - app.add_action( - "buffer:add_selection_above", - BufferView::add_selection_above, - ); - app.add_action( - "buffer:add_selection_below", - BufferView::add_selection_below, - ); - app.add_action( - "buffer:select_larger_syntax_node", - BufferView::select_larger_syntax_node, - ); - app.add_action( - "buffer:select_smaller_syntax_node", - BufferView::select_smaller_syntax_node, - ); - app.add_action( - "buffer:move_to_enclosing_bracket", - BufferView::move_to_enclosing_bracket, - ); - app.add_action("buffer:page_up", BufferView::page_up); - app.add_action("buffer:page_down", BufferView::page_down); - app.add_action("buffer:fold", BufferView::fold); - app.add_action("buffer:unfold", BufferView::unfold); - app.add_action( - "buffer:fold_selected_ranges", - BufferView::fold_selected_ranges, - ); -} - -pub enum SelectAction { - Begin { - position: DisplayPoint, - add: bool, - }, - Update { - position: DisplayPoint, - scroll_position: Vector2F, - }, - End, -} - -pub struct BufferView { - handle: WeakViewHandle, - buffer: ModelHandle, - display_map: DisplayMap, - selection_set_id: SelectionSetId, - pending_selection: Option, - next_selection_id: usize, - add_selections_state: Option, - select_larger_syntax_node_stack: Vec>, - scroll_position: Mutex, - autoscroll_requested: Mutex, - settings: watch::Receiver, - focused: bool, - cursors_visible: bool, - blink_epoch: usize, - blinking_paused: bool, - single_line: bool, -} - -struct AddSelectionsState { - above: bool, - stack: Vec, -} - -#[derive(Serialize, Deserialize)] -struct ClipboardSelection { - len: usize, - is_entire_line: bool, -} - -impl BufferView { - pub fn single_line(settings: watch::Receiver, ctx: &mut ViewContext) -> Self { - let buffer = ctx.add_model(|ctx| Buffer::new(0, String::new(), ctx)); - let mut view = Self::for_buffer(buffer, settings, ctx); - view.single_line = true; - view - } - - pub fn for_buffer( - buffer: ModelHandle, - settings: watch::Receiver, - ctx: &mut ViewContext, - ) -> Self { - ctx.observe_model(&buffer, Self::on_buffer_changed); - ctx.subscribe_to_model(&buffer, Self::on_buffer_event); - let display_map = DisplayMap::new(buffer.clone(), settings.borrow().tab_size, ctx.as_ref()); - - let mut next_selection_id = 0; - let (selection_set_id, _) = buffer.update(ctx, |buffer, ctx| { - buffer.add_selection_set( - vec![Selection { - id: post_inc(&mut next_selection_id), - start: buffer.anchor_before(0), - end: buffer.anchor_before(0), - reversed: false, - goal: SelectionGoal::None, - }], - Some(ctx), - ) - }); - Self { - handle: ctx.handle().downgrade(), - buffer, - display_map, - selection_set_id, - pending_selection: None, - next_selection_id, - add_selections_state: None, - select_larger_syntax_node_stack: Vec::new(), - scroll_position: Mutex::new(Vector2F::zero()), - autoscroll_requested: Mutex::new(false), - settings, - focused: false, - cursors_visible: false, - blink_epoch: 0, - blinking_paused: false, - single_line: false, - } - } - - pub fn buffer(&self) -> &ModelHandle { - &self.buffer - } - - pub fn is_gutter_visible(&self) -> bool { - !self.single_line - } - - fn scroll(&mut self, scroll_position: &Vector2F, ctx: &mut ViewContext) { - *self.scroll_position.lock() = *scroll_position; - ctx.notify(); - } - - pub fn scroll_position(&self) -> Vector2F { - *self.scroll_position.lock() - } - - pub fn clamp_scroll_left(&self, max: f32) { - let mut scroll_position = self.scroll_position.lock(); - let scroll_left = scroll_position.x(); - scroll_position.set_x(scroll_left.min(max)); - } - - pub fn autoscroll_vertically( - &self, - viewport_height: f32, - line_height: f32, - app: &AppContext, - ) -> bool { - let mut scroll_position = self.scroll_position.lock(); - let scroll_top = scroll_position.y(); - scroll_position.set_y(scroll_top.min(self.max_point(app).row().saturating_sub(1) as f32)); - - let mut autoscroll_requested = self.autoscroll_requested.lock(); - if *autoscroll_requested { - *autoscroll_requested = false; - } else { - return false; - } - - let visible_lines = viewport_height / line_height; - let first_cursor_top = self - .selections(app) - .first() - .unwrap() - .head() - .to_display_point(&self.display_map, app) - .row() as f32; - let last_cursor_bottom = self - .selections(app) - .last() - .unwrap() - .head() - .to_display_point(&self.display_map, app) - .row() as f32 - + 1.0; - - let margin = ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0) - .floor() - .min(3.0); - 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); - } else if target_bottom >= end_row { - scroll_position.set_y(target_bottom - visible_lines); - } - - true - } - - pub fn autoscroll_horizontally( - &self, - start_row: u32, - viewport_width: f32, - scroll_width: f32, - max_glyph_width: f32, - layouts: &[text_layout::Line], - ctx: &AppContext, - ) { - let mut target_left = std::f32::INFINITY; - let mut target_right = 0.0_f32; - for selection in self.selections(ctx) { - let head = selection.head().to_display_point(&self.display_map, ctx); - let start_column = head.column().saturating_sub(3); - let end_column = cmp::min( - self.display_map.line_len(head.row(), ctx), - head.column() + 3, - ); - target_left = target_left - .min(layouts[(head.row() - start_row) as usize].x_for_index(start_column as usize)); - target_right = target_right.max( - layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize) - + max_glyph_width, - ); - } - target_right = target_right.min(scroll_width); - - if target_right - target_left > viewport_width { - return; - } - - let mut scroll_position = self.scroll_position.lock(); - let scroll_left = scroll_position.x() * max_glyph_width; - let scroll_right = scroll_left + viewport_width; - - if target_left < scroll_left { - scroll_position.set_x(target_left / max_glyph_width); - } else if target_right > scroll_right { - scroll_position.set_x((target_right - viewport_width) / max_glyph_width); - } - } - - fn select(&mut self, arg: &SelectAction, ctx: &mut ViewContext) { - match arg { - SelectAction::Begin { position, add } => self.begin_selection(*position, *add, ctx), - SelectAction::Update { - position, - scroll_position, - } => self.update_selection(*position, *scroll_position, ctx), - SelectAction::End => self.end_selection(ctx), - } - } - - fn begin_selection(&mut self, position: DisplayPoint, add: bool, ctx: &mut ViewContext) { - if !self.focused { - ctx.focus_self(); - ctx.emit(Event::Activate); - } - - let cursor = self - .display_map - .anchor_before(position, Bias::Left, ctx.as_ref()); - let selection = Selection { - id: post_inc(&mut self.next_selection_id), - start: cursor.clone(), - end: cursor, - reversed: false, - goal: SelectionGoal::None, - }; - - if !add { - self.update_selections(Vec::new(), false, ctx); - } - self.pending_selection = Some(selection); - - ctx.notify(); - } - - fn update_selection( - &mut self, - position: DisplayPoint, - scroll_position: Vector2F, - ctx: &mut ViewContext, - ) { - let buffer = self.buffer.read(ctx); - let cursor = self - .display_map - .anchor_before(position, Bias::Left, ctx.as_ref()); - if let Some(selection) = self.pending_selection.as_mut() { - selection.set_head(buffer, cursor); - } else { - log::error!("update_selection dispatched with no pending selection"); - return; - } - - *self.scroll_position.lock() = scroll_position; - - ctx.notify(); - } - - fn end_selection(&mut self, ctx: &mut ViewContext) { - if let Some(selection) = self.pending_selection.take() { - let ix = self.selection_insertion_index(&selection.start, ctx.as_ref()); - let mut selections = self.selections(ctx.as_ref()).to_vec(); - selections.insert(ix, selection); - self.update_selections(selections, false, ctx); - } else { - log::error!("end_selection dispatched with no pending selection"); - } - } - - pub fn is_selecting(&self) -> bool { - self.pending_selection.is_some() - } - - pub fn cancel(&mut self, _: &(), ctx: &mut ViewContext) { - let selections = self.selections(ctx.as_ref()); - if let Some(pending_selection) = self.pending_selection.take() { - if selections.is_empty() { - self.update_selections(vec![pending_selection], true, ctx); - } - } else { - let mut oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); - if selections.len() == 1 { - oldest_selection.start = oldest_selection.head().clone(); - oldest_selection.end = oldest_selection.head().clone(); - } - self.update_selections(vec![oldest_selection], true, ctx); - } - } - - fn select_ranges(&mut self, ranges: I, autoscroll: bool, ctx: &mut ViewContext) - where - I: IntoIterator>, - T: ToOffset, - { - let buffer = self.buffer.read(ctx); - let mut selections = Vec::new(); - for range in ranges { - let mut start = range.start.to_offset(buffer); - let mut end = range.end.to_offset(buffer); - let reversed = if start > end { - mem::swap(&mut start, &mut end); - true - } else { - false - }; - selections.push(Selection { - id: post_inc(&mut self.next_selection_id), - start: buffer.anchor_before(start), - end: buffer.anchor_before(end), - reversed, - goal: SelectionGoal::None, - }); - } - self.update_selections(selections, autoscroll, ctx); - } - - #[cfg(test)] - fn select_display_ranges<'a, T>(&mut self, ranges: T, ctx: &mut ViewContext) -> Result<()> - where - T: IntoIterator>, - { - let mut selections = Vec::new(); - for range in ranges { - let mut start = range.start; - let mut end = range.end; - let reversed = if start > end { - mem::swap(&mut start, &mut end); - true - } else { - false - }; - - selections.push(Selection { - id: post_inc(&mut self.next_selection_id), - start: self - .display_map - .anchor_before(start, Bias::Left, ctx.as_ref()), - end: self - .display_map - .anchor_before(end, Bias::Left, ctx.as_ref()), - reversed, - goal: SelectionGoal::None, - }); - } - self.update_selections(selections, false, ctx); - Ok(()) - } - - pub fn insert(&mut self, text: &String, ctx: &mut ViewContext) { - let mut old_selections = SmallVec::<[_; 32]>::new(); - { - let buffer = self.buffer.read(ctx); - for selection in self.selections(ctx.as_ref()) { - let start = selection.start.to_offset(buffer); - let end = selection.end.to_offset(buffer); - old_selections.push((selection.id, start..end)); - } - } - - self.start_transaction(ctx); - let mut new_selections = Vec::new(); - self.buffer.update(ctx, |buffer, ctx| { - let edit_ranges = old_selections.iter().map(|(_, range)| range.clone()); - if let Err(error) = buffer.edit(edit_ranges, text.as_str(), Some(ctx)) { - log::error!("error inserting text: {}", error); - }; - let text_len = text.len() as isize; - let mut delta = 0_isize; - new_selections = old_selections - .into_iter() - .map(|(id, range)| { - let start = range.start as isize; - let end = range.end as isize; - let anchor = buffer.anchor_before((start + delta + text_len) as usize); - let deleted_count = end - start; - delta += text_len - deleted_count; - Selection { - id, - start: anchor.clone(), - end: anchor, - reversed: false, - goal: SelectionGoal::None, - } - }) - .collect(); - }); - - self.update_selections(new_selections, true, ctx); - self.end_transaction(ctx); - } - - fn newline(&mut self, _: &(), ctx: &mut ViewContext) { - if self.single_line { - ctx.propagate_action(); - } else { - self.insert(&"\n".into(), ctx); - } - } - - pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - let range = selection.point_range(buffer); - if range.start == range.end { - let head = selection - .head() - .to_display_point(&self.display_map, ctx.as_ref()); - let cursor = self.display_map.anchor_before( - movement::left(&self.display_map, head, ctx.as_ref()).unwrap(), - Bias::Left, - ctx.as_ref(), - ); - selection.set_head(&buffer, cursor); - selection.goal = SelectionGoal::None; - } - } - } - - self.update_selections(selections, true, ctx); - self.insert(&String::new(), ctx); - self.end_transaction(ctx); - } - - pub fn delete(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - let range = selection.point_range(buffer); - if range.start == range.end { - let head = selection - .head() - .to_display_point(&self.display_map, ctx.as_ref()); - let cursor = self.display_map.anchor_before( - movement::right(&self.display_map, head, ctx.as_ref()).unwrap(), - Bias::Right, - ctx.as_ref(), - ); - selection.set_head(&buffer, cursor); - selection.goal = SelectionGoal::None; - } - } - } - - self.update_selections(selections, true, ctx); - self.insert(&String::new(), ctx); - self.end_transaction(ctx); - } - - pub fn delete_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - - let mut new_cursors = Vec::new(); - let mut edit_ranges = Vec::new(); - - let mut selections = self.selections(app).iter().peekable(); - while let Some(selection) = selections.next() { - let (mut rows, _) = - selection.buffer_rows_for_display_rows(false, &self.display_map, app); - let goal_display_column = selection - .head() - .to_display_point(&self.display_map, app) - .column(); - - // Accumulate contiguous regions of rows that we want to delete. - while let Some(next_selection) = selections.peek() { - let (next_rows, _) = - next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); - if next_rows.start <= rows.end { - rows.end = next_rows.end; - selections.next().unwrap(); - } else { - break; - } - } - - let mut edit_start = Point::new(rows.start, 0).to_offset(buffer); - let edit_end; - let cursor_buffer_row; - if buffer.max_point().row >= rows.end { - // If there's a line after the range, delete the \n from the end of the row range - // and position the cursor on the next line. - edit_end = Point::new(rows.end, 0).to_offset(buffer); - cursor_buffer_row = rows.end; - } else { - // If there isn't a line after the range, delete the \n from the line before the - // start of the row range and position the cursor there. - edit_start = edit_start.saturating_sub(1); - edit_end = buffer.len(); - cursor_buffer_row = rows.start.saturating_sub(1); - } - - let mut cursor = - Point::new(cursor_buffer_row, 0).to_display_point(&self.display_map, app); - *cursor.column_mut() = cmp::min( - goal_display_column, - self.display_map.line_len(cursor.row(), app), - ); - - new_cursors.push(( - selection.id, - cursor.to_buffer_point(&self.display_map, Bias::Left, app), - )); - edit_ranges.push(edit_start..edit_end); - } - - new_cursors.sort_unstable_by_key(|(_, range)| range.clone()); - let new_selections = new_cursors - .into_iter() - .map(|(id, cursor)| { - let anchor = buffer.anchor_before(cursor); - Selection { - id, - start: anchor.clone(), - end: anchor, - reversed: false, - goal: SelectionGoal::None, - } - }) - .collect(); - self.buffer - .update(ctx, |buffer, ctx| buffer.edit(edit_ranges, "", Some(ctx))) - .unwrap(); - self.update_selections(new_selections, true, ctx); - self.end_transaction(ctx); - } - - pub fn duplicate_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - // Temporarily bias selections right to allow newly duplicate lines to push them down - // when the selections are at the beginning of a line. - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - selection.start = selection.start.bias_right(buffer); - selection.end = selection.end.bias_right(buffer); - } - } - self.update_selections(selections.clone(), false, ctx); - - let app = ctx.as_ref(); - let buffer = self.buffer.read(ctx); - - let mut edits = Vec::new(); - let mut selections_iter = selections.iter_mut().peekable(); - while let Some(selection) = selections_iter.next() { - // Avoid duplicating the same lines twice. - let (mut rows, _) = - selection.buffer_rows_for_display_rows(false, &self.display_map, app); - while let Some(next_selection) = selections_iter.peek() { - let (next_rows, _) = - next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); - if next_rows.start <= rows.end - 1 { - rows.end = next_rows.end; - selections_iter.next().unwrap(); - } else { - break; - } - } - - // Copy the text from the selected row region and splice it at the start of the region. - let start = Point::new(rows.start, 0); - let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1)); - let text = buffer - .text_for_range(start..end) - .chain(Some("\n")) - .collect::(); - edits.push((start, text)); - } - - self.buffer.update(ctx, |buffer, ctx| { - for (offset, text) in edits.into_iter().rev() { - buffer.edit(Some(offset..offset), text, Some(ctx)).unwrap(); - } - }); - - // Restore bias on selections. - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - selection.start = selection.start.bias_left(buffer); - selection.end = selection.end.bias_left(buffer); - } - self.update_selections(selections, true, ctx); - - self.end_transaction(ctx); - } - - pub fn move_line_up(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - - let app = ctx.as_ref(); - let buffer = self.buffer.read(ctx); - - let mut edits = Vec::new(); - let mut new_selection_ranges = Vec::new(); - let mut old_folds = Vec::new(); - let mut new_folds = Vec::new(); - - let mut selections = self.selections(app).iter().peekable(); - let mut contiguous_selections = Vec::new(); - while let Some(selection) = selections.next() { - // Accumulate contiguous regions of rows that we want to move. - contiguous_selections.push(selection.point_range(buffer)); - let (mut buffer_rows, mut display_rows) = - selection.buffer_rows_for_display_rows(false, &self.display_map, app); - while let Some(next_selection) = selections.peek() { - let (next_buffer_rows, next_display_rows) = - next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); - if next_buffer_rows.start <= buffer_rows.end { - buffer_rows.end = next_buffer_rows.end; - display_rows.end = next_display_rows.end; - contiguous_selections.push(next_selection.point_range(buffer)); - selections.next().unwrap(); - } else { - break; - } - } - - // Cut the text from the selected rows and paste it at the start of the previous line. - if display_rows.start != 0 { - let start = Point::new(buffer_rows.start, 0).to_offset(buffer); - let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1)) - .to_offset(buffer); - - let prev_row_display_start = DisplayPoint::new(display_rows.start - 1, 0); - let prev_row_start = - prev_row_display_start.to_buffer_offset(&self.display_map, Bias::Left, app); - - let mut text = String::new(); - text.extend(buffer.text_for_range(start..end)); - text.push('\n'); - edits.push((prev_row_start..prev_row_start, text)); - edits.push((start - 1..end, String::new())); - - let row_delta = buffer_rows.start - - prev_row_display_start - .to_buffer_point(&self.display_map, Bias::Left, app) - .row; - - // Move selections up. - for range in &mut contiguous_selections { - range.start.row -= row_delta; - range.end.row -= row_delta; - } - - // Move folds up. - old_folds.push(start..end); - for fold in self.display_map.folds_in_range(start..end, app) { - let mut start = fold.start.to_point(buffer); - let mut end = fold.end.to_point(buffer); - start.row -= row_delta; - end.row -= row_delta; - new_folds.push(start..end); - } - } - - new_selection_ranges.extend(contiguous_selections.drain(..)); - } - - self.unfold_ranges(old_folds, ctx); - self.buffer.update(ctx, |buffer, ctx| { - for (range, text) in edits.into_iter().rev() { - buffer.edit(Some(range), text, Some(ctx)).unwrap(); - } - }); - self.fold_ranges(new_folds, ctx); - self.select_ranges(new_selection_ranges, true, ctx); - - self.end_transaction(ctx); - } - - pub fn move_line_down(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - - let app = ctx.as_ref(); - let buffer = self.buffer.read(ctx); - - let mut edits = Vec::new(); - let mut new_selection_ranges = Vec::new(); - let mut old_folds = Vec::new(); - let mut new_folds = Vec::new(); - - let mut selections = self.selections(app).iter().peekable(); - let mut contiguous_selections = Vec::new(); - while let Some(selection) = selections.next() { - // Accumulate contiguous regions of rows that we want to move. - contiguous_selections.push(selection.point_range(buffer)); - let (mut buffer_rows, mut display_rows) = - selection.buffer_rows_for_display_rows(false, &self.display_map, app); - while let Some(next_selection) = selections.peek() { - let (next_buffer_rows, next_display_rows) = - next_selection.buffer_rows_for_display_rows(false, &self.display_map, app); - if next_buffer_rows.start <= buffer_rows.end { - buffer_rows.end = next_buffer_rows.end; - display_rows.end = next_display_rows.end; - contiguous_selections.push(next_selection.point_range(buffer)); - selections.next().unwrap(); - } else { - break; - } - } - - // Cut the text from the selected rows and paste it at the end of the next line. - if display_rows.end <= self.display_map.max_point(app).row() { - let start = Point::new(buffer_rows.start, 0).to_offset(buffer); - let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1)) - .to_offset(buffer); - - let next_row_display_end = DisplayPoint::new( - display_rows.end, - self.display_map.line_len(display_rows.end, app), - ); - let next_row_end = - next_row_display_end.to_buffer_offset(&self.display_map, Bias::Right, app); - - let mut text = String::new(); - text.push('\n'); - text.extend(buffer.text_for_range(start..end)); - edits.push((start..end + 1, String::new())); - edits.push((next_row_end..next_row_end, text)); - - let row_delta = next_row_display_end - .to_buffer_point(&self.display_map, Bias::Right, app) - .row - - buffer_rows.end - + 1; - - // Move selections down. - for range in &mut contiguous_selections { - range.start.row += row_delta; - range.end.row += row_delta; - } - - // Move folds down. - old_folds.push(start..end); - for fold in self.display_map.folds_in_range(start..end, app) { - let mut start = fold.start.to_point(buffer); - let mut end = fold.end.to_point(buffer); - start.row += row_delta; - end.row += row_delta; - new_folds.push(start..end); - } - } - - new_selection_ranges.extend(contiguous_selections.drain(..)); - } - - self.unfold_ranges(old_folds, ctx); - self.buffer.update(ctx, |buffer, ctx| { - for (range, text) in edits.into_iter().rev() { - buffer.edit(Some(range), text, Some(ctx)).unwrap(); - } - }); - self.fold_ranges(new_folds, ctx); - self.select_ranges(new_selection_ranges, true, ctx); - - self.end_transaction(ctx); - } - - pub fn cut(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - let mut text = String::new(); - let mut selections = self.selections(ctx.as_ref()).to_vec(); - let mut clipboard_selections = Vec::with_capacity(selections.len()); - { - let buffer = self.buffer.read(ctx); - let max_point = buffer.max_point(); - for selection in &mut selections { - let mut start = selection.start.to_point(buffer); - let mut end = selection.end.to_point(buffer); - let is_entire_line = start == end; - if is_entire_line { - start = Point::new(start.row, 0); - end = cmp::min(max_point, Point::new(start.row + 1, 0)); - selection.start = buffer.anchor_before(start); - selection.end = buffer.anchor_before(end); - } - let mut len = 0; - for chunk in buffer.text_for_range(start..end) { - text.push_str(chunk); - len += chunk.len(); - } - clipboard_selections.push(ClipboardSelection { - len, - is_entire_line, - }); - } - } - self.update_selections(selections, true, ctx); - self.insert(&String::new(), ctx); - self.end_transaction(ctx); - - ctx.as_mut() - .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); - } - - pub fn copy(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx); - let max_point = buffer.max_point(); - let mut text = String::new(); - let selections = self.selections(ctx.as_ref()); - let mut clipboard_selections = Vec::with_capacity(selections.len()); - for selection in selections { - let mut start = selection.start.to_point(buffer); - let mut end = selection.end.to_point(buffer); - let is_entire_line = start == end; - if is_entire_line { - start = Point::new(start.row, 0); - end = cmp::min(max_point, Point::new(start.row + 1, 0)); - } - let mut len = 0; - for chunk in buffer.text_for_range(start..end) { - text.push_str(chunk); - len += chunk.len(); - } - clipboard_selections.push(ClipboardSelection { - len, - is_entire_line, - }); - } - - ctx.as_mut() - .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); - } - - pub fn paste(&mut self, _: &(), ctx: &mut ViewContext) { - if let Some(item) = ctx.as_mut().read_from_clipboard() { - let clipboard_text = item.text(); - if let Some(mut clipboard_selections) = item.metadata::>() { - let selections = self.selections(ctx.as_ref()).to_vec(); - if clipboard_selections.len() != selections.len() { - let merged_selection = ClipboardSelection { - len: clipboard_selections.iter().map(|s| s.len).sum(), - is_entire_line: clipboard_selections.iter().all(|s| s.is_entire_line), - }; - clipboard_selections.clear(); - clipboard_selections.push(merged_selection); - } - - self.start_transaction(ctx); - let mut new_selections = Vec::with_capacity(selections.len()); - let mut clipboard_chars = clipboard_text.chars().cycle(); - for (selection, clipboard_selection) in - selections.iter().zip(clipboard_selections.iter().cycle()) - { - let to_insert = - String::from_iter(clipboard_chars.by_ref().take(clipboard_selection.len)); - - self.buffer.update(ctx, |buffer, ctx| { - let selection_start = selection.start.to_point(buffer); - let selection_end = selection.end.to_point(buffer); - - // If the corresponding selection was empty when this slice of the - // clipboard text was written, then the entire line containing the - // selection was copied. If this selection is also currently empty, - // then paste the line before the current line of the buffer. - let new_selection_start = selection.end.bias_right(buffer); - if selection_start == selection_end && clipboard_selection.is_entire_line { - let line_start = Point::new(selection_start.row, 0); - buffer - .edit(Some(line_start..line_start), to_insert, Some(ctx)) - .unwrap(); - } else { - buffer - .edit(Some(&selection.start..&selection.end), to_insert, Some(ctx)) - .unwrap(); - }; - - let new_selection_start = new_selection_start.bias_left(buffer); - new_selections.push(Selection { - id: selection.id, - start: new_selection_start.clone(), - end: new_selection_start, - reversed: false, - goal: SelectionGoal::None, - }); - }); - } - self.update_selections(new_selections, true, ctx); - self.end_transaction(ctx); - } else { - self.insert(clipboard_text, ctx); - } - } - } - - pub fn undo(&mut self, _: &(), ctx: &mut ViewContext) { - self.buffer - .update(ctx, |buffer, ctx| buffer.undo(Some(ctx))); - } - - pub fn redo(&mut self, _: &(), ctx: &mut ViewContext) { - self.buffer - .update(ctx, |buffer, ctx| buffer.redo(Some(ctx))); - } - - pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - for selection in &mut selections { - let start = selection.start.to_display_point(&self.display_map, app); - let end = selection.end.to_display_point(&self.display_map, app); - - if start != end { - selection.end = selection.start.clone(); - } else { - let cursor = self.display_map.anchor_before( - movement::left(&self.display_map, start, app).unwrap(), - Bias::Left, - app, - ); - selection.start = cursor.clone(); - selection.end = cursor; - } - selection.reversed = false; - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - let head = selection - .head() - .to_display_point(&self.display_map, ctx.as_ref()); - let cursor = self.display_map.anchor_before( - movement::left(&self.display_map, head, ctx.as_ref()).unwrap(), - Bias::Left, - ctx.as_ref(), - ); - selection.set_head(&buffer, cursor); - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let app = ctx.as_ref(); - for selection in &mut selections { - let start = selection.start.to_display_point(&self.display_map, app); - let end = selection.end.to_display_point(&self.display_map, app); - - if start != end { - selection.start = selection.end.clone(); - } else { - let cursor = self.display_map.anchor_before( - movement::right(&self.display_map, end, app).unwrap(), - Bias::Right, - app, - ); - selection.start = cursor.clone(); - selection.end = cursor; - } - selection.reversed = false; - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - for selection in &mut selections { - let head = selection - .head() - .to_display_point(&self.display_map, ctx.as_ref()); - let cursor = self.display_map.anchor_before( - movement::right(&self.display_map, head, app).unwrap(), - Bias::Right, - app, - ); - selection.set_head(&buffer, cursor); - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn move_up(&mut self, _: &(), ctx: &mut ViewContext) { - if self.single_line { - ctx.propagate_action(); - } else { - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let app = ctx.as_ref(); - for selection in &mut selections { - let start = selection.start.to_display_point(&self.display_map, app); - let end = selection.end.to_display_point(&self.display_map, app); - if start != end { - selection.goal = SelectionGoal::None; - } - - let (start, goal) = - movement::up(&self.display_map, start, selection.goal, app).unwrap(); - let cursor = self.display_map.anchor_before(start, Bias::Left, app); - selection.start = cursor.clone(); - selection.end = cursor; - selection.goal = goal; - selection.reversed = false; - } - } - self.update_selections(selections, true, ctx); - } - } - - pub fn select_up(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let (head, goal) = - movement::up(&self.display_map, head, selection.goal, app).unwrap(); - selection.set_head( - &buffer, - self.display_map.anchor_before(head, Bias::Left, app), - ); - selection.goal = goal; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn move_down(&mut self, _: &(), ctx: &mut ViewContext) { - if self.single_line { - ctx.propagate_action(); - } else { - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let app = ctx.as_ref(); - for selection in &mut selections { - let start = selection.start.to_display_point(&self.display_map, app); - let end = selection.end.to_display_point(&self.display_map, app); - if start != end { - selection.goal = SelectionGoal::None; - } - - let (start, goal) = - movement::down(&self.display_map, end, selection.goal, app).unwrap(); - let cursor = self.display_map.anchor_before(start, Bias::Right, app); - selection.start = cursor.clone(); - selection.end = cursor; - selection.goal = goal; - selection.reversed = false; - } - } - self.update_selections(selections, true, ctx); - } - } - - pub fn select_down(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); - { - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let (head, goal) = - movement::down(&self.display_map, head, selection.goal, app).unwrap(); - selection.set_head( - &buffer, - self.display_map.anchor_before(head, Bias::Right, app), - ); - selection.goal = goal; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn move_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = movement::prev_word_boundary(&self.display_map, head, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.start = anchor.clone(); - selection.end = anchor; - selection.reversed = false; - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn select_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = movement::prev_word_boundary(&self.display_map, head, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn delete_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_previous_word_boundary(&(), ctx); - self.backspace(&(), ctx); - self.end_transaction(ctx); - } - - pub fn move_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = movement::next_word_boundary(&self.display_map, head, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.start = anchor.clone(); - selection.end = anchor; - selection.reversed = false; - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn select_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = movement::next_word_boundary(&self.display_map, head, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn delete_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_next_word_boundary(&(), ctx); - self.delete(&(), ctx); - self.end_transaction(ctx); - } - - pub fn move_to_beginning_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = - movement::line_beginning(&self.display_map, head, true, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.start = anchor.clone(); - selection.end = anchor; - selection.reversed = false; - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn select_to_beginning_of_line( - &mut self, - toggle_indent: &bool, - ctx: &mut ViewContext, - ) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = - movement::line_beginning(&self.display_map, head, *toggle_indent, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn delete_to_beginning_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_beginning_of_line(&false, ctx); - self.backspace(&(), ctx); - self.end_transaction(ctx); - } - - pub fn move_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = movement::line_end(&self.display_map, head, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.start = anchor.clone(); - selection.end = anchor; - selection.reversed = false; - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn select_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let mut selections = self.selections(app).to_vec(); - { - let buffer = self.buffer.read(ctx); - for selection in &mut selections { - let head = selection.head().to_display_point(&self.display_map, app); - let new_head = movement::line_end(&self.display_map, head, app).unwrap(); - let anchor = self.display_map.anchor_before(new_head, Bias::Left, app); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } - } - self.update_selections(selections, true, ctx); - } - - pub fn delete_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_end_of_line(&(), ctx); - self.delete(&(), ctx); - self.end_transaction(ctx); - } - - pub fn move_to_beginning(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx); - let cursor = buffer.anchor_before(Point::new(0, 0)); - let selection = Selection { - id: post_inc(&mut self.next_selection_id), - start: cursor.clone(), - end: cursor, - reversed: false, - goal: SelectionGoal::None, - }; - self.update_selections(vec![selection], true, ctx); - } - - pub fn select_to_beginning(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone(); - selection.set_head(self.buffer.read(ctx), Anchor::Start); - self.update_selections(vec![selection], true, ctx); - } - - pub fn move_to_end(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx); - let cursor = buffer.anchor_before(buffer.max_point()); - let selection = Selection { - id: post_inc(&mut self.next_selection_id), - start: cursor.clone(), - end: cursor, - reversed: false, - goal: SelectionGoal::None, - }; - self.update_selections(vec![selection], true, ctx); - } - - pub fn select_to_end(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone(); - selection.set_head(self.buffer.read(ctx), Anchor::End); - self.update_selections(vec![selection], true, ctx); - } - - pub fn select_all(&mut self, _: &(), ctx: &mut ViewContext) { - let selection = Selection { - id: post_inc(&mut self.next_selection_id), - start: Anchor::Start, - end: Anchor::End, - reversed: false, - goal: SelectionGoal::None, - }; - self.update_selections(vec![selection], false, ctx); - } - - pub fn select_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - let mut selections = self.selections(app).to_vec(); - let max_point = buffer.max_point(); - for selection in &mut selections { - let (rows, _) = selection.buffer_rows_for_display_rows(true, &self.display_map, app); - selection.start = buffer.anchor_before(Point::new(rows.start, 0)); - selection.end = buffer.anchor_before(cmp::min(max_point, Point::new(rows.end, 0))); - selection.reversed = false; - } - self.update_selections(selections, true, ctx); - } - - pub fn split_selection_into_lines(&mut self, _: &(), ctx: &mut ViewContext) { - use super::RangeExt; - - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - - let mut to_unfold = Vec::new(); - let mut new_selections = Vec::new(); - for selection in self.selections(app) { - let range = selection.point_range(buffer).sorted(); - if range.start.row != range.end.row { - new_selections.push(Selection { - id: post_inc(&mut self.next_selection_id), - start: selection.start.clone(), - end: selection.start.clone(), - reversed: false, - goal: SelectionGoal::None, - }); - } - for row in range.start.row + 1..range.end.row { - let cursor = buffer.anchor_before(Point::new(row, buffer.line_len(row))); - new_selections.push(Selection { - id: post_inc(&mut self.next_selection_id), - start: cursor.clone(), - end: cursor, - reversed: false, - goal: SelectionGoal::None, - }); - } - new_selections.push(Selection { - id: selection.id, - start: selection.end.clone(), - end: selection.end.clone(), - reversed: false, - goal: SelectionGoal::None, - }); - to_unfold.push(range); - } - self.unfold_ranges(to_unfold, ctx); - self.update_selections(new_selections, true, ctx); - } - - pub fn add_selection_above(&mut self, _: &(), ctx: &mut ViewContext) { - self.add_selection(true, ctx); - } - - pub fn add_selection_below(&mut self, _: &(), ctx: &mut ViewContext) { - self.add_selection(false, ctx); - } - - fn add_selection(&mut self, above: bool, ctx: &mut ViewContext) { - use super::RangeExt; - - let app = ctx.as_ref(); - - let mut selections = self.selections(app).to_vec(); - let mut state = self.add_selections_state.take().unwrap_or_else(|| { - let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); - let range = oldest_selection - .display_range(&self.display_map, app) - .sorted(); - let columns = cmp::min(range.start.column(), range.end.column()) - ..cmp::max(range.start.column(), range.end.column()); - - selections.clear(); - let mut stack = Vec::new(); - for row in range.start.row()..=range.end.row() { - if let Some(selection) = - self.build_columnar_selection(row, &columns, oldest_selection.reversed, app) - { - stack.push(selection.id); - selections.push(selection); - } - } - - if above { - stack.reverse(); - } - - AddSelectionsState { above, stack } - }); - - let last_added_selection = *state.stack.last().unwrap(); - let mut new_selections = Vec::new(); - if above == state.above { - let end_row = if above { - 0 - } else { - self.display_map.max_point(app).row() - }; - - 'outer: for selection in selections { - if selection.id == last_added_selection { - let range = selection.display_range(&self.display_map, app).sorted(); - debug_assert_eq!(range.start.row(), range.end.row()); - let mut row = range.start.row(); - let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal - { - start..end - } else { - cmp::min(range.start.column(), range.end.column()) - ..cmp::max(range.start.column(), range.end.column()) - }; - - while row != end_row { - if above { - row -= 1; - } else { - row += 1; - } - - if let Some(new_selection) = - self.build_columnar_selection(row, &columns, selection.reversed, app) - { - state.stack.push(new_selection.id); - if above { - new_selections.push(new_selection); - new_selections.push(selection); - } else { - new_selections.push(selection); - new_selections.push(new_selection); - } - - continue 'outer; - } - } - } - - new_selections.push(selection); - } - } else { - new_selections = selections; - new_selections.retain(|s| s.id != last_added_selection); - state.stack.pop(); - } - - self.update_selections(new_selections, true, ctx); - if state.stack.len() > 1 { - self.add_selections_state = Some(state); - } - } - - pub fn select_larger_syntax_node(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - - let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); - let mut selected_larger_node = false; - let old_selections = self.selections(app).to_vec(); - let mut new_selections = Vec::new(); - for selection in &old_selections { - let old_range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer); - let mut new_range = old_range.clone(); - while let Some(containing_range) = buffer.range_for_syntax_ancestor(new_range.clone()) { - new_range = containing_range; - if !self.display_map.intersects_fold(new_range.start, app) - && !self.display_map.intersects_fold(new_range.end, app) - { - break; - } - } - - selected_larger_node |= new_range != old_range; - new_selections.push(Selection { - id: selection.id, - start: buffer.anchor_before(new_range.start), - end: buffer.anchor_before(new_range.end), - reversed: selection.reversed, - goal: SelectionGoal::None, - }); - } - - if selected_larger_node { - stack.push(old_selections); - self.update_selections(new_selections, true, ctx); - } - self.select_larger_syntax_node_stack = stack; - } - - pub fn select_smaller_syntax_node(&mut self, _: &(), ctx: &mut ViewContext) { - let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); - if let Some(selections) = stack.pop() { - self.update_selections(selections, true, ctx); - } - self.select_larger_syntax_node_stack = stack; - } - - pub fn move_to_enclosing_bracket(&mut self, _: &(), ctx: &mut ViewContext) { - use super::RangeExt as _; - - let buffer = self.buffer.read(ctx.as_ref()); - let mut selections = self.selections(ctx.as_ref()).to_vec(); - for selection in &mut selections { - let selection_range = selection.offset_range(buffer); - if let Some((open_range, close_range)) = - buffer.enclosing_bracket_ranges(selection_range.clone()) - { - let close_range = close_range.to_inclusive(); - let destination = if close_range.contains(&selection_range.start) - && close_range.contains(&selection_range.end) - { - open_range.end - } else { - *close_range.start() - }; - selection.start = buffer.anchor_before(destination); - selection.end = selection.start.clone(); - } - } - - self.update_selections(selections, true, ctx); - } - - fn build_columnar_selection( - &mut self, - row: u32, - columns: &Range, - reversed: bool, - ctx: &AppContext, - ) -> Option { - let is_empty = columns.start == columns.end; - let line_len = self.display_map.line_len(row, ctx); - if columns.start < line_len || (is_empty && columns.start == line_len) { - let start = DisplayPoint::new(row, columns.start); - let end = DisplayPoint::new(row, cmp::min(columns.end, line_len)); - Some(Selection { - id: post_inc(&mut self.next_selection_id), - start: self.display_map.anchor_before(start, Bias::Left, ctx), - end: self.display_map.anchor_before(end, Bias::Left, ctx), - reversed, - goal: SelectionGoal::ColumnRange { - start: columns.start, - end: columns.end, - }, - }) - } else { - None - } - } - - pub fn selections_in_range<'a>( - &'a self, - range: Range, - app: &'a AppContext, - ) -> impl 'a + Iterator> { - let start = self.display_map.anchor_before(range.start, Bias::Left, app); - let start_index = self.selection_insertion_index(&start, app); - let pending_selection = self.pending_selection.as_ref().and_then(|s| { - let selection_range = s.display_range(&self.display_map, app); - if selection_range.start <= range.end || selection_range.end <= range.end { - Some(selection_range) - } else { - None - } - }); - self.selections(app)[start_index..] - .iter() - .map(move |s| s.display_range(&self.display_map, app)) - .take_while(move |r| r.start <= range.end || r.end <= range.end) - .chain(pending_selection) - } - - fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize { - let buffer = self.buffer.read(app); - let selections = self.selections(app); - match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) { - Ok(index) => index, - Err(index) => { - if index > 0 - && selections[index - 1].end.cmp(&start, buffer).unwrap() == Ordering::Greater - { - index - 1 - } else { - index - } - } - } - } - - fn selections<'a>(&self, app: &'a AppContext) -> &'a [Selection] { - self.buffer - .read(app) - .selections(self.selection_set_id) - .unwrap() - } - - fn update_selections( - &mut self, - mut selections: Vec, - autoscroll: bool, - ctx: &mut ViewContext, - ) { - // Merge overlapping selections. - let buffer = self.buffer.read(ctx); - let mut i = 1; - while i < selections.len() { - if selections[i - 1] - .end - .cmp(&selections[i].start, buffer) - .unwrap() - >= Ordering::Equal - { - let removed = selections.remove(i); - if removed.start.cmp(&selections[i - 1].start, buffer).unwrap() < Ordering::Equal { - selections[i - 1].start = removed.start; - } - if removed.end.cmp(&selections[i - 1].end, buffer).unwrap() > Ordering::Equal { - selections[i - 1].end = removed.end; - } - } else { - i += 1; - } - } - - self.buffer.update(ctx, |buffer, ctx| { - buffer - .update_selection_set(self.selection_set_id, selections, Some(ctx)) - .unwrap() - }); - self.pause_cursor_blinking(ctx); - - if autoscroll { - *self.autoscroll_requested.lock() = true; - ctx.notify(); - } - - self.add_selections_state = None; - self.select_larger_syntax_node_stack.clear(); - } - - fn start_transaction(&self, ctx: &mut ViewContext) { - self.buffer.update(ctx, |buffer, _| { - buffer - .start_transaction(Some(self.selection_set_id)) - .unwrap() - }); - } - - fn end_transaction(&self, ctx: &mut ViewContext) { - self.buffer.update(ctx, |buffer, ctx| { - buffer - .end_transaction(Some(self.selection_set_id), Some(ctx)) - .unwrap() - }); - } - - pub fn page_up(&mut self, _: &(), _: &mut ViewContext) { - log::info!("BufferView::page_up"); - } - - pub fn page_down(&mut self, _: &(), _: &mut ViewContext) { - log::info!("BufferView::page_down"); - } - - pub fn fold(&mut self, _: &(), ctx: &mut ViewContext) { - use super::RangeExt; - - let mut fold_ranges = Vec::new(); - - let app = ctx.as_ref(); - for selection in self.selections(app) { - let range = selection.display_range(&self.display_map, app).sorted(); - let buffer_start_row = range - .start - .to_buffer_point(&self.display_map, Bias::Left, app) - .row; - - for row in (0..=range.end.row()).rev() { - if self.is_line_foldable(row, app) - && !self.display_map.is_line_folded(row, ctx.as_ref()) - { - let fold_range = self.foldable_range_for_line(row, app); - if fold_range.end.row >= buffer_start_row { - fold_ranges.push(fold_range); - if row <= range.start.row() { - break; - } - } - } - } - } - - self.fold_ranges(fold_ranges, ctx); - } - - pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext) { - use super::RangeExt; - - let app = ctx.as_ref(); - let buffer = self.buffer.read(app); - let ranges = self - .selections(app) - .iter() - .map(|s| { - let range = s.display_range(&self.display_map, app).sorted(); - let mut start = range - .start - .to_buffer_point(&self.display_map, Bias::Left, app); - let mut end = range - .end - .to_buffer_point(&self.display_map, Bias::Left, app); - start.column = 0; - end.column = buffer.line_len(end.row); - start..end - }) - .collect::>(); - self.unfold_ranges(ranges, ctx); - } - - fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool { - let max_point = self.max_point(app); - if display_row >= max_point.row() { - false - } else { - let (start_indent, is_blank) = self.display_map.line_indent(display_row, app); - if is_blank { - false - } else { - for display_row in display_row + 1..=max_point.row() { - let (indent, is_blank) = self.display_map.line_indent(display_row, app); - if !is_blank { - return indent > start_indent; - } - } - false - } - } - } - - fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Range { - let max_point = self.max_point(app); - - let (start_indent, _) = self.display_map.line_indent(start_row, app); - let start = DisplayPoint::new(start_row, self.line_len(start_row, app)); - let mut end = None; - for row in start_row + 1..=max_point.row() { - let (indent, is_blank) = self.display_map.line_indent(row, app); - if !is_blank && indent <= start_indent { - end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, app))); - break; - } - } - - let end = end.unwrap_or(max_point); - return start.to_buffer_point(&self.display_map, Bias::Left, app) - ..end.to_buffer_point(&self.display_map, Bias::Left, app); - } - - pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext) { - use super::RangeExt; - - let buffer = self.buffer.read(ctx); - let ranges = self - .selections(ctx.as_ref()) - .iter() - .map(|s| s.point_range(buffer).sorted()) - .collect(); - self.fold_ranges(ranges, ctx); - } - - fn fold_ranges(&mut self, ranges: Vec>, ctx: &mut ViewContext) { - if !ranges.is_empty() { - self.display_map.fold(ranges, ctx.as_ref()); - *self.autoscroll_requested.lock() = true; - ctx.notify(); - } - } - - fn unfold_ranges(&mut self, ranges: Vec>, ctx: &mut ViewContext) { - if !ranges.is_empty() { - self.display_map.unfold(ranges, ctx.as_ref()); - *self.autoscroll_requested.lock() = true; - ctx.notify(); - } - } - - pub fn line(&self, display_row: u32, ctx: &AppContext) -> String { - self.display_map.line(display_row, ctx) - } - - pub fn line_len(&self, display_row: u32, ctx: &AppContext) -> u32 { - self.display_map.line_len(display_row, ctx) - } - - pub fn longest_row(&self, ctx: &AppContext) -> u32 { - self.display_map.longest_row(ctx) - } - - pub fn max_point(&self, ctx: &AppContext) -> DisplayPoint { - self.display_map.max_point(ctx) - } - - pub fn text(&self, ctx: &AppContext) -> String { - self.display_map.text(ctx) - } - - pub fn font_size(&self) -> f32 { - self.settings.borrow().buffer_font_size - } - - pub fn font_ascent(&self, font_cache: &FontCache) -> f32 { - let settings = self.settings.borrow(); - let font_id = font_cache.default_font(settings.buffer_font_family); - let ascent = font_cache.metric(font_id, |m| m.ascent); - font_cache.scale_metric(ascent, font_id, settings.buffer_font_size) - } - - pub fn font_descent(&self, font_cache: &FontCache) -> f32 { - let settings = self.settings.borrow(); - let font_id = font_cache.default_font(settings.buffer_font_family); - let ascent = font_cache.metric(font_id, |m| m.descent); - font_cache.scale_metric(ascent, font_id, settings.buffer_font_size) - } - - pub fn line_height(&self, font_cache: &FontCache) -> f32 { - let settings = self.settings.borrow(); - let font_id = font_cache.default_font(settings.buffer_font_family); - font_cache.line_height(font_id, settings.buffer_font_size) - } - - pub fn em_width(&self, font_cache: &FontCache) -> f32 { - let settings = self.settings.borrow(); - let font_id = font_cache.default_font(settings.buffer_font_family); - font_cache.em_width(font_id, settings.buffer_font_size) - } - - // TODO: Can we make this not return a result? - pub fn max_line_number_width( - &self, - font_cache: &FontCache, - layout_cache: &TextLayoutCache, - app: &AppContext, - ) -> Result { - let settings = self.settings.borrow(); - let font_size = settings.buffer_font_size; - let font_id = - font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; - let digit_count = (self.buffer.read(app).row_count() as f32).log10().floor() as usize + 1; - - Ok(layout_cache - .layout_str( - "1".repeat(digit_count).as_str(), - font_size, - &[(digit_count, font_id, ColorU::black())], - ) - .width()) - } - - pub fn layout_line_numbers( - &self, - viewport_height: f32, - font_cache: &FontCache, - layout_cache: &TextLayoutCache, - ctx: &AppContext, - ) -> Result> { - let settings = self.settings.borrow(); - let font_size = settings.buffer_font_size; - let font_id = - font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; - - let start_row = self.scroll_position().y() as usize; - let end_row = cmp::min( - self.max_point(ctx).row() as usize, - start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize, - ); - let line_count = end_row - start_row + 1; - - let mut layouts = Vec::with_capacity(line_count); - let mut line_number = String::new(); - for buffer_row in self - .display_map - .snapshot(ctx) - .buffer_rows(start_row as u32) - .take(line_count) - { - line_number.clear(); - write!(&mut line_number, "{}", buffer_row + 1).unwrap(); - layouts.push(layout_cache.layout_str( - &line_number, - font_size, - &[(line_number.len(), font_id, ColorU::black())], - )); - } - - Ok(layouts) - } - - pub fn layout_lines( - &self, - mut rows: Range, - font_cache: &FontCache, - layout_cache: &TextLayoutCache, - ctx: &AppContext, - ) -> Result> { - rows.end = cmp::min(rows.end, self.display_map.max_point(ctx).row() + 1); - if rows.start >= rows.end { - return Ok(Vec::new()); - } - - let settings = self.settings.borrow(); - let font_size = settings.buffer_font_size; - let font_family = settings.buffer_font_family; - let mut prev_font_properties = FontProperties::new(); - let mut prev_font_id = font_cache - .select_font(font_family, &prev_font_properties) - .unwrap(); - - let mut layouts = Vec::with_capacity(rows.len()); - let mut line = String::new(); - let mut styles = Vec::new(); - let mut row = rows.start; - let mut snapshot = self.display_map.snapshot(ctx); - let chunks = snapshot.highlighted_chunks_for_rows(rows.clone()); - let theme = settings.theme.clone(); - - 'outer: for (chunk, style_ix) in chunks.chain(Some(("\n", StyleId::default()))) { - for (ix, line_chunk) in chunk.split('\n').enumerate() { - if ix > 0 { - layouts.push(layout_cache.layout_str(&line, font_size, &styles)); - line.clear(); - styles.clear(); - row += 1; - if row == rows.end { - break 'outer; - } - } - - if !line_chunk.is_empty() { - let (color, font_properties) = theme.syntax_style(style_ix); - // Avoid a lookup if the font properties match the previous ones. - let font_id = if font_properties == prev_font_properties { - prev_font_id - } else { - font_cache.select_font(font_family, &font_properties)? - }; - line.push_str(line_chunk); - styles.push((line_chunk.len(), font_id, color)); - prev_font_id = font_id; - prev_font_properties = font_properties; - } - } - } - - Ok(layouts) - } - - pub fn layout_line( - &self, - row: u32, - font_cache: &FontCache, - layout_cache: &TextLayoutCache, - app: &AppContext, - ) -> Result { - let settings = self.settings.borrow(); - let font_id = - font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; - - let line = self.line(row, app); - - Ok(layout_cache.layout_str( - &line, - settings.buffer_font_size, - &[(self.line_len(row, app) as usize, font_id, ColorU::black())], - )) - } - - fn next_blink_epoch(&mut self) -> usize { - self.blink_epoch += 1; - self.blink_epoch - } - - fn pause_cursor_blinking(&mut self, ctx: &mut ViewContext) { - self.cursors_visible = true; - ctx.notify(); - - let epoch = self.next_blink_epoch(); - ctx.spawn(|this, mut ctx| async move { - Timer::after(CURSOR_BLINK_INTERVAL).await; - this.update(&mut ctx, |this, ctx| { - this.resume_cursor_blinking(epoch, ctx); - }) - }) - .detach(); - } - - fn resume_cursor_blinking(&mut self, epoch: usize, ctx: &mut ViewContext) { - if epoch == self.blink_epoch { - self.blinking_paused = false; - self.blink_cursors(epoch, ctx); - } - } - - fn blink_cursors(&mut self, epoch: usize, ctx: &mut ViewContext) { - if epoch == self.blink_epoch && self.focused && !self.blinking_paused { - self.cursors_visible = !self.cursors_visible; - ctx.notify(); - - let epoch = self.next_blink_epoch(); - ctx.spawn(|this, mut ctx| async move { - Timer::after(CURSOR_BLINK_INTERVAL).await; - this.update(&mut ctx, |this, ctx| this.blink_cursors(epoch, ctx)); - }) - .detach(); - } - } - - pub fn cursors_visible(&self) -> bool { - self.cursors_visible - } - - fn on_buffer_changed(&mut self, _: ModelHandle, ctx: &mut ViewContext) { - ctx.notify(); - } - - fn on_buffer_event( - &mut self, - _: ModelHandle, - event: &buffer::Event, - ctx: &mut ViewContext, - ) { - match event { - buffer::Event::Edited => ctx.emit(Event::Edited), - buffer::Event::Dirtied => ctx.emit(Event::Dirtied), - buffer::Event::Saved => ctx.emit(Event::Saved), - buffer::Event::FileHandleChanged => ctx.emit(Event::FileHandleChanged), - buffer::Event::Reloaded => ctx.emit(Event::FileHandleChanged), - buffer::Event::Reparsed => {} - } - } -} - -pub enum Event { - Activate, - Edited, - Blurred, - Dirtied, - Saved, - FileHandleChanged, -} - -impl Entity for BufferView { - type Event = Event; -} - -impl View for BufferView { - fn render<'a>(&self, _: &AppContext) -> ElementBox { - BufferElement::new(self.handle.clone()).boxed() - } - - fn ui_name() -> &'static str { - "BufferView" - } - - fn on_focus(&mut self, ctx: &mut ViewContext) { - self.focused = true; - self.blink_cursors(self.blink_epoch, ctx); - } - - fn on_blur(&mut self, ctx: &mut ViewContext) { - self.focused = false; - self.cursors_visible = false; - ctx.emit(Event::Blurred); - ctx.notify(); - } -} - -impl workspace::Item for Buffer { - type View = BufferView; - - fn file(&self) -> Option<&FileHandle> { - self.file() - } - - fn build_view( - handle: ModelHandle, - settings: watch::Receiver, - ctx: &mut ViewContext, - ) -> Self::View { - BufferView::for_buffer(handle, settings, ctx) - } -} - -impl workspace::ItemView for BufferView { - fn should_activate_item_on_event(event: &Self::Event) -> bool { - matches!(event, Event::Activate) - } - - fn should_update_tab_on_event(event: &Self::Event) -> bool { - matches!( - event, - Event::Saved | Event::Dirtied | Event::FileHandleChanged - ) - } - - fn title(&self, app: &AppContext) -> std::string::String { - let filename = self - .buffer - .read(app) - .file() - .and_then(|file| file.file_name(app)); - if let Some(name) = filename { - name.to_string_lossy().into() - } else { - "untitled".into() - } - } - - fn entry_id(&self, ctx: &AppContext) -> Option<(usize, Arc)> { - self.buffer.read(ctx).file().map(|file| file.entry_id()) - } - - fn clone_on_split(&self, ctx: &mut ViewContext) -> Option - where - Self: Sized, - { - let clone = BufferView::for_buffer(self.buffer.clone(), self.settings.clone(), ctx); - *clone.scroll_position.lock() = *self.scroll_position.lock(); - Some(clone) - } - - fn save( - &mut self, - new_file: Option, - ctx: &mut ViewContext, - ) -> Task> { - self.buffer.update(ctx, |b, ctx| b.save(new_file, ctx)) - } - - fn is_dirty(&self, ctx: &AppContext) -> bool { - self.buffer.read(ctx).is_dirty() - } - - fn has_conflict(&self, ctx: &AppContext) -> bool { - self.buffer.read(ctx).has_conflict() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - editor::Point, - settings, - test::{build_app_state, sample_text}, - }; - use buffer::History; - use unindent::Unindent; - - #[gpui::test] - fn test_selection_with_mouse(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, buffer_view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - - buffer_view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(2, 2), false, ctx); - }); - - let view = buffer_view.read(app); - let selections = view - .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), - ) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] - ); - - buffer_view.update(app, |view, ctx| { - view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); - }); - - let view = buffer_view.read(app); - let selections = view - .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), - ) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] - ); - - buffer_view.update(app, |view, ctx| { - view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); - }); - - let view = buffer_view.read(app); - let selections = view - .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), - ) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] - ); - - buffer_view.update(app, |view, ctx| { - view.end_selection(ctx); - view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); - }); - - let view = buffer_view.read(app); - let selections = view - .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), - ) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] - ); - - buffer_view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(3, 3), true, ctx); - view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx); - }); - - let view = buffer_view.read(app); - let selections = view - .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), - ) - .collect::>(); - assert_eq!( - selections, - [ - DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0) - ] - ); - - buffer_view.update(app, |view, ctx| { - view.end_selection(ctx); - }); - - let view = buffer_view.read(app); - let selections = view - .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), - ) - .collect::>(); - assert_eq!( - selections, - [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)] - ); - } - - #[gpui::test] - fn test_canceling_pending_selection(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - - view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(2, 2), false, ctx); - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] - ); - - view.update(app, |view, ctx| { - view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] - ); - - view.update(app, |view, ctx| { - view.cancel(&(), ctx); - view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] - ); - } - - #[gpui::test] - fn test_cancel(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - - view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(3, 4), false, ctx); - view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); - view.end_selection(ctx); - - view.begin_selection(DisplayPoint::new(0, 1), true, ctx); - view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), ctx); - view.end_selection(ctx); - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1), - ] - ); - - view.update(app, |view, ctx| view.cancel(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)] - ); - - view.update(app, |view, ctx| view.cancel(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)] - ); - } - - #[gpui::test] - fn test_layout_line_numbers(app: &mut gpui::MutableAppContext) { - let layout_cache = TextLayoutCache::new(app.platform().fonts()); - let font_cache = app.font_cache().clone(); - - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); - - let settings = settings::channel(&font_cache).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - - let layouts = view - .read(app) - .layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref()) - .unwrap(); - assert_eq!(layouts.len(), 6); - } - - #[gpui::test] - fn test_fold(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| { - Buffer::new( - 0, - " - impl Foo { - // Hello! - - fn a() { - 1 - } - - fn b() { - 2 - } - - fn c() { - 3 - } - } - " - .unindent(), - ctx, - ) - }); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], ctx) - .unwrap(); - view.fold(&(), ctx); - assert_eq!( - view.text(ctx.as_ref()), - " - impl Foo { - // Hello! - - fn a() { - 1 - } - - fn b() {… - } - - fn c() {… - } - } - " - .unindent(), - ); - - view.fold(&(), ctx); - assert_eq!( - view.text(ctx.as_ref()), - " - impl Foo {… - } - " - .unindent(), - ); - - view.unfold(&(), ctx); - assert_eq!( - view.text(ctx.as_ref()), - " - impl Foo { - // Hello! - - fn a() { - 1 - } - - fn b() {… - } - - fn c() {… - } - } - " - .unindent(), - ); - - view.unfold(&(), ctx); - assert_eq!(view.text(ctx.as_ref()), buffer.read(ctx).text()); - }); - } - - #[gpui::test] - fn test_move_cursor(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - - buffer.update(app, |buffer, ctx| { - buffer - .edit( - vec![ - Point::new(1, 0)..Point::new(1, 0), - Point::new(1, 1)..Point::new(1, 1), - ], - "\t", - Some(ctx), - ) - .unwrap(); - }); - - view.update(app, |view, ctx| { - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] - ); - - view.move_down(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] - ); - - view.move_right(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] - ); - - view.move_left(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] - ); - - view.move_up(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] - ); - - view.move_to_end(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)] - ); - - view.move_to_beginning(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] - ); - - view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], ctx) - .unwrap(); - view.select_to_beginning(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)] - ); - - view.select_to_end(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)] - ); - }); - } - - #[gpui::test] - fn test_move_cursor_multibyte(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - - assert_eq!('ⓐ'.len_utf8(), 3); - assert_eq!('α'.len_utf8(), 2); - - view.update(app, |view, ctx| { - view.fold_ranges( - vec![ - Point::new(0, 6)..Point::new(0, 12), - Point::new(1, 2)..Point::new(1, 4), - Point::new(2, 4)..Point::new(2, 8), - ], - ctx, - ); - assert_eq!(view.text(ctx.as_ref()), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n"); - - view.move_right(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(0, "ⓐ".len())] - ); - view.move_right(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(0, "ⓐⓑ".len())] - ); - view.move_right(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(0, "ⓐⓑ…".len())] - ); - - view.move_down(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(1, "ab…".len())] - ); - view.move_left(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(1, "ab".len())] - ); - view.move_left(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(1, "a".len())] - ); - - view.move_down(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(2, "α".len())] - ); - view.move_right(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(2, "αβ".len())] - ); - view.move_right(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(2, "αβ…".len())] - ); - view.move_right(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(2, "αβ…ε".len())] - ); - - view.move_up(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(1, "ab…e".len())] - ); - view.move_up(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(0, "ⓐⓑ…ⓔ".len())] - ); - view.move_left(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(0, "ⓐⓑ…".len())] - ); - view.move_left(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(0, "ⓐⓑ".len())] - ); - view.move_left(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(0, "ⓐ".len())] - ); - }); - } - - #[gpui::test] - fn test_move_cursor_different_line_lengths(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], ctx) - .unwrap(); - - view.move_down(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(1, "abcd".len())] - ); - - view.move_down(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(2, "αβγ".len())] - ); - - view.move_down(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(3, "abcd".len())] - ); - - view.move_down(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())] - ); - - view.move_up(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(3, "abcd".len())] - ); - - view.move_up(&(), ctx); - assert_eq!( - view.selection_ranges(ctx.as_ref()), - &[empty_range(2, "αβγ".len())] - ); - }); - } - - #[gpui::test] - fn test_beginning_end_of_line(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\n def", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), - ], - ctx, - ) - .unwrap(); - }); - - view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - ] - ); - - view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); - - view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - ] - ); - - view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), - ] - ); - - // Moving to the end of line again is a no-op. - view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), - ] - ); - - view.update(app, |view, ctx| { - view.move_left(&(), ctx); - view.select_to_beginning_of_line(&true, ctx); - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), - ] - ); - - view.update(app, |view, ctx| { - view.select_to_beginning_of_line(&true, ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0), - ] - ); - - view.update(app, |view, ctx| { - view.select_to_beginning_of_line(&true, ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), - ] - ); - - view.update(app, |view, ctx| view.select_to_end_of_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5), - ] - ); - - view.update(app, |view, ctx| view.delete_to_end_of_line(&(), ctx)); - assert_eq!(view.read(app).text(app.as_ref()), "ab\n de"); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), - ] - ); - - view.update(app, |view, ctx| view.delete_to_beginning_of_line(&(), ctx)); - assert_eq!(view.read(app).text(app.as_ref()), "\n"); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); - } - - #[gpui::test] - fn test_prev_next_word_boundary(app: &mut gpui::MutableAppContext) { - let buffer = - app.add_model(|ctx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11), - DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4), - ], - ctx, - ) - .unwrap(); - }); - - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), - ] - ); - - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), - DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), - ] - ); - - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), - ] - ); - - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); - - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), - ] - ); - - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23), - ] - ); - - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), - ] - ); - - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - ] - ); - - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), - ] - ); - - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), - ] - ); - - view.update(app, |view, ctx| { - view.move_right(&(), ctx); - view.select_to_previous_word_boundary(&(), ctx); - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), - ] - ); - - view.update(app, |view, ctx| { - view.select_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0), - ] - ); - - view.update(app, |view, ctx| view.select_to_next_word_boundary(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), - ] - ); - - view.update(app, |view, ctx| view.delete_to_next_word_boundary(&(), ctx)); - assert_eq!( - view.read(app).text(app.as_ref()), - "use std::s::{foo, bar}\n\n {az.qux()}" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10), - DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), - ] - ); - - view.update(app, |view, ctx| { - view.delete_to_previous_word_boundary(&(), ctx) - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "use std::::{foo, bar}\n\n az.qux()}" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), - DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), - ] - ); - } - - #[gpui::test] - fn test_backspace(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| { - Buffer::new( - 0, - "one two three\nfour five six\nseven eight nine\nten\n", - ctx, - ) - }); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - // an empty selection - the preceding character is deleted - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - // one character selected - it is deleted - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), - // a line suffix selected - it is deleted - DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0), - ], - ctx, - ) - .unwrap(); - view.backspace(&(), ctx); - }); - - assert_eq!( - buffer.read(app).text(), - "oe two three\nfou five six\nseven ten\n" - ); - } - - #[gpui::test] - fn test_delete(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| { - Buffer::new( - 0, - "one two three\nfour five six\nseven eight nine\nten\n", - ctx, - ) - }); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); - - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - // an empty selection - the following character is deleted - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - // one character selected - it is deleted - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), - // a line suffix selected - it is deleted - DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0), - ], - ctx, - ) - .unwrap(); - view.delete(&(), ctx); - }); - - assert_eq!( - buffer.read(app).text(), - "on two three\nfou five six\nseven ten\n" - ); - } - - #[gpui::test] - fn test_delete_line(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), - ], - ctx, - ) - .unwrap(); - view.delete_line(&(), ctx); - }); - assert_eq!(view.read(app).text(app.as_ref()), "ghi"); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1) - ] - ); - - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], ctx) - .unwrap(); - view.delete_line(&(), ctx); - }); - assert_eq!(view.read(app).text(app.as_ref()), "ghi\n"); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] - ); - } - - #[gpui::test] - fn test_duplicate_line(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), - ], - ctx, - ) - .unwrap(); - view.duplicate_line(&(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "abc\nabc\ndef\ndef\nghi\n\n" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), - DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0), - ] - ); - - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1), - ], - ctx, - ) - .unwrap(); - view.duplicate_line(&(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "abc\ndef\nghi\nabc\ndef\nghi\n" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1), - DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1), - ] - ); - } - - #[gpui::test] - fn test_move_line_up_down(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(10, 5), ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.fold_ranges( - vec![ - Point::new(0, 2)..Point::new(1, 2), - Point::new(2, 3)..Point::new(4, 1), - Point::new(7, 0)..Point::new(8, 4), - ], - ctx, - ); - view.select_display_ranges( - &[ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2), - ], - ctx, - ) - .unwrap(); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj" - ); - - view.update(app, |view, ctx| view.move_line_up(&(), ctx)); - assert_eq!( - view.read(app).text(app.as_ref()), - "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), - DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) - ] - ); - - view.update(app, |view, ctx| view.move_line_down(&(), ctx)); - assert_eq!( - view.read(app).text(app.as_ref()), - "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) - ] - ); - - view.update(app, |view, ctx| view.move_line_down(&(), ctx)); - assert_eq!( - view.read(app).text(app.as_ref()), - "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), - DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2) - ] - ); - - view.update(app, |view, ctx| view.move_line_up(&(), ctx)); - assert_eq!( - view.read(app).text(app.as_ref()), - "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3), - DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2) - ] - ); - } - - #[gpui::test] - fn test_clipboard(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let view = app - .add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)) - .1; - - // Cut with three selections. Clipboard text is divided into three slices. - view.update(app, |view, ctx| { - view.select_ranges(vec![0..4, 8..14, 19..24], false, ctx); - view.cut(&(), ctx); - }); - assert_eq!(view.read(app).text(app.as_ref()), "two four six "); - - // Paste with three cursors. Each cursor pastes one slice of the clipboard text. - view.update(app, |view, ctx| { - view.select_ranges(vec![4..4, 9..9, 13..13], false, ctx); - view.paste(&(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "two one four three six five " - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8), - DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19), - DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28) - ] - ); - - // Paste again but with only two cursors. Since the number of cursors doesn't - // match the number of slices in the clipboard, the entire clipboard text - // is pasted at each cursor. - view.update(app, |view, ctx| { - view.select_ranges(vec![0..0, 28..28], false, ctx); - view.insert(&"( ".to_string(), ctx); - view.paste(&(), ctx); - view.insert(&") ".to_string(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "( one three five ) two one four three six five ( one three five ) " - ); - - view.update(app, |view, ctx| { - view.select_ranges(vec![0..0], false, ctx); - view.insert(&"123\n4567\n89\n".to_string(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) " - ); - - // Cut with three selections, one of which is full-line. - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1), - ], - ctx, - ) - .unwrap(); - view.cut(&(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "13\n9\n( one three five ) two one four three six five ( one three five ) " - ); - - // Paste with three selections, noticing how the copied selection that was full-line - // gets inserted before the second cursor. - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3), - ], - ctx, - ) - .unwrap(); - view.paste(&(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) " - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3), - ] - ); - - // Copy with a single cursor only, which writes the whole line into the clipboard. - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], ctx) - .unwrap(); - view.copy(&(), ctx); - }); - - // Paste with three selections, noticing how the copied full-line selection is inserted - // before the empty selections but replaces the selection that is non-empty. - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2), - DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), - ], - ctx, - ) - .unwrap(); - view.paste(&(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "123\n123\n123\n67\n123\n9\n( 8ne three five ) two one four three six five ( one three five ) " - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[ - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1), - ] - ); - } - - #[gpui::test] - fn test_select_all(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\nde\nfgh", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |b, ctx| b.select_all(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)] - ); - } - - #[gpui::test] - fn test_select_line(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 5), ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2), - ], - ctx, - ) - .unwrap(); - view.select_line(&(), ctx); - }); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0), - DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0), - ] - ); - - view.update(app, |view, ctx| view.select_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0), - DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5), - ] - ); - - view.update(app, |view, ctx| view.select_line(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)] - ); - } - - #[gpui::test] - fn test_split_selection_into_lines(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(9, 5), ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.fold_ranges( - vec![ - Point::new(0, 2)..Point::new(1, 2), - Point::new(2, 3)..Point::new(4, 1), - Point::new(7, 0)..Point::new(8, 4), - ], - ctx, - ); - view.select_display_ranges( - &[ - DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4), - ], - ctx, - ) - .unwrap(); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "aa…bbb\nccc…eeee\nfffff\nggggg\n…i" - ); - - view.update(app, |view, ctx| view.split_selection_into_lines(&(), ctx)); - assert_eq!( - view.read(app).text(app.as_ref()), - "aa…bbb\nccc…eeee\nfffff\nggggg\n…i" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), - DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4) - ] - ); - - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)], ctx) - .unwrap(); - view.split_selection_into_lines(&(), ctx); - }); - assert_eq!( - view.read(app).text(app.as_ref()), - "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i" - ); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - [ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), - DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5), - DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5), - DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5), - DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5), - DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5), - DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0) - ] - ); - } - - #[gpui::test] - fn test_add_selection_above_below(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", ctx)); - let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); - - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], ctx) - .unwrap(); - }); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) - ] - ); - - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) - ] - ); - - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)] - ); - - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) - ] - ); - - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) - ] - ); - - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], ctx) - .unwrap(); - }); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) - ] - ); - - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), - DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) - ] - ); - - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] - ); - - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] - ); - - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], ctx) - .unwrap(); - }); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), - ] - ); - - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), - DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4), - ] - ); - - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), - DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), - DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2), - ] - ); - - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], ctx) - .unwrap(); - }); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1), - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), - ] - ); - - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); - assert_eq!( - view.read(app).selection_ranges(app.as_ref()), - vec![ - DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), - DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), - DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1), - ] - ); - } - - #[gpui::test] - async fn test_select_larger_smaller_syntax_node(mut app: gpui::TestAppContext) { - let app_state = app.read(build_app_state); - let lang = app_state.language_registry.select_language("z.rs"); - let text = r#" - use mod1::mod2::{mod3, mod4}; - - fn fn_1(param1: bool, param2: &str) { - let var1 = "text"; - } - "# - .unindent(); - let buffer = app.add_model(|ctx| { - let history = History::new(text.into()); - Buffer::from_history(0, history, None, lang.cloned(), ctx) - }); - let (_, view) = - app.add_window(|ctx| BufferView::for_buffer(buffer, app_state.settings, ctx)); - view.condition(&app, |view, ctx| !view.buffer.read(ctx).is_parsing()) - .await; - - view.update(&mut app, |view, ctx| { - view.select_display_ranges( - &[ - DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), - DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), - DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), - ], - ctx, - ) - .unwrap(); - view.select_larger_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[ - DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), - DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), - DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), - ] - ); - - view.update(&mut app, |view, ctx| { - view.select_larger_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[ - DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), - DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), - ] - ); - - view.update(&mut app, |view, ctx| { - view.select_larger_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] - ); - - // Trying to expand the selected syntax node one more time has no effect. - view.update(&mut app, |view, ctx| { - view.select_larger_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] - ); - - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[ - DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), - DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), - ] - ); - - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[ - DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), - DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), - DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21), - ] - ); - - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[ - DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), - DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), - DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), - ] - ); - - // Trying to shrink the selected syntax node one more time has no effect. - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[ - DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), - DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), - DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), - ] - ); - - // Ensure that we keep expanding the selection if the larger selection starts or ends within - // a fold. - view.update(&mut app, |view, ctx| { - view.fold_ranges( - vec![ - Point::new(0, 21)..Point::new(0, 24), - Point::new(3, 20)..Point::new(3, 22), - ], - ctx, - ); - view.select_larger_syntax_node(&(), ctx); - }); - assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), - &[ - DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), - DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), - DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23), - ] - ); - } - - impl BufferView { - fn selection_ranges(&self, app: &AppContext) -> Vec> { - self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app) - .collect::>() - } - } - - fn empty_range(row: usize, column: usize) -> Range { - let point = DisplayPoint::new(row as u32, column as u32); - point..point - } -} diff --git a/zed/src/editor/buffer_element.rs b/zed/src/editor/element.rs similarity index 98% rename from zed/src/editor/buffer_element.rs rename to zed/src/editor/element.rs index fc5b7852e9e59d334498229e8d43f39427d1290d..5cd93cf57cf7fd0f4acbbb694c3d04d832afddaa 100644 --- a/zed/src/editor/buffer_element.rs +++ b/zed/src/editor/element.rs @@ -1,4 +1,4 @@ -use super::{BufferView, DisplayPoint, SelectAction}; +use super::{DisplayPoint, Editor, SelectAction}; use gpui::{ color::{ColorF, ColorU}, geometry::{ @@ -16,16 +16,16 @@ use smallvec::SmallVec; use std::cmp::Ordering; use std::cmp::{self}; -pub struct BufferElement { - view: WeakViewHandle, +pub struct EditorElement { + view: WeakViewHandle, } -impl BufferElement { - pub fn new(view: WeakViewHandle) -> Self { +impl EditorElement { + pub fn new(view: WeakViewHandle) -> Self { Self { view } } - fn view<'a>(&self, ctx: &'a AppContext) -> &'a BufferView { + fn view<'a>(&self, ctx: &'a AppContext) -> &'a Editor { self.view.upgrade(ctx).unwrap().read(ctx) } @@ -302,7 +302,7 @@ impl BufferElement { } } -impl Element for BufferElement { +impl Element for EditorElement { type LayoutState = Option; type PaintState = Option; @@ -510,7 +510,7 @@ pub struct LayoutState { impl LayoutState { fn scroll_width( &self, - view: &BufferView, + view: &Editor, font_cache: &FontCache, layout_cache: &TextLayoutCache, app: &AppContext, @@ -525,7 +525,7 @@ impl LayoutState { fn scroll_max( &self, - view: &BufferView, + view: &Editor, font_cache: &FontCache, layout_cache: &TextLayoutCache, app: &AppContext, @@ -547,7 +547,7 @@ pub struct PaintState { impl PaintState { fn point_for_position( &self, - view: &BufferView, + view: &Editor, layout: &LayoutState, position: Vector2F, font_cache: &FontCache, diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 5c3cffff7b792f5dec627e918234d8a5339ac677..40b3894d2599af471a7d71ef24274ff99cbda51e 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -1,5 +1,5 @@ use crate::{ - editor::{buffer_view, BufferView}, + editor::{self, Editor}, settings::Settings, util, workspace::Workspace, @@ -28,7 +28,7 @@ pub struct FileFinder { handle: WeakViewHandle, settings: watch::Receiver, workspace: WeakViewHandle, - query_buffer: ViewHandle, + query_buffer: ViewHandle, search_count: usize, latest_search_id: usize, latest_search_did_cancel: bool, @@ -290,8 +290,8 @@ impl FileFinder { ) -> Self { ctx.observe_view(&workspace, Self::workspace_updated); - let query_buffer = ctx.add_view(|ctx| BufferView::single_line(settings.clone(), ctx)); - ctx.subscribe_to_view(&query_buffer, Self::on_query_buffer_event); + let query_buffer = ctx.add_view(|ctx| Editor::single_line(settings.clone(), ctx)); + ctx.subscribe_to_view(&query_buffer, Self::on_query_editor_event); Self { handle: ctx.handle().downgrade(), @@ -315,15 +315,14 @@ impl FileFinder { } } - fn on_query_buffer_event( + fn on_query_editor_event( &mut self, - _: ViewHandle, - event: &buffer_view::Event, + _: ViewHandle, + event: &editor::Event, ctx: &mut ViewContext, ) { - use buffer_view::Event::*; match event { - Edited => { + editor::Event::Edited => { let query = self.query_buffer.read(ctx).text(ctx.as_ref()); if query.is_empty() { self.latest_search_id = util::post_inc(&mut self.search_count); @@ -335,7 +334,7 @@ impl FileFinder { } } } - Blurred => ctx.emit(Event::Dismissed), + editor::Event::Blurred => ctx.emit(Event::Dismissed), _ => {} } } diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index bb77ca11817ad2d961586806eff11b14b85a8939..552ee24d26c7048c9a08e1be2a35728ecc2bc1d7 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -1,7 +1,7 @@ pub mod pane; pub mod pane_group; use crate::{ - editor::{Buffer, BufferView}, + editor::{Buffer, Editor}, language::LanguageRegistry, settings::Settings, time::ReplicaId, @@ -452,7 +452,7 @@ impl Workspace { pub fn open_new_file(&mut self, _: &(), ctx: &mut ViewContext) { let buffer = ctx.add_model(|ctx| Buffer::new(self.replica_id, "", ctx)); let buffer_view = - ctx.add_view(|ctx| BufferView::for_buffer(buffer.clone(), self.settings.clone(), ctx)); + ctx.add_view(|ctx| Editor::for_buffer(buffer.clone(), self.settings.clone(), ctx)); self.items.push(ItemHandle::downgrade(&buffer)); self.add_item_view(Box::new(buffer_view), ctx); } @@ -776,7 +776,7 @@ impl WorkspaceHandle for ViewHandle { mod tests { use super::*; use crate::{ - editor::BufferView, + editor::Editor, test::{build_app_state, temp_tree}, }; use serde_json::json; @@ -1049,7 +1049,7 @@ mod tests { let editor = app.read(|ctx| { let pane = workspace.read(ctx).active_pane().read(ctx); let item = pane.active_item().unwrap(); - item.to_any().downcast::().unwrap() + item.to_any().downcast::().unwrap() }); app.update(|ctx| editor.update(ctx, |editor, ctx| editor.insert(&"x".to_string(), ctx))); @@ -1095,7 +1095,7 @@ mod tests { .active_item(ctx) .unwrap() .to_any() - .downcast::() + .downcast::() .unwrap() }); editor.update(&mut app, |editor, ctx| { @@ -1155,7 +1155,7 @@ mod tests { .active_item(ctx) .unwrap() .to_any() - .downcast::() + .downcast::() .unwrap() }); app.read(|ctx| { From 5176f3deba39a0b2cc7ca035cee3f476977e2f00 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 14:53:30 -0700 Subject: [PATCH 03/16] Rename context parameters to `cx` in editor.rs --- zed/src/editor.rs | 1839 ++++++++++++++++++++++----------------------- 1 file changed, 908 insertions(+), 931 deletions(-) diff --git a/zed/src/editor.rs b/zed/src/editor.rs index 08ba35d86bfaeb27513f0ff71f552b1ce8df5bd7..328f9ff729f9b3ce48dc2308f70aa0080d77283d 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -38,8 +38,8 @@ use std::{ const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); -pub fn init(app: &mut MutableAppContext) { - app.add_bindings(vec![ +pub fn init(cx: &mut MutableAppContext) { + cx.add_bindings(vec![ Binding::new("escape", "buffer:cancel", Some("BufferView")), Binding::new("backspace", "buffer:backspace", Some("BufferView")), Binding::new("ctrl-h", "buffer:backspace", Some("BufferView")), @@ -197,104 +197,104 @@ pub fn init(app: &mut MutableAppContext) { ), ]); - app.add_action("buffer:scroll", Editor::scroll); - app.add_action("buffer:select", Editor::select); - app.add_action("buffer:cancel", Editor::cancel); - app.add_action("buffer:insert", Editor::insert); - app.add_action("buffer:newline", Editor::newline); - app.add_action("buffer:backspace", Editor::backspace); - app.add_action("buffer:delete", Editor::delete); - app.add_action("buffer:delete_line", Editor::delete_line); - app.add_action( + cx.add_action("buffer:scroll", Editor::scroll); + cx.add_action("buffer:select", Editor::select); + cx.add_action("buffer:cancel", Editor::cancel); + cx.add_action("buffer:insert", Editor::insert); + cx.add_action("buffer:newline", Editor::newline); + cx.add_action("buffer:backspace", Editor::backspace); + cx.add_action("buffer:delete", Editor::delete); + cx.add_action("buffer:delete_line", Editor::delete_line); + cx.add_action( "buffer:delete_to_previous_word_boundary", Editor::delete_to_previous_word_boundary, ); - app.add_action( + cx.add_action( "buffer:delete_to_next_word_boundary", Editor::delete_to_next_word_boundary, ); - app.add_action( + cx.add_action( "buffer:delete_to_beginning_of_line", Editor::delete_to_beginning_of_line, ); - app.add_action( + cx.add_action( "buffer:delete_to_end_of_line", Editor::delete_to_end_of_line, ); - app.add_action("buffer:duplicate_line", Editor::duplicate_line); - app.add_action("buffer:move_line_up", Editor::move_line_up); - app.add_action("buffer:move_line_down", Editor::move_line_down); - app.add_action("buffer:cut", Editor::cut); - app.add_action("buffer:copy", Editor::copy); - app.add_action("buffer:paste", Editor::paste); - app.add_action("buffer:undo", Editor::undo); - app.add_action("buffer:redo", Editor::redo); - app.add_action("buffer:move_up", Editor::move_up); - app.add_action("buffer:move_down", Editor::move_down); - app.add_action("buffer:move_left", Editor::move_left); - app.add_action("buffer:move_right", Editor::move_right); - app.add_action( + cx.add_action("buffer:duplicate_line", Editor::duplicate_line); + cx.add_action("buffer:move_line_up", Editor::move_line_up); + cx.add_action("buffer:move_line_down", Editor::move_line_down); + cx.add_action("buffer:cut", Editor::cut); + cx.add_action("buffer:copy", Editor::copy); + cx.add_action("buffer:paste", Editor::paste); + cx.add_action("buffer:undo", Editor::undo); + cx.add_action("buffer:redo", Editor::redo); + cx.add_action("buffer:move_up", Editor::move_up); + cx.add_action("buffer:move_down", Editor::move_down); + cx.add_action("buffer:move_left", Editor::move_left); + cx.add_action("buffer:move_right", Editor::move_right); + cx.add_action( "buffer:move_to_previous_word_boundary", Editor::move_to_previous_word_boundary, ); - app.add_action( + cx.add_action( "buffer:move_to_next_word_boundary", Editor::move_to_next_word_boundary, ); - app.add_action( + cx.add_action( "buffer:move_to_beginning_of_line", Editor::move_to_beginning_of_line, ); - app.add_action("buffer:move_to_end_of_line", Editor::move_to_end_of_line); - app.add_action("buffer:move_to_beginning", Editor::move_to_beginning); - app.add_action("buffer:move_to_end", Editor::move_to_end); - app.add_action("buffer:select_up", Editor::select_up); - app.add_action("buffer:select_down", Editor::select_down); - app.add_action("buffer:select_left", Editor::select_left); - app.add_action("buffer:select_right", Editor::select_right); - app.add_action( + cx.add_action("buffer:move_to_end_of_line", Editor::move_to_end_of_line); + cx.add_action("buffer:move_to_beginning", Editor::move_to_beginning); + cx.add_action("buffer:move_to_end", Editor::move_to_end); + cx.add_action("buffer:select_up", Editor::select_up); + cx.add_action("buffer:select_down", Editor::select_down); + cx.add_action("buffer:select_left", Editor::select_left); + cx.add_action("buffer:select_right", Editor::select_right); + cx.add_action( "buffer:select_to_previous_word_boundary", Editor::select_to_previous_word_boundary, ); - app.add_action( + cx.add_action( "buffer:select_to_next_word_boundary", Editor::select_to_next_word_boundary, ); - app.add_action( + cx.add_action( "buffer:select_to_beginning_of_line", Editor::select_to_beginning_of_line, ); - app.add_action( + cx.add_action( "buffer:select_to_end_of_line", Editor::select_to_end_of_line, ); - app.add_action("buffer:select_to_beginning", Editor::select_to_beginning); - app.add_action("buffer:select_to_end", Editor::select_to_end); - app.add_action("buffer:select_all", Editor::select_all); - app.add_action("buffer:select_line", Editor::select_line); - app.add_action( + cx.add_action("buffer:select_to_beginning", Editor::select_to_beginning); + cx.add_action("buffer:select_to_end", Editor::select_to_end); + cx.add_action("buffer:select_all", Editor::select_all); + cx.add_action("buffer:select_line", Editor::select_line); + cx.add_action( "buffer:split_selection_into_lines", Editor::split_selection_into_lines, ); - app.add_action("buffer:add_selection_above", Editor::add_selection_above); - app.add_action("buffer:add_selection_below", Editor::add_selection_below); - app.add_action( + cx.add_action("buffer:add_selection_above", Editor::add_selection_above); + cx.add_action("buffer:add_selection_below", Editor::add_selection_below); + cx.add_action( "buffer:select_larger_syntax_node", Editor::select_larger_syntax_node, ); - app.add_action( + cx.add_action( "buffer:select_smaller_syntax_node", Editor::select_smaller_syntax_node, ); - app.add_action( + cx.add_action( "buffer:move_to_enclosing_bracket", Editor::move_to_enclosing_bracket, ); - app.add_action("buffer:page_up", Editor::page_up); - app.add_action("buffer:page_down", Editor::page_down); - app.add_action("buffer:fold", Editor::fold); - app.add_action("buffer:unfold", Editor::unfold); - app.add_action("buffer:fold_selected_ranges", Editor::fold_selected_ranges); + cx.add_action("buffer:page_up", Editor::page_up); + cx.add_action("buffer:page_down", Editor::page_down); + cx.add_action("buffer:fold", Editor::fold); + cx.add_action("buffer:unfold", Editor::unfold); + cx.add_action("buffer:fold_selected_ranges", Editor::fold_selected_ranges); } pub enum SelectAction { @@ -340,9 +340,9 @@ struct ClipboardSelection { } impl Editor { - pub fn single_line(settings: watch::Receiver, ctx: &mut ViewContext) -> Self { - let buffer = ctx.add_model(|ctx| Buffer::new(0, String::new(), ctx)); - let mut view = Self::for_buffer(buffer, settings, ctx); + pub fn single_line(settings: watch::Receiver, cx: &mut ViewContext) -> Self { + let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx)); + let mut view = Self::for_buffer(buffer, settings, cx); view.single_line = true; view } @@ -350,14 +350,14 @@ impl Editor { pub fn for_buffer( buffer: ModelHandle, settings: watch::Receiver, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self { - ctx.observe_model(&buffer, Self::on_buffer_changed); - ctx.subscribe_to_model(&buffer, Self::on_buffer_event); - let display_map = DisplayMap::new(buffer.clone(), settings.borrow().tab_size, ctx.as_ref()); + cx.observe_model(&buffer, Self::on_buffer_changed); + cx.subscribe_to_model(&buffer, Self::on_buffer_event); + let display_map = DisplayMap::new(buffer.clone(), settings.borrow().tab_size, cx.as_ref()); let mut next_selection_id = 0; - let (selection_set_id, _) = buffer.update(ctx, |buffer, ctx| { + let (selection_set_id, _) = buffer.update(cx, |buffer, cx| { buffer.add_selection_set( vec![Selection { id: post_inc(&mut next_selection_id), @@ -366,11 +366,11 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }], - Some(ctx), + Some(cx), ) }); Self { - handle: ctx.handle().downgrade(), + handle: cx.handle().downgrade(), buffer, display_map, selection_set_id, @@ -397,9 +397,9 @@ impl Editor { !self.single_line } - fn scroll(&mut self, scroll_position: &Vector2F, ctx: &mut ViewContext) { + fn scroll(&mut self, scroll_position: &Vector2F, cx: &mut ViewContext) { *self.scroll_position.lock() = *scroll_position; - ctx.notify(); + cx.notify(); } pub fn scroll_position(&self) -> Vector2F { @@ -416,11 +416,11 @@ impl Editor { &self, viewport_height: f32, line_height: f32, - app: &AppContext, + cx: &AppContext, ) -> bool { let mut scroll_position = self.scroll_position.lock(); let scroll_top = scroll_position.y(); - scroll_position.set_y(scroll_top.min(self.max_point(app).row().saturating_sub(1) as f32)); + scroll_position.set_y(scroll_top.min(self.max_point(cx).row().saturating_sub(1) as f32)); let mut autoscroll_requested = self.autoscroll_requested.lock(); if *autoscroll_requested { @@ -431,18 +431,18 @@ impl Editor { let visible_lines = viewport_height / line_height; let first_cursor_top = self - .selections(app) + .selections(cx) .first() .unwrap() .head() - .to_display_point(&self.display_map, app) + .to_display_point(&self.display_map, cx) .row() as f32; let last_cursor_bottom = self - .selections(app) + .selections(cx) .last() .unwrap() .head() - .to_display_point(&self.display_map, app) + .to_display_point(&self.display_map, cx) .row() as f32 + 1.0; @@ -474,17 +474,14 @@ impl Editor { scroll_width: f32, max_glyph_width: f32, layouts: &[text_layout::Line], - ctx: &AppContext, + cx: &AppContext, ) { let mut target_left = std::f32::INFINITY; let mut target_right = 0.0_f32; - for selection in self.selections(ctx) { - let head = selection.head().to_display_point(&self.display_map, ctx); + for selection in self.selections(cx) { + let head = selection.head().to_display_point(&self.display_map, cx); let start_column = head.column().saturating_sub(3); - let end_column = cmp::min( - self.display_map.line_len(head.row(), ctx), - head.column() + 3, - ); + let end_column = cmp::min(self.display_map.line_len(head.row(), cx), head.column() + 3); target_left = target_left .min(layouts[(head.row() - start_row) as usize].x_for_index(start_column as usize)); target_right = target_right.max( @@ -509,26 +506,26 @@ impl Editor { } } - fn select(&mut self, arg: &SelectAction, ctx: &mut ViewContext) { + fn select(&mut self, arg: &SelectAction, cx: &mut ViewContext) { match arg { - SelectAction::Begin { position, add } => self.begin_selection(*position, *add, ctx), + SelectAction::Begin { position, add } => self.begin_selection(*position, *add, cx), SelectAction::Update { position, scroll_position, - } => self.update_selection(*position, *scroll_position, ctx), - SelectAction::End => self.end_selection(ctx), + } => self.update_selection(*position, *scroll_position, cx), + SelectAction::End => self.end_selection(cx), } } - fn begin_selection(&mut self, position: DisplayPoint, add: bool, ctx: &mut ViewContext) { + fn begin_selection(&mut self, position: DisplayPoint, add: bool, cx: &mut ViewContext) { if !self.focused { - ctx.focus_self(); - ctx.emit(Event::Activate); + cx.focus_self(); + cx.emit(Event::Activate); } let cursor = self .display_map - .anchor_before(position, Bias::Left, ctx.as_ref()); + .anchor_before(position, Bias::Left, cx.as_ref()); let selection = Selection { id: post_inc(&mut self.next_selection_id), start: cursor.clone(), @@ -538,23 +535,23 @@ impl Editor { }; if !add { - self.update_selections(Vec::new(), false, ctx); + self.update_selections(Vec::new(), false, cx); } self.pending_selection = Some(selection); - ctx.notify(); + cx.notify(); } fn update_selection( &mut self, position: DisplayPoint, scroll_position: Vector2F, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); let cursor = self .display_map - .anchor_before(position, Bias::Left, ctx.as_ref()); + .anchor_before(position, Bias::Left, cx.as_ref()); if let Some(selection) = self.pending_selection.as_mut() { selection.set_head(buffer, cursor); } else { @@ -564,15 +561,15 @@ impl Editor { *self.scroll_position.lock() = scroll_position; - ctx.notify(); + cx.notify(); } - fn end_selection(&mut self, ctx: &mut ViewContext) { + fn end_selection(&mut self, cx: &mut ViewContext) { if let Some(selection) = self.pending_selection.take() { - let ix = self.selection_insertion_index(&selection.start, ctx.as_ref()); - let mut selections = self.selections(ctx.as_ref()).to_vec(); + let ix = self.selection_insertion_index(&selection.start, cx.as_ref()); + let mut selections = self.selections(cx.as_ref()).to_vec(); selections.insert(ix, selection); - self.update_selections(selections, false, ctx); + self.update_selections(selections, false, cx); } else { log::error!("end_selection dispatched with no pending selection"); } @@ -582,11 +579,11 @@ impl Editor { self.pending_selection.is_some() } - pub fn cancel(&mut self, _: &(), ctx: &mut ViewContext) { - let selections = self.selections(ctx.as_ref()); + pub fn cancel(&mut self, _: &(), cx: &mut ViewContext) { + let selections = self.selections(cx.as_ref()); if let Some(pending_selection) = self.pending_selection.take() { if selections.is_empty() { - self.update_selections(vec![pending_selection], true, ctx); + self.update_selections(vec![pending_selection], true, cx); } } else { let mut oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); @@ -594,16 +591,16 @@ impl Editor { oldest_selection.start = oldest_selection.head().clone(); oldest_selection.end = oldest_selection.head().clone(); } - self.update_selections(vec![oldest_selection], true, ctx); + self.update_selections(vec![oldest_selection], true, cx); } } - fn select_ranges(&mut self, ranges: I, autoscroll: bool, ctx: &mut ViewContext) + fn select_ranges(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext) where I: IntoIterator>, T: ToOffset, { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); let mut selections = Vec::new(); for range in ranges { let mut start = range.start.to_offset(buffer); @@ -622,11 +619,11 @@ impl Editor { goal: SelectionGoal::None, }); } - self.update_selections(selections, autoscroll, ctx); + self.update_selections(selections, autoscroll, cx); } #[cfg(test)] - fn select_display_ranges<'a, T>(&mut self, ranges: T, ctx: &mut ViewContext) -> Result<()> + fn select_display_ranges<'a, T>(&mut self, ranges: T, cx: &mut ViewContext) -> Result<()> where T: IntoIterator>, { @@ -645,34 +642,32 @@ impl Editor { id: post_inc(&mut self.next_selection_id), start: self .display_map - .anchor_before(start, Bias::Left, ctx.as_ref()), - end: self - .display_map - .anchor_before(end, Bias::Left, ctx.as_ref()), + .anchor_before(start, Bias::Left, cx.as_ref()), + end: self.display_map.anchor_before(end, Bias::Left, cx.as_ref()), reversed, goal: SelectionGoal::None, }); } - self.update_selections(selections, false, ctx); + self.update_selections(selections, false, cx); Ok(()) } - pub fn insert(&mut self, text: &String, ctx: &mut ViewContext) { + pub fn insert(&mut self, text: &String, cx: &mut ViewContext) { let mut old_selections = SmallVec::<[_; 32]>::new(); { - let buffer = self.buffer.read(ctx); - for selection in self.selections(ctx.as_ref()) { + let buffer = self.buffer.read(cx); + for selection in self.selections(cx.as_ref()) { let start = selection.start.to_offset(buffer); let end = selection.end.to_offset(buffer); old_selections.push((selection.id, start..end)); } } - self.start_transaction(ctx); + self.start_transaction(cx); let mut new_selections = Vec::new(); - self.buffer.update(ctx, |buffer, ctx| { + self.buffer.update(cx, |buffer, cx| { let edit_ranges = old_selections.iter().map(|(_, range)| range.clone()); - if let Err(error) = buffer.edit(edit_ranges, text.as_str(), Some(ctx)) { + if let Err(error) = buffer.edit(edit_ranges, text.as_str(), Some(cx)) { log::error!("error inserting text: {}", error); }; let text_len = text.len() as isize; @@ -696,33 +691,33 @@ impl Editor { .collect(); }); - self.update_selections(new_selections, true, ctx); - self.end_transaction(ctx); + self.update_selections(new_selections, true, cx); + self.end_transaction(cx); } - fn newline(&mut self, _: &(), ctx: &mut ViewContext) { + fn newline(&mut self, _: &(), cx: &mut ViewContext) { if self.single_line { - ctx.propagate_action(); + cx.propagate_action(); } else { - self.insert(&"\n".into(), ctx); + self.insert(&"\n".into(), cx); } } - pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn backspace(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { let range = selection.point_range(buffer); if range.start == range.end { let head = selection .head() - .to_display_point(&self.display_map, ctx.as_ref()); + .to_display_point(&self.display_map, cx.as_ref()); let cursor = self.display_map.anchor_before( - movement::left(&self.display_map, head, ctx.as_ref()).unwrap(), + movement::left(&self.display_map, head, cx.as_ref()).unwrap(), Bias::Left, - ctx.as_ref(), + cx.as_ref(), ); selection.set_head(&buffer, cursor); selection.goal = SelectionGoal::None; @@ -730,26 +725,26 @@ impl Editor { } } - self.update_selections(selections, true, ctx); - self.insert(&String::new(), ctx); - self.end_transaction(ctx); + self.update_selections(selections, true, cx); + self.insert(&String::new(), cx); + self.end_transaction(cx); } - pub fn delete(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn delete(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { let range = selection.point_range(buffer); if range.start == range.end { let head = selection .head() - .to_display_point(&self.display_map, ctx.as_ref()); + .to_display_point(&self.display_map, cx.as_ref()); let cursor = self.display_map.anchor_before( - movement::right(&self.display_map, head, ctx.as_ref()).unwrap(), + movement::right(&self.display_map, head, cx.as_ref()).unwrap(), Bias::Right, - ctx.as_ref(), + cx.as_ref(), ); selection.set_head(&buffer, cursor); selection.goal = SelectionGoal::None; @@ -757,15 +752,15 @@ impl Editor { } } - self.update_selections(selections, true, ctx); - self.insert(&String::new(), ctx); - self.end_transaction(ctx); + self.update_selections(selections, true, cx); + self.insert(&String::new(), cx); + self.end_transaction(cx); } - pub fn delete_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); + pub fn delete_line(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); - let app = ctx.as_ref(); + let app = cx.as_ref(); let buffer = self.buffer.read(app); let mut new_cursors = Vec::new(); @@ -837,29 +832,29 @@ impl Editor { }) .collect(); self.buffer - .update(ctx, |buffer, ctx| buffer.edit(edit_ranges, "", Some(ctx))) + .update(cx, |buffer, cx| buffer.edit(edit_ranges, "", Some(cx))) .unwrap(); - self.update_selections(new_selections, true, ctx); - self.end_transaction(ctx); + self.update_selections(new_selections, true, cx); + self.end_transaction(cx); } - pub fn duplicate_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); + pub fn duplicate_line(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); - let mut selections = self.selections(ctx.as_ref()).to_vec(); + let mut selections = self.selections(cx.as_ref()).to_vec(); { // Temporarily bias selections right to allow newly duplicate lines to push them down // when the selections are at the beginning of a line. - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { selection.start = selection.start.bias_right(buffer); selection.end = selection.end.bias_right(buffer); } } - self.update_selections(selections.clone(), false, ctx); + self.update_selections(selections.clone(), false, cx); - let app = ctx.as_ref(); - let buffer = self.buffer.read(ctx); + let app = cx.as_ref(); + let buffer = self.buffer.read(cx); let mut edits = Vec::new(); let mut selections_iter = selections.iter_mut().peekable(); @@ -888,28 +883,28 @@ impl Editor { edits.push((start, text)); } - self.buffer.update(ctx, |buffer, ctx| { + self.buffer.update(cx, |buffer, cx| { for (offset, text) in edits.into_iter().rev() { - buffer.edit(Some(offset..offset), text, Some(ctx)).unwrap(); + buffer.edit(Some(offset..offset), text, Some(cx)).unwrap(); } }); // Restore bias on selections. - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { selection.start = selection.start.bias_left(buffer); selection.end = selection.end.bias_left(buffer); } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); - self.end_transaction(ctx); + self.end_transaction(cx); } - pub fn move_line_up(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); + pub fn move_line_up(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); - let app = ctx.as_ref(); - let buffer = self.buffer.read(ctx); + let app = cx.as_ref(); + let buffer = self.buffer.read(cx); let mut edits = Vec::new(); let mut new_selection_ranges = Vec::new(); @@ -977,23 +972,23 @@ impl Editor { new_selection_ranges.extend(contiguous_selections.drain(..)); } - self.unfold_ranges(old_folds, ctx); - self.buffer.update(ctx, |buffer, ctx| { + self.unfold_ranges(old_folds, cx); + self.buffer.update(cx, |buffer, cx| { for (range, text) in edits.into_iter().rev() { - buffer.edit(Some(range), text, Some(ctx)).unwrap(); + buffer.edit(Some(range), text, Some(cx)).unwrap(); } }); - self.fold_ranges(new_folds, ctx); - self.select_ranges(new_selection_ranges, true, ctx); + self.fold_ranges(new_folds, cx); + self.select_ranges(new_selection_ranges, true, cx); - self.end_transaction(ctx); + self.end_transaction(cx); } - pub fn move_line_down(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); + pub fn move_line_down(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); - let app = ctx.as_ref(); - let buffer = self.buffer.read(ctx); + let app = cx.as_ref(); + let buffer = self.buffer.read(cx); let mut edits = Vec::new(); let mut new_selection_ranges = Vec::new(); @@ -1065,25 +1060,25 @@ impl Editor { new_selection_ranges.extend(contiguous_selections.drain(..)); } - self.unfold_ranges(old_folds, ctx); - self.buffer.update(ctx, |buffer, ctx| { + self.unfold_ranges(old_folds, cx); + self.buffer.update(cx, |buffer, cx| { for (range, text) in edits.into_iter().rev() { - buffer.edit(Some(range), text, Some(ctx)).unwrap(); + buffer.edit(Some(range), text, Some(cx)).unwrap(); } }); - self.fold_ranges(new_folds, ctx); - self.select_ranges(new_selection_ranges, true, ctx); + self.fold_ranges(new_folds, cx); + self.select_ranges(new_selection_ranges, true, cx); - self.end_transaction(ctx); + self.end_transaction(cx); } - pub fn cut(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); + pub fn cut(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); let mut text = String::new(); - let mut selections = self.selections(ctx.as_ref()).to_vec(); + let mut selections = self.selections(cx.as_ref()).to_vec(); let mut clipboard_selections = Vec::with_capacity(selections.len()); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); let max_point = buffer.max_point(); for selection in &mut selections { let mut start = selection.start.to_point(buffer); @@ -1106,19 +1101,19 @@ impl Editor { }); } } - self.update_selections(selections, true, ctx); - self.insert(&String::new(), ctx); - self.end_transaction(ctx); + self.update_selections(selections, true, cx); + self.insert(&String::new(), cx); + self.end_transaction(cx); - ctx.as_mut() + cx.as_mut() .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); } - pub fn copy(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx); + pub fn copy(&mut self, _: &(), cx: &mut ViewContext) { + let buffer = self.buffer.read(cx); let max_point = buffer.max_point(); let mut text = String::new(); - let selections = self.selections(ctx.as_ref()); + let selections = self.selections(cx.as_ref()); let mut clipboard_selections = Vec::with_capacity(selections.len()); for selection in selections { let mut start = selection.start.to_point(buffer); @@ -1139,15 +1134,15 @@ impl Editor { }); } - ctx.as_mut() + cx.as_mut() .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); } - pub fn paste(&mut self, _: &(), ctx: &mut ViewContext) { - if let Some(item) = ctx.as_mut().read_from_clipboard() { + pub fn paste(&mut self, _: &(), cx: &mut ViewContext) { + if let Some(item) = cx.as_mut().read_from_clipboard() { let clipboard_text = item.text(); if let Some(mut clipboard_selections) = item.metadata::>() { - let selections = self.selections(ctx.as_ref()).to_vec(); + let selections = self.selections(cx.as_ref()).to_vec(); if clipboard_selections.len() != selections.len() { let merged_selection = ClipboardSelection { len: clipboard_selections.iter().map(|s| s.len).sum(), @@ -1157,7 +1152,7 @@ impl Editor { clipboard_selections.push(merged_selection); } - self.start_transaction(ctx); + self.start_transaction(cx); let mut new_selections = Vec::with_capacity(selections.len()); let mut clipboard_chars = clipboard_text.chars().cycle(); for (selection, clipboard_selection) in @@ -1166,7 +1161,7 @@ impl Editor { let to_insert = String::from_iter(clipboard_chars.by_ref().take(clipboard_selection.len)); - self.buffer.update(ctx, |buffer, ctx| { + self.buffer.update(cx, |buffer, cx| { let selection_start = selection.start.to_point(buffer); let selection_end = selection.end.to_point(buffer); @@ -1178,11 +1173,11 @@ impl Editor { if selection_start == selection_end && clipboard_selection.is_entire_line { let line_start = Point::new(selection_start.row, 0); buffer - .edit(Some(line_start..line_start), to_insert, Some(ctx)) + .edit(Some(line_start..line_start), to_insert, Some(cx)) .unwrap(); } else { buffer - .edit(Some(&selection.start..&selection.end), to_insert, Some(ctx)) + .edit(Some(&selection.start..&selection.end), to_insert, Some(cx)) .unwrap(); }; @@ -1196,26 +1191,24 @@ impl Editor { }); }); } - self.update_selections(new_selections, true, ctx); - self.end_transaction(ctx); + self.update_selections(new_selections, true, cx); + self.end_transaction(cx); } else { - self.insert(clipboard_text, ctx); + self.insert(clipboard_text, cx); } } } - pub fn undo(&mut self, _: &(), ctx: &mut ViewContext) { - self.buffer - .update(ctx, |buffer, ctx| buffer.undo(Some(ctx))); + pub fn undo(&mut self, _: &(), cx: &mut ViewContext) { + self.buffer.update(cx, |buffer, cx| buffer.undo(Some(cx))); } - pub fn redo(&mut self, _: &(), ctx: &mut ViewContext) { - self.buffer - .update(ctx, |buffer, ctx| buffer.redo(Some(ctx))); + pub fn redo(&mut self, _: &(), cx: &mut ViewContext) { + self.buffer.update(cx, |buffer, cx| buffer.redo(Some(cx))); } - pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn move_left(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { for selection in &mut selections { @@ -1237,33 +1230,33 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn select_left(&mut self, _: &(), cx: &mut ViewContext) { + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { let head = selection .head() - .to_display_point(&self.display_map, ctx.as_ref()); + .to_display_point(&self.display_map, cx.as_ref()); let cursor = self.display_map.anchor_before( - movement::left(&self.display_map, head, ctx.as_ref()).unwrap(), + movement::left(&self.display_map, head, cx.as_ref()).unwrap(), Bias::Left, - ctx.as_ref(), + cx.as_ref(), ); selection.set_head(&buffer, cursor); selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn move_right(&mut self, _: &(), cx: &mut ViewContext) { + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let app = ctx.as_ref(); + let app = cx.as_ref(); for selection in &mut selections { let start = selection.start.to_display_point(&self.display_map, app); let end = selection.end.to_display_point(&self.display_map, app); @@ -1283,18 +1276,18 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn select_right(&mut self, _: &(), cx: &mut ViewContext) { + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let app = ctx.as_ref(); + let app = cx.as_ref(); let buffer = self.buffer.read(app); for selection in &mut selections { let head = selection .head() - .to_display_point(&self.display_map, ctx.as_ref()); + .to_display_point(&self.display_map, cx.as_ref()); let cursor = self.display_map.anchor_before( movement::right(&self.display_map, head, app).unwrap(), Bias::Right, @@ -1304,16 +1297,16 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn move_up(&mut self, _: &(), ctx: &mut ViewContext) { + pub fn move_up(&mut self, _: &(), cx: &mut ViewContext) { if self.single_line { - ctx.propagate_action(); + cx.propagate_action(); } else { - let mut selections = self.selections(ctx.as_ref()).to_vec(); + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let app = ctx.as_ref(); + let app = cx.as_ref(); for selection in &mut selections { let start = selection.start.to_display_point(&self.display_map, app); let end = selection.end.to_display_point(&self.display_map, app); @@ -1330,14 +1323,14 @@ impl Editor { selection.reversed = false; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } } - pub fn select_up(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn select_up(&mut self, _: &(), cx: &mut ViewContext) { + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let app = ctx.as_ref(); + let app = cx.as_ref(); let buffer = self.buffer.read(app); for selection in &mut selections { let head = selection.head().to_display_point(&self.display_map, app); @@ -1350,16 +1343,16 @@ impl Editor { selection.goal = goal; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn move_down(&mut self, _: &(), ctx: &mut ViewContext) { + pub fn move_down(&mut self, _: &(), cx: &mut ViewContext) { if self.single_line { - ctx.propagate_action(); + cx.propagate_action(); } else { - let mut selections = self.selections(ctx.as_ref()).to_vec(); + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let app = ctx.as_ref(); + let app = cx.as_ref(); for selection in &mut selections { let start = selection.start.to_display_point(&self.display_map, app); let end = selection.end.to_display_point(&self.display_map, app); @@ -1376,14 +1369,14 @@ impl Editor { selection.reversed = false; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } } - pub fn select_down(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn select_down(&mut self, _: &(), cx: &mut ViewContext) { + let mut selections = self.selections(cx.as_ref()).to_vec(); { - let app = ctx.as_ref(); + let app = cx.as_ref(); let buffer = self.buffer.read(app); for selection in &mut selections { let head = selection.head().to_display_point(&self.display_map, app); @@ -1396,11 +1389,11 @@ impl Editor { selection.goal = goal; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn move_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn move_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { for selection in &mut selections { @@ -1413,14 +1406,14 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn select_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn select_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { let head = selection.head().to_display_point(&self.display_map, app); let new_head = movement::prev_word_boundary(&self.display_map, head, app).unwrap(); @@ -1429,18 +1422,18 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn delete_to_previous_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_previous_word_boundary(&(), ctx); - self.backspace(&(), ctx); - self.end_transaction(ctx); + pub fn delete_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); + self.select_to_previous_word_boundary(&(), cx); + self.backspace(&(), cx); + self.end_transaction(cx); } - pub fn move_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn move_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { for selection in &mut selections { @@ -1453,14 +1446,14 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn select_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn select_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { let head = selection.head().to_display_point(&self.display_map, app); let new_head = movement::next_word_boundary(&self.display_map, head, app).unwrap(); @@ -1469,18 +1462,18 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn delete_to_next_word_boundary(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_next_word_boundary(&(), ctx); - self.delete(&(), ctx); - self.end_transaction(ctx); + pub fn delete_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); + self.select_to_next_word_boundary(&(), cx); + self.delete(&(), cx); + self.end_transaction(cx); } - pub fn move_to_beginning_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn move_to_beginning_of_line(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { for selection in &mut selections { @@ -1494,18 +1487,18 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } pub fn select_to_beginning_of_line( &mut self, toggle_indent: &bool, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { - let app = ctx.as_ref(); + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { let head = selection.head().to_display_point(&self.display_map, app); let new_head = @@ -1515,18 +1508,18 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn delete_to_beginning_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_beginning_of_line(&false, ctx); - self.backspace(&(), ctx); - self.end_transaction(ctx); + pub fn delete_to_beginning_of_line(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); + self.select_to_beginning_of_line(&false, cx); + self.backspace(&(), cx); + self.end_transaction(cx); } - pub fn move_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn move_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { for selection in &mut selections { @@ -1539,14 +1532,14 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn select_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn select_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for selection in &mut selections { let head = selection.head().to_display_point(&self.display_map, app); let new_head = movement::line_end(&self.display_map, head, app).unwrap(); @@ -1555,18 +1548,18 @@ impl Editor { selection.goal = SelectionGoal::None; } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn delete_to_end_of_line(&mut self, _: &(), ctx: &mut ViewContext) { - self.start_transaction(ctx); - self.select_to_end_of_line(&(), ctx); - self.delete(&(), ctx); - self.end_transaction(ctx); + pub fn delete_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext) { + self.start_transaction(cx); + self.select_to_end_of_line(&(), cx); + self.delete(&(), cx); + self.end_transaction(cx); } - pub fn move_to_beginning(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx); + pub fn move_to_beginning(&mut self, _: &(), cx: &mut ViewContext) { + let buffer = self.buffer.read(cx); let cursor = buffer.anchor_before(Point::new(0, 0)); let selection = Selection { id: post_inc(&mut self.next_selection_id), @@ -1575,17 +1568,17 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }; - self.update_selections(vec![selection], true, ctx); + self.update_selections(vec![selection], true, cx); } - pub fn select_to_beginning(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone(); - selection.set_head(self.buffer.read(ctx), Anchor::Start); - self.update_selections(vec![selection], true, ctx); + pub fn select_to_beginning(&mut self, _: &(), cx: &mut ViewContext) { + let mut selection = self.selections(cx.as_ref()).last().unwrap().clone(); + selection.set_head(self.buffer.read(cx), Anchor::Start); + self.update_selections(vec![selection], true, cx); } - pub fn move_to_end(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx); + pub fn move_to_end(&mut self, _: &(), cx: &mut ViewContext) { + let buffer = self.buffer.read(cx); let cursor = buffer.anchor_before(buffer.max_point()); let selection = Selection { id: post_inc(&mut self.next_selection_id), @@ -1594,16 +1587,16 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }; - self.update_selections(vec![selection], true, ctx); + self.update_selections(vec![selection], true, cx); } - pub fn select_to_end(&mut self, _: &(), ctx: &mut ViewContext) { - let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone(); - selection.set_head(self.buffer.read(ctx), Anchor::End); - self.update_selections(vec![selection], true, ctx); + pub fn select_to_end(&mut self, _: &(), cx: &mut ViewContext) { + let mut selection = self.selections(cx.as_ref()).last().unwrap().clone(); + selection.set_head(self.buffer.read(cx), Anchor::End); + self.update_selections(vec![selection], true, cx); } - pub fn select_all(&mut self, _: &(), ctx: &mut ViewContext) { + pub fn select_all(&mut self, _: &(), cx: &mut ViewContext) { let selection = Selection { id: post_inc(&mut self.next_selection_id), start: Anchor::Start, @@ -1611,11 +1604,11 @@ impl Editor { reversed: false, goal: SelectionGoal::None, }; - self.update_selections(vec![selection], false, ctx); + self.update_selections(vec![selection], false, cx); } - pub fn select_line(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn select_line(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let buffer = self.buffer.read(app); let mut selections = self.selections(app).to_vec(); let max_point = buffer.max_point(); @@ -1625,11 +1618,11 @@ impl Editor { selection.end = buffer.anchor_before(cmp::min(max_point, Point::new(rows.end, 0))); selection.reversed = false; } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } - pub fn split_selection_into_lines(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn split_selection_into_lines(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let buffer = self.buffer.read(app); let mut to_unfold = Vec::new(); @@ -1664,20 +1657,20 @@ impl Editor { }); to_unfold.push(range); } - self.unfold_ranges(to_unfold, ctx); - self.update_selections(new_selections, true, ctx); + self.unfold_ranges(to_unfold, cx); + self.update_selections(new_selections, true, cx); } - pub fn add_selection_above(&mut self, _: &(), ctx: &mut ViewContext) { - self.add_selection(true, ctx); + pub fn add_selection_above(&mut self, _: &(), cx: &mut ViewContext) { + self.add_selection(true, cx); } - pub fn add_selection_below(&mut self, _: &(), ctx: &mut ViewContext) { - self.add_selection(false, ctx); + pub fn add_selection_below(&mut self, _: &(), cx: &mut ViewContext) { + self.add_selection(false, cx); } - fn add_selection(&mut self, above: bool, ctx: &mut ViewContext) { - let app = ctx.as_ref(); + fn add_selection(&mut self, above: bool, cx: &mut ViewContext) { + let app = cx.as_ref(); let mut selections = self.selections(app).to_vec(); let mut state = self.add_selections_state.take().unwrap_or_else(|| { @@ -1760,14 +1753,14 @@ impl Editor { state.stack.pop(); } - self.update_selections(new_selections, true, ctx); + self.update_selections(new_selections, true, cx); if state.stack.len() > 1 { self.add_selections_state = Some(state); } } - pub fn select_larger_syntax_node(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn select_larger_syntax_node(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let buffer = self.buffer.read(app); let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); @@ -1798,22 +1791,22 @@ impl Editor { if selected_larger_node { stack.push(old_selections); - self.update_selections(new_selections, true, ctx); + self.update_selections(new_selections, true, cx); } self.select_larger_syntax_node_stack = stack; } - pub fn select_smaller_syntax_node(&mut self, _: &(), ctx: &mut ViewContext) { + pub fn select_smaller_syntax_node(&mut self, _: &(), cx: &mut ViewContext) { let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); if let Some(selections) = stack.pop() { - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } self.select_larger_syntax_node_stack = stack; } - pub fn move_to_enclosing_bracket(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx.as_ref()); - let mut selections = self.selections(ctx.as_ref()).to_vec(); + pub fn move_to_enclosing_bracket(&mut self, _: &(), cx: &mut ViewContext) { + let buffer = self.buffer.read(cx.as_ref()); + let mut selections = self.selections(cx.as_ref()).to_vec(); for selection in &mut selections { let selection_range = selection.offset_range(buffer); if let Some((open_range, close_range)) = @@ -1832,7 +1825,7 @@ impl Editor { } } - self.update_selections(selections, true, ctx); + self.update_selections(selections, true, cx); } fn build_columnar_selection( @@ -1840,17 +1833,17 @@ impl Editor { row: u32, columns: &Range, reversed: bool, - ctx: &AppContext, + cx: &AppContext, ) -> Option { let is_empty = columns.start == columns.end; - let line_len = self.display_map.line_len(row, ctx); + let line_len = self.display_map.line_len(row, cx); if columns.start < line_len || (is_empty && columns.start == line_len) { let start = DisplayPoint::new(row, columns.start); let end = DisplayPoint::new(row, cmp::min(columns.end, line_len)); Some(Selection { id: post_inc(&mut self.next_selection_id), - start: self.display_map.anchor_before(start, Bias::Left, ctx), - end: self.display_map.anchor_before(end, Bias::Left, ctx), + start: self.display_map.anchor_before(start, Bias::Left, cx), + end: self.display_map.anchor_before(end, Bias::Left, cx), reversed, goal: SelectionGoal::ColumnRange { start: columns.start, @@ -1865,28 +1858,28 @@ impl Editor { pub fn selections_in_range<'a>( &'a self, range: Range, - app: &'a AppContext, + cx: &'a AppContext, ) -> impl 'a + Iterator> { - let start = self.display_map.anchor_before(range.start, Bias::Left, app); - let start_index = self.selection_insertion_index(&start, app); + let start = self.display_map.anchor_before(range.start, Bias::Left, cx); + let start_index = self.selection_insertion_index(&start, cx); let pending_selection = self.pending_selection.as_ref().and_then(|s| { - let selection_range = s.display_range(&self.display_map, app); + let selection_range = s.display_range(&self.display_map, cx); if selection_range.start <= range.end || selection_range.end <= range.end { Some(selection_range) } else { None } }); - self.selections(app)[start_index..] + self.selections(cx)[start_index..] .iter() - .map(move |s| s.display_range(&self.display_map, app)) + .map(move |s| s.display_range(&self.display_map, cx)) .take_while(move |r| r.start <= range.end || r.end <= range.end) .chain(pending_selection) } - fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize { - let buffer = self.buffer.read(app); - let selections = self.selections(app); + fn selection_insertion_index(&self, start: &Anchor, cx: &AppContext) -> usize { + let buffer = self.buffer.read(cx); + let selections = self.selections(cx); match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) { Ok(index) => index, Err(index) => { @@ -1901,9 +1894,9 @@ impl Editor { } } - fn selections<'a>(&self, app: &'a AppContext) -> &'a [Selection] { + fn selections<'a>(&self, cx: &'a AppContext) -> &'a [Selection] { self.buffer - .read(app) + .read(cx) .selections(self.selection_set_id) .unwrap() } @@ -1912,10 +1905,10 @@ impl Editor { &mut self, mut selections: Vec, autoscroll: bool, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { // Merge overlapping selections. - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); let mut i = 1; while i < selections.len() { if selections[i - 1] @@ -1936,34 +1929,34 @@ impl Editor { } } - self.buffer.update(ctx, |buffer, ctx| { + self.buffer.update(cx, |buffer, cx| { buffer - .update_selection_set(self.selection_set_id, selections, Some(ctx)) + .update_selection_set(self.selection_set_id, selections, Some(cx)) .unwrap() }); - self.pause_cursor_blinking(ctx); + self.pause_cursor_blinking(cx); if autoscroll { *self.autoscroll_requested.lock() = true; - ctx.notify(); + cx.notify(); } self.add_selections_state = None; self.select_larger_syntax_node_stack.clear(); } - fn start_transaction(&self, ctx: &mut ViewContext) { - self.buffer.update(ctx, |buffer, _| { + fn start_transaction(&self, cx: &mut ViewContext) { + self.buffer.update(cx, |buffer, _| { buffer .start_transaction(Some(self.selection_set_id)) .unwrap() }); } - fn end_transaction(&self, ctx: &mut ViewContext) { - self.buffer.update(ctx, |buffer, ctx| { + fn end_transaction(&self, cx: &mut ViewContext) { + self.buffer.update(cx, |buffer, cx| { buffer - .end_transaction(Some(self.selection_set_id), Some(ctx)) + .end_transaction(Some(self.selection_set_id), Some(cx)) .unwrap() }); } @@ -1976,10 +1969,10 @@ impl Editor { log::info!("BufferView::page_down"); } - pub fn fold(&mut self, _: &(), ctx: &mut ViewContext) { + pub fn fold(&mut self, _: &(), cx: &mut ViewContext) { let mut fold_ranges = Vec::new(); - let app = ctx.as_ref(); + let app = cx.as_ref(); for selection in self.selections(app) { let range = selection.display_range(&self.display_map, app).sorted(); let buffer_start_row = range @@ -1989,7 +1982,7 @@ impl Editor { for row in (0..=range.end.row()).rev() { if self.is_line_foldable(row, app) - && !self.display_map.is_line_folded(row, ctx.as_ref()) + && !self.display_map.is_line_folded(row, cx.as_ref()) { let fold_range = self.foldable_range_for_line(row, app); if fold_range.end.row >= buffer_start_row { @@ -2002,11 +1995,11 @@ impl Editor { } } - self.fold_ranges(fold_ranges, ctx); + self.fold_ranges(fold_ranges, cx); } - pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext) { - let app = ctx.as_ref(); + pub fn unfold(&mut self, _: &(), cx: &mut ViewContext) { + let app = cx.as_ref(); let buffer = self.buffer.read(app); let ranges = self .selections(app) @@ -2024,20 +2017,20 @@ impl Editor { start..end }) .collect::>(); - self.unfold_ranges(ranges, ctx); + self.unfold_ranges(ranges, cx); } - fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool { - let max_point = self.max_point(app); + fn is_line_foldable(&self, display_row: u32, cx: &AppContext) -> bool { + let max_point = self.max_point(cx); if display_row >= max_point.row() { false } else { - let (start_indent, is_blank) = self.display_map.line_indent(display_row, app); + let (start_indent, is_blank) = self.display_map.line_indent(display_row, cx); if is_blank { false } else { for display_row in display_row + 1..=max_point.row() { - let (indent, is_blank) = self.display_map.line_indent(display_row, app); + let (indent, is_blank) = self.display_map.line_indent(display_row, cx); if !is_blank { return indent > start_indent; } @@ -2047,69 +2040,69 @@ impl Editor { } } - fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Range { - let max_point = self.max_point(app); + fn foldable_range_for_line(&self, start_row: u32, cx: &AppContext) -> Range { + let max_point = self.max_point(cx); - let (start_indent, _) = self.display_map.line_indent(start_row, app); - let start = DisplayPoint::new(start_row, self.line_len(start_row, app)); + let (start_indent, _) = self.display_map.line_indent(start_row, cx); + let start = DisplayPoint::new(start_row, self.line_len(start_row, cx)); let mut end = None; for row in start_row + 1..=max_point.row() { - let (indent, is_blank) = self.display_map.line_indent(row, app); + let (indent, is_blank) = self.display_map.line_indent(row, cx); if !is_blank && indent <= start_indent { - end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, app))); + end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, cx))); break; } } let end = end.unwrap_or(max_point); - return start.to_buffer_point(&self.display_map, Bias::Left, app) - ..end.to_buffer_point(&self.display_map, Bias::Left, app); + return start.to_buffer_point(&self.display_map, Bias::Left, cx) + ..end.to_buffer_point(&self.display_map, Bias::Left, cx); } - pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.read(ctx); + pub fn fold_selected_ranges(&mut self, _: &(), cx: &mut ViewContext) { + let buffer = self.buffer.read(cx); let ranges = self - .selections(ctx.as_ref()) + .selections(cx.as_ref()) .iter() .map(|s| s.point_range(buffer).sorted()) .collect(); - self.fold_ranges(ranges, ctx); + self.fold_ranges(ranges, cx); } - fn fold_ranges(&mut self, ranges: Vec>, ctx: &mut ViewContext) { + fn fold_ranges(&mut self, ranges: Vec>, cx: &mut ViewContext) { if !ranges.is_empty() { - self.display_map.fold(ranges, ctx.as_ref()); + self.display_map.fold(ranges, cx.as_ref()); *self.autoscroll_requested.lock() = true; - ctx.notify(); + cx.notify(); } } - fn unfold_ranges(&mut self, ranges: Vec>, ctx: &mut ViewContext) { + fn unfold_ranges(&mut self, ranges: Vec>, cx: &mut ViewContext) { if !ranges.is_empty() { - self.display_map.unfold(ranges, ctx.as_ref()); + self.display_map.unfold(ranges, cx.as_ref()); *self.autoscroll_requested.lock() = true; - ctx.notify(); + cx.notify(); } } - pub fn line(&self, display_row: u32, ctx: &AppContext) -> String { - self.display_map.line(display_row, ctx) + pub fn line(&self, display_row: u32, cx: &AppContext) -> String { + self.display_map.line(display_row, cx) } - pub fn line_len(&self, display_row: u32, ctx: &AppContext) -> u32 { - self.display_map.line_len(display_row, ctx) + pub fn line_len(&self, display_row: u32, cx: &AppContext) -> u32 { + self.display_map.line_len(display_row, cx) } - pub fn longest_row(&self, ctx: &AppContext) -> u32 { - self.display_map.longest_row(ctx) + pub fn longest_row(&self, cx: &AppContext) -> u32 { + self.display_map.longest_row(cx) } - pub fn max_point(&self, ctx: &AppContext) -> DisplayPoint { - self.display_map.max_point(ctx) + pub fn max_point(&self, cx: &AppContext) -> DisplayPoint { + self.display_map.max_point(cx) } - pub fn text(&self, ctx: &AppContext) -> String { - self.display_map.text(ctx) + pub fn text(&self, cx: &AppContext) -> String { + self.display_map.text(cx) } pub fn font_size(&self) -> f32 { @@ -2147,13 +2140,13 @@ impl Editor { &self, font_cache: &FontCache, layout_cache: &TextLayoutCache, - app: &AppContext, + cx: &AppContext, ) -> Result { let settings = self.settings.borrow(); let font_size = settings.buffer_font_size; let font_id = font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; - let digit_count = (self.buffer.read(app).row_count() as f32).log10().floor() as usize + 1; + let digit_count = (self.buffer.read(cx).row_count() as f32).log10().floor() as usize + 1; Ok(layout_cache .layout_str( @@ -2169,7 +2162,7 @@ impl Editor { viewport_height: f32, font_cache: &FontCache, layout_cache: &TextLayoutCache, - ctx: &AppContext, + cx: &AppContext, ) -> Result> { let settings = self.settings.borrow(); let font_size = settings.buffer_font_size; @@ -2178,7 +2171,7 @@ impl Editor { let start_row = self.scroll_position().y() as usize; let end_row = cmp::min( - self.max_point(ctx).row() as usize, + self.max_point(cx).row() as usize, start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize, ); let line_count = end_row - start_row + 1; @@ -2187,7 +2180,7 @@ impl Editor { let mut line_number = String::new(); for buffer_row in self .display_map - .snapshot(ctx) + .snapshot(cx) .buffer_rows(start_row as u32) .take(line_count) { @@ -2208,9 +2201,9 @@ impl Editor { mut rows: Range, font_cache: &FontCache, layout_cache: &TextLayoutCache, - ctx: &AppContext, + cx: &AppContext, ) -> Result> { - rows.end = cmp::min(rows.end, self.display_map.max_point(ctx).row() + 1); + rows.end = cmp::min(rows.end, self.display_map.max_point(cx).row() + 1); if rows.start >= rows.end { return Ok(Vec::new()); } @@ -2227,7 +2220,7 @@ impl Editor { let mut line = String::new(); let mut styles = Vec::new(); let mut row = rows.start; - let mut snapshot = self.display_map.snapshot(ctx); + let mut snapshot = self.display_map.snapshot(cx); let chunks = snapshot.highlighted_chunks_for_rows(rows.clone()); let theme = settings.theme.clone(); @@ -2267,18 +2260,18 @@ impl Editor { row: u32, font_cache: &FontCache, layout_cache: &TextLayoutCache, - app: &AppContext, + cx: &AppContext, ) -> Result { let settings = self.settings.borrow(); let font_id = font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?; - let line = self.line(row, app); + let line = self.line(row, cx); Ok(layout_cache.layout_str( &line, settings.buffer_font_size, - &[(self.line_len(row, app) as usize, font_id, ColorU::black())], + &[(self.line_len(row, cx) as usize, font_id, ColorU::black())], )) } @@ -2287,36 +2280,36 @@ impl Editor { self.blink_epoch } - fn pause_cursor_blinking(&mut self, ctx: &mut ViewContext) { + fn pause_cursor_blinking(&mut self, cx: &mut ViewContext) { self.cursors_visible = true; - ctx.notify(); + cx.notify(); let epoch = self.next_blink_epoch(); - ctx.spawn(|this, mut ctx| async move { + cx.spawn(|this, mut cx| async move { Timer::after(CURSOR_BLINK_INTERVAL).await; - this.update(&mut ctx, |this, ctx| { - this.resume_cursor_blinking(epoch, ctx); + this.update(&mut cx, |this, cx| { + this.resume_cursor_blinking(epoch, cx); }) }) .detach(); } - fn resume_cursor_blinking(&mut self, epoch: usize, ctx: &mut ViewContext) { + fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext) { if epoch == self.blink_epoch { self.blinking_paused = false; - self.blink_cursors(epoch, ctx); + self.blink_cursors(epoch, cx); } } - fn blink_cursors(&mut self, epoch: usize, ctx: &mut ViewContext) { + fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext) { if epoch == self.blink_epoch && self.focused && !self.blinking_paused { self.cursors_visible = !self.cursors_visible; - ctx.notify(); + cx.notify(); let epoch = self.next_blink_epoch(); - ctx.spawn(|this, mut ctx| async move { + cx.spawn(|this, mut cx| async move { Timer::after(CURSOR_BLINK_INTERVAL).await; - this.update(&mut ctx, |this, ctx| this.blink_cursors(epoch, ctx)); + this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx)); }) .detach(); } @@ -2326,22 +2319,22 @@ impl Editor { self.cursors_visible } - fn on_buffer_changed(&mut self, _: ModelHandle, ctx: &mut ViewContext) { - ctx.notify(); + fn on_buffer_changed(&mut self, _: ModelHandle, cx: &mut ViewContext) { + cx.notify(); } fn on_buffer_event( &mut self, _: ModelHandle, event: &buffer::Event, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { match event { - buffer::Event::Edited => ctx.emit(Event::Edited), - buffer::Event::Dirtied => ctx.emit(Event::Dirtied), - buffer::Event::Saved => ctx.emit(Event::Saved), - buffer::Event::FileHandleChanged => ctx.emit(Event::FileHandleChanged), - buffer::Event::Reloaded => ctx.emit(Event::FileHandleChanged), + buffer::Event::Edited => cx.emit(Event::Edited), + buffer::Event::Dirtied => cx.emit(Event::Dirtied), + buffer::Event::Saved => cx.emit(Event::Saved), + buffer::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged), + buffer::Event::Reloaded => cx.emit(Event::FileHandleChanged), buffer::Event::Reparsed => {} } } @@ -2369,16 +2362,16 @@ impl View for Editor { "BufferView" } - fn on_focus(&mut self, ctx: &mut ViewContext) { + fn on_focus(&mut self, cx: &mut ViewContext) { self.focused = true; - self.blink_cursors(self.blink_epoch, ctx); + self.blink_cursors(self.blink_epoch, cx); } - fn on_blur(&mut self, ctx: &mut ViewContext) { + fn on_blur(&mut self, cx: &mut ViewContext) { self.focused = false; self.cursors_visible = false; - ctx.emit(Event::Blurred); - ctx.notify(); + cx.emit(Event::Blurred); + cx.notify(); } } @@ -2392,9 +2385,9 @@ impl workspace::Item for Buffer { fn build_view( handle: ModelHandle, settings: watch::Receiver, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::View { - Editor::for_buffer(handle, settings, ctx) + Editor::for_buffer(handle, settings, cx) } } @@ -2410,12 +2403,12 @@ impl workspace::ItemView for Editor { ) } - fn title(&self, app: &AppContext) -> std::string::String { + fn title(&self, cx: &AppContext) -> std::string::String { let filename = self .buffer - .read(app) + .read(cx) .file() - .and_then(|file| file.file_name(app)); + .and_then(|file| file.file_name(cx)); if let Some(name) = filename { name.to_string_lossy().into() } else { @@ -2423,15 +2416,15 @@ impl workspace::ItemView for Editor { } } - fn entry_id(&self, ctx: &AppContext) -> Option<(usize, Arc)> { - self.buffer.read(ctx).file().map(|file| file.entry_id()) + fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc)> { + self.buffer.read(cx).file().map(|file| file.entry_id()) } - fn clone_on_split(&self, ctx: &mut ViewContext) -> Option + fn clone_on_split(&self, cx: &mut ViewContext) -> Option where Self: Sized, { - let clone = Editor::for_buffer(self.buffer.clone(), self.settings.clone(), ctx); + let clone = Editor::for_buffer(self.buffer.clone(), self.settings.clone(), cx); *clone.scroll_position.lock() = *self.scroll_position.lock(); Some(clone) } @@ -2439,17 +2432,17 @@ impl workspace::ItemView for Editor { fn save( &mut self, new_file: Option, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Task> { - self.buffer.update(ctx, |b, ctx| b.save(new_file, ctx)) + self.buffer.update(cx, |b, cx| b.save(new_file, cx)) } - fn is_dirty(&self, ctx: &AppContext) -> bool { - self.buffer.read(ctx).is_dirty() + fn is_dirty(&self, cx: &AppContext) -> bool { + self.buffer.read(cx).is_dirty() } - fn has_conflict(&self, ctx: &AppContext) -> bool { - self.buffer.read(ctx).has_conflict() + fn has_conflict(&self, cx: &AppContext) -> bool { + self.buffer.read(cx).has_conflict() } } @@ -2465,20 +2458,20 @@ mod tests { use unindent::Unindent; #[gpui::test] - fn test_selection_with_mouse(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, buffer_view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, buffer_view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); - buffer_view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(2, 2), false, ctx); + buffer_view.update(cx, |view, cx| { + view.begin_selection(DisplayPoint::new(2, 2), false, cx); }); - let view = buffer_view.read(app); + let view = buffer_view.read(cx); let selections = view .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), + DisplayPoint::zero()..view.max_point(cx.as_ref()), + cx.as_ref(), ) .collect::>(); assert_eq!( @@ -2486,15 +2479,15 @@ mod tests { [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] ); - buffer_view.update(app, |view, ctx| { - view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); + buffer_view.update(cx, |view, cx| { + view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx); }); - let view = buffer_view.read(app); + let view = buffer_view.read(cx); let selections = view .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), + DisplayPoint::zero()..view.max_point(cx.as_ref()), + cx.as_ref(), ) .collect::>(); assert_eq!( @@ -2502,15 +2495,15 @@ mod tests { [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] ); - buffer_view.update(app, |view, ctx| { - view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); + buffer_view.update(cx, |view, cx| { + view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx); }); - let view = buffer_view.read(app); + let view = buffer_view.read(cx); let selections = view .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), + DisplayPoint::zero()..view.max_point(cx.as_ref()), + cx.as_ref(), ) .collect::>(); assert_eq!( @@ -2518,16 +2511,16 @@ mod tests { [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] ); - buffer_view.update(app, |view, ctx| { - view.end_selection(ctx); - view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); + buffer_view.update(cx, |view, cx| { + view.end_selection(cx); + view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx); }); - let view = buffer_view.read(app); + let view = buffer_view.read(cx); let selections = view .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), + DisplayPoint::zero()..view.max_point(cx.as_ref()), + cx.as_ref(), ) .collect::>(); assert_eq!( @@ -2535,16 +2528,16 @@ mod tests { [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)] ); - buffer_view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(3, 3), true, ctx); - view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx); + buffer_view.update(cx, |view, cx| { + view.begin_selection(DisplayPoint::new(3, 3), true, cx); + view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx); }); - let view = buffer_view.read(app); + let view = buffer_view.read(cx); let selections = view .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), + DisplayPoint::zero()..view.max_point(cx.as_ref()), + cx.as_ref(), ) .collect::>(); assert_eq!( @@ -2555,15 +2548,15 @@ mod tests { ] ); - buffer_view.update(app, |view, ctx| { - view.end_selection(ctx); + buffer_view.update(cx, |view, cx| { + view.end_selection(cx); }); - let view = buffer_view.read(app); + let view = buffer_view.read(cx); let selections = view .selections_in_range( - DisplayPoint::zero()..view.max_point(app.as_ref()), - app.as_ref(), + DisplayPoint::zero()..view.max_point(cx.as_ref()), + cx.as_ref(), ) .collect::>(); assert_eq!( @@ -2573,93 +2566,93 @@ mod tests { } #[gpui::test] - fn test_canceling_pending_selection(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); - view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(2, 2), false, ctx); + view.update(cx, |view, cx| { + view.begin_selection(DisplayPoint::new(2, 2), false, cx); }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] ); - view.update(app, |view, ctx| { - view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx); + view.update(cx, |view, cx| { + view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx); }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] ); - view.update(app, |view, ctx| { - view.cancel(&(), ctx); - view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); + view.update(cx, |view, cx| { + view.cancel(&(), cx); + view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx); }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)] ); } #[gpui::test] - fn test_cancel(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - - view.update(app, |view, ctx| { - view.begin_selection(DisplayPoint::new(3, 4), false, ctx); - view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx); - view.end_selection(ctx); - - view.begin_selection(DisplayPoint::new(0, 1), true, ctx); - view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), ctx); - view.end_selection(ctx); + fn test_cancel(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + + view.update(cx, |view, cx| { + view.begin_selection(DisplayPoint::new(3, 4), false, cx); + view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx); + view.end_selection(cx); + + view.begin_selection(DisplayPoint::new(0, 1), true, cx); + view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx); + view.end_selection(cx); }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1), ] ); - view.update(app, |view, ctx| view.cancel(&(), ctx)); + view.update(cx, |view, cx| view.cancel(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)] ); - view.update(app, |view, ctx| view.cancel(&(), ctx)); + view.update(cx, |view, cx| view.cancel(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)] ); } #[gpui::test] - fn test_layout_line_numbers(app: &mut gpui::MutableAppContext) { - let layout_cache = TextLayoutCache::new(app.platform().fonts()); - let font_cache = app.font_cache().clone(); + fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) { + let layout_cache = TextLayoutCache::new(cx.platform().fonts()); + let font_cache = cx.font_cache().clone(); - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx)); let settings = settings::channel(&font_cache).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); let layouts = view - .read(app) - .layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref()) + .read(cx) + .layout_line_numbers(1000.0, &font_cache, &layout_cache, cx.as_ref()) .unwrap(); assert_eq!(layouts.len(), 6); } #[gpui::test] - fn test_fold(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| { + fn test_fold(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| { Buffer::new( 0, " @@ -2680,18 +2673,18 @@ mod tests { } " .unindent(), - ctx, + cx, ) }); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], ctx) + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], cx) .unwrap(); - view.fold(&(), ctx); + view.fold(&(), cx); assert_eq!( - view.text(ctx.as_ref()), + view.text(cx.as_ref()), " impl Foo { // Hello! @@ -2710,9 +2703,9 @@ mod tests { .unindent(), ); - view.fold(&(), ctx); + view.fold(&(), cx); assert_eq!( - view.text(ctx.as_ref()), + view.text(cx.as_ref()), " impl Foo {… } @@ -2720,9 +2713,9 @@ mod tests { .unindent(), ); - view.unfold(&(), ctx); + view.unfold(&(), cx); assert_eq!( - view.text(ctx.as_ref()), + view.text(cx.as_ref()), " impl Foo { // Hello! @@ -2741,18 +2734,18 @@ mod tests { .unindent(), ); - view.unfold(&(), ctx); - assert_eq!(view.text(ctx.as_ref()), buffer.read(ctx).text()); + view.unfold(&(), cx); + assert_eq!(view.text(cx.as_ref()), buffer.read(cx).text()); }); } #[gpui::test] - fn test_move_cursor(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + fn test_move_cursor(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); - buffer.update(app, |buffer, ctx| { + buffer.update(cx, |buffer, cx| { buffer .edit( vec![ @@ -2760,263 +2753,263 @@ mod tests { Point::new(1, 1)..Point::new(1, 1), ], "\t", - Some(ctx), + Some(cx), ) .unwrap(); }); - view.update(app, |view, ctx| { + view.update(cx, |view, cx| { assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); - view.move_down(&(), ctx); + view.move_down(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); - view.move_right(&(), ctx); + view.move_right(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] ); - view.move_left(&(), ctx); + view.move_left(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); - view.move_up(&(), ctx); + view.move_up(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); - view.move_to_end(&(), ctx); + view.move_to_end(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)] ); - view.move_to_beginning(&(), ctx); + view.move_to_beginning(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); - view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], ctx) + view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], cx) .unwrap(); - view.select_to_beginning(&(), ctx); + view.select_to_beginning(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)] ); - view.select_to_end(&(), ctx); + view.select_to_end(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)] ); }); } #[gpui::test] - fn test_move_cursor_multibyte(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); assert_eq!('ⓐ'.len_utf8(), 3); assert_eq!('α'.len_utf8(), 2); - view.update(app, |view, ctx| { + view.update(cx, |view, cx| { view.fold_ranges( vec![ Point::new(0, 6)..Point::new(0, 12), Point::new(1, 2)..Point::new(1, 4), Point::new(2, 4)..Point::new(2, 8), ], - ctx, + cx, ); - assert_eq!(view.text(ctx.as_ref()), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n"); + assert_eq!(view.text(cx.as_ref()), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n"); - view.move_right(&(), ctx); + view.move_right(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(0, "ⓐ".len())] ); - view.move_right(&(), ctx); + view.move_right(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(0, "ⓐⓑ".len())] ); - view.move_right(&(), ctx); + view.move_right(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(0, "ⓐⓑ…".len())] ); - view.move_down(&(), ctx); + view.move_down(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(1, "ab…".len())] ); - view.move_left(&(), ctx); + view.move_left(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(1, "ab".len())] ); - view.move_left(&(), ctx); + view.move_left(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(1, "a".len())] ); - view.move_down(&(), ctx); + view.move_down(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(2, "α".len())] ); - view.move_right(&(), ctx); + view.move_right(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(2, "αβ".len())] ); - view.move_right(&(), ctx); + view.move_right(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(2, "αβ…".len())] ); - view.move_right(&(), ctx); + view.move_right(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(2, "αβ…ε".len())] ); - view.move_up(&(), ctx); + view.move_up(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(1, "ab…e".len())] ); - view.move_up(&(), ctx); + view.move_up(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(0, "ⓐⓑ…ⓔ".len())] ); - view.move_left(&(), ctx); + view.move_left(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(0, "ⓐⓑ…".len())] ); - view.move_left(&(), ctx); + view.move_left(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(0, "ⓐⓑ".len())] ); - view.move_left(&(), ctx); + view.move_left(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(0, "ⓐ".len())] ); }); } #[gpui::test] - fn test_move_cursor_different_line_lengths(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], ctx) + fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); + view.update(cx, |view, cx| { + view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], cx) .unwrap(); - view.move_down(&(), ctx); + view.move_down(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(1, "abcd".len())] ); - view.move_down(&(), ctx); + view.move_down(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(2, "αβγ".len())] ); - view.move_down(&(), ctx); + view.move_down(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(3, "abcd".len())] ); - view.move_down(&(), ctx); + view.move_down(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())] ); - view.move_up(&(), ctx); + view.move_up(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(3, "abcd".len())] ); - view.move_up(&(), ctx); + view.move_up(&(), cx); assert_eq!( - view.selection_ranges(ctx.as_ref()), + view.selection_ranges(cx.as_ref()), &[empty_range(2, "αβγ".len())] ); }); } #[gpui::test] - fn test_beginning_end_of_line(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\n def", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "abc\n def", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), ], - ctx, + cx, ) .unwrap(); }); - view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); + view.update(cx, |view, cx| view.move_to_beginning_of_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), ] ); - view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); + view.update(cx, |view, cx| view.move_to_beginning_of_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), ] ); - view.update(app, |view, ctx| view.move_to_beginning_of_line(&(), ctx)); + view.update(cx, |view, cx| view.move_to_beginning_of_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), ] ); - view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx)); + view.update(cx, |view, cx| view.move_to_end_of_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), @@ -3024,72 +3017,68 @@ mod tests { ); // Moving to the end of line again is a no-op. - view.update(app, |view, ctx| view.move_to_end_of_line(&(), ctx)); + view.update(cx, |view, cx| view.move_to_end_of_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), ] ); - view.update(app, |view, ctx| { - view.move_left(&(), ctx); - view.select_to_beginning_of_line(&true, ctx); + view.update(cx, |view, cx| { + view.move_left(&(), cx); + view.select_to_beginning_of_line(&true, cx); }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), ] ); - view.update(app, |view, ctx| { - view.select_to_beginning_of_line(&true, ctx) - }); + view.update(cx, |view, cx| view.select_to_beginning_of_line(&true, cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0), ] ); - view.update(app, |view, ctx| { - view.select_to_beginning_of_line(&true, ctx) - }); + view.update(cx, |view, cx| view.select_to_beginning_of_line(&true, cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0), DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2), ] ); - view.update(app, |view, ctx| view.select_to_end_of_line(&(), ctx)); + view.update(cx, |view, cx| view.select_to_end_of_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5), ] ); - view.update(app, |view, ctx| view.delete_to_end_of_line(&(), ctx)); - assert_eq!(view.read(app).text(app.as_ref()), "ab\n de"); + view.update(cx, |view, cx| view.delete_to_end_of_line(&(), cx)); + assert_eq!(view.read(cx).text(cx.as_ref()), "ab\n de"); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4), ] ); - view.update(app, |view, ctx| view.delete_to_beginning_of_line(&(), ctx)); - assert_eq!(view.read(app).text(app.as_ref()), "\n"); + view.update(cx, |view, cx| view.delete_to_beginning_of_line(&(), cx)); + assert_eq!(view.read(cx).text(cx.as_ref()), "\n"); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), @@ -3098,178 +3087,166 @@ mod tests { } #[gpui::test] - fn test_prev_next_word_boundary(app: &mut gpui::MutableAppContext) { + fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) { let buffer = - app.add_model(|ctx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + cx.add_model(|cx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11), DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4), ], - ctx, + cx, ) .unwrap(); }); - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); + view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), ] ); - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); + view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), ] ); - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); + view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), ] ); - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); + view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), ] ); - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); + view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), ] ); - view.update(app, |view, ctx| { - view.move_to_previous_word_boundary(&(), ctx) - }); + view.update(cx, |view, cx| view.move_to_previous_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23), ] ); - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24), ] ); - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4), DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), ] ); - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7), DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0), ] ); - view.update(app, |view, ctx| view.move_to_next_word_boundary(&(), ctx)); + view.update(cx, |view, cx| view.move_to_next_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), ] ); - view.update(app, |view, ctx| { - view.move_right(&(), ctx); - view.select_to_previous_word_boundary(&(), ctx); + view.update(cx, |view, cx| { + view.move_right(&(), cx); + view.select_to_previous_word_boundary(&(), cx); }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), ] ); - view.update(app, |view, ctx| { - view.select_to_previous_word_boundary(&(), ctx) + view.update(cx, |view, cx| { + view.select_to_previous_word_boundary(&(), cx) }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7), DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0), ] ); - view.update(app, |view, ctx| view.select_to_next_word_boundary(&(), ctx)); + view.update(cx, |view, cx| view.select_to_next_word_boundary(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9), DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2), ] ); - view.update(app, |view, ctx| view.delete_to_next_word_boundary(&(), ctx)); + view.update(cx, |view, cx| view.delete_to_next_word_boundary(&(), cx)); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "use std::s::{foo, bar}\n\n {az.qux()}" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10), DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3), ] ); - view.update(app, |view, ctx| { - view.delete_to_previous_word_boundary(&(), ctx) + view.update(cx, |view, cx| { + view.delete_to_previous_word_boundary(&(), cx) }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "use std::::{foo, bar}\n\n az.qux()}" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9), DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2), @@ -3278,18 +3255,18 @@ mod tests { } #[gpui::test] - fn test_backspace(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| { + fn test_backspace(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| { Buffer::new( 0, "one two three\nfour five six\nseven eight nine\nten\n", - ctx, + cx, ) }); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); - view.update(app, |view, ctx| { + view.update(cx, |view, cx| { view.select_display_ranges( &[ // an empty selection - the preceding character is deleted @@ -3299,31 +3276,31 @@ mod tests { // a line suffix selected - it is deleted DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0), ], - ctx, + cx, ) .unwrap(); - view.backspace(&(), ctx); + view.backspace(&(), cx); }); assert_eq!( - buffer.read(app).text(), + buffer.read(cx).text(), "oe two three\nfou five six\nseven ten\n" ); } #[gpui::test] - fn test_delete(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| { + fn test_delete(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| { Buffer::new( 0, "one two three\nfour five six\nseven eight nine\nten\n", - ctx, + cx, ) }); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)); - view.update(app, |view, ctx| { + view.update(cx, |view, cx| { view.select_display_ranges( &[ // an empty selection - the following character is deleted @@ -3333,65 +3310,65 @@ mod tests { // a line suffix selected - it is deleted DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0), ], - ctx, + cx, ) .unwrap(); - view.delete(&(), ctx); + view.delete(&(), cx); }); assert_eq!( - buffer.read(app).text(), + buffer.read(cx).text(), "on two three\nfou five six\nseven ten\n" ); } #[gpui::test] - fn test_delete_line(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + fn test_delete_line(cx: &mut gpui::MutableAppContext) { + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), ], - ctx, + cx, ) .unwrap(); - view.delete_line(&(), ctx); + view.delete_line(&(), cx); }); - assert_eq!(view.read(app).text(app.as_ref()), "ghi"); + assert_eq!(view.read(cx).text(cx.as_ref()), "ghi"); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0), DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1) ] ); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], ctx) + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], cx) .unwrap(); - view.delete_line(&(), ctx); + view.delete_line(&(), cx); }); - assert_eq!(view.read(app).text(app.as_ref()), "ghi\n"); + assert_eq!(view.read(cx).text(cx.as_ref()), "ghi\n"); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] ); } #[gpui::test] - fn test_duplicate_line(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + fn test_duplicate_line(cx: &mut gpui::MutableAppContext) { + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), @@ -3399,17 +3376,17 @@ mod tests { DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), ], - ctx, + cx, ) .unwrap(); - view.duplicate_line(&(), ctx); + view.duplicate_line(&(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "abc\nabc\ndef\ndef\nghi\n\n" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1), DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2), @@ -3418,26 +3395,26 @@ mod tests { ] ); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1), DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1), ], - ctx, + cx, ) .unwrap(); - view.duplicate_line(&(), ctx); + view.duplicate_line(&(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "abc\ndef\nghi\nabc\ndef\nghi\n" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1), DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1), @@ -3446,18 +3423,18 @@ mod tests { } #[gpui::test] - fn test_move_line_up_down(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(10, 5), ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) { + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(10, 5), cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.fold_ranges( vec![ Point::new(0, 2)..Point::new(1, 2), Point::new(2, 3)..Point::new(4, 1), Point::new(7, 0)..Point::new(8, 4), ], - ctx, + cx, ); view.select_display_ranges( &[ @@ -3466,22 +3443,22 @@ mod tests { DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3), DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2), ], - ctx, + cx, ) .unwrap(); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj" ); - view.update(app, |view, ctx| view.move_line_up(&(), ctx)); + view.update(cx, |view, cx| view.move_line_up(&(), cx)); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), @@ -3490,13 +3467,13 @@ mod tests { ] ); - view.update(app, |view, ctx| view.move_line_down(&(), ctx)); + view.update(cx, |view, cx| view.move_line_down(&(), cx)); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), @@ -3505,13 +3482,13 @@ mod tests { ] ); - view.update(app, |view, ctx| view.move_line_down(&(), ctx)); + view.update(cx, |view, cx| view.move_line_down(&(), cx)); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1), @@ -3520,13 +3497,13 @@ mod tests { ] ); - view.update(app, |view, ctx| view.move_line_up(&(), ctx)); + view.update(cx, |view, cx| view.move_line_up(&(), cx)); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), @@ -3537,31 +3514,31 @@ mod tests { } #[gpui::test] - fn test_clipboard(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let view = app - .add_window(|ctx| Editor::for_buffer(buffer.clone(), settings, ctx)) + fn test_clipboard(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "one two three four five six ", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let view = cx + .add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx)) .1; // Cut with three selections. Clipboard text is divided into three slices. - view.update(app, |view, ctx| { - view.select_ranges(vec![0..4, 8..14, 19..24], false, ctx); - view.cut(&(), ctx); + view.update(cx, |view, cx| { + view.select_ranges(vec![0..4, 8..14, 19..24], false, cx); + view.cut(&(), cx); }); - assert_eq!(view.read(app).text(app.as_ref()), "two four six "); + assert_eq!(view.read(cx).text(cx.as_ref()), "two four six "); // Paste with three cursors. Each cursor pastes one slice of the clipboard text. - view.update(app, |view, ctx| { - view.select_ranges(vec![4..4, 9..9, 13..13], false, ctx); - view.paste(&(), ctx); + view.update(cx, |view, cx| { + view.select_ranges(vec![4..4, 9..9, 13..13], false, cx); + view.paste(&(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "two one four three six five " ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8), DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19), @@ -3572,64 +3549,64 @@ mod tests { // Paste again but with only two cursors. Since the number of cursors doesn't // match the number of slices in the clipboard, the entire clipboard text // is pasted at each cursor. - view.update(app, |view, ctx| { - view.select_ranges(vec![0..0, 28..28], false, ctx); - view.insert(&"( ".to_string(), ctx); - view.paste(&(), ctx); - view.insert(&") ".to_string(), ctx); + view.update(cx, |view, cx| { + view.select_ranges(vec![0..0, 28..28], false, cx); + view.insert(&"( ".to_string(), cx); + view.paste(&(), cx); + view.insert(&") ".to_string(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "( one three five ) two one four three six five ( one three five ) " ); - view.update(app, |view, ctx| { - view.select_ranges(vec![0..0], false, ctx); - view.insert(&"123\n4567\n89\n".to_string(), ctx); + view.update(cx, |view, cx| { + view.select_ranges(vec![0..0], false, cx); + view.insert(&"123\n4567\n89\n".to_string(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) " ); // Cut with three selections, one of which is full-line. - view.update(app, |view, ctx| { + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2), DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1), ], - ctx, + cx, ) .unwrap(); - view.cut(&(), ctx); + view.cut(&(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "13\n9\n( one three five ) two one four three six five ( one three five ) " ); // Paste with three selections, noticing how the copied selection that was full-line // gets inserted before the second cursor. - view.update(app, |view, ctx| { + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3), ], - ctx, + cx, ) .unwrap(); - view.paste(&(), ctx); + view.paste(&(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) " ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), @@ -3638,32 +3615,32 @@ mod tests { ); // Copy with a single cursor only, which writes the whole line into the clipboard. - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], ctx) + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], cx) .unwrap(); - view.copy(&(), ctx); + view.copy(&(), cx); }); // Paste with three selections, noticing how the copied full-line selection is inserted // before the empty selections but replaces the selection that is non-empty. - view.update(app, |view, ctx| { + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2), DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1), ], - ctx, + cx, ) .unwrap(); - view.paste(&(), ctx); + view.paste(&(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "123\n123\n123\n67\n123\n9\n( 8ne three five ) two one four three six five ( one three five ) " ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[ DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1), DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0), @@ -3673,23 +3650,23 @@ mod tests { } #[gpui::test] - fn test_select_all(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\nde\nfgh", ctx)); - let settings = settings::channel(&app.font_cache()).unwrap().1; - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |b, ctx| b.select_all(&(), ctx)); + fn test_select_all(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "abc\nde\nfgh", cx)); + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |b, cx| b.select_all(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)] ); } #[gpui::test] - fn test_select_line(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 5), ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + fn test_select_line(cx: &mut gpui::MutableAppContext) { + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 5), cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1), @@ -3697,48 +3674,48 @@ mod tests { DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2), ], - ctx, + cx, ) .unwrap(); - view.select_line(&(), ctx); + view.select_line(&(), cx); }); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0), DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0), ] ); - view.update(app, |view, ctx| view.select_line(&(), ctx)); + view.update(cx, |view, cx| view.select_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0), DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5), ] ); - view.update(app, |view, ctx| view.select_line(&(), ctx)); + view.update(cx, |view, cx| view.select_line(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)] ); } #[gpui::test] - fn test_split_selection_into_lines(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(9, 5), ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); - view.update(app, |view, ctx| { + fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) { + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(9, 5), cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); + view.update(cx, |view, cx| { view.fold_ranges( vec![ Point::new(0, 2)..Point::new(1, 2), Point::new(2, 3)..Point::new(4, 1), Point::new(7, 0)..Point::new(8, 4), ], - ctx, + cx, ); view.select_display_ranges( &[ @@ -3747,22 +3724,22 @@ mod tests { DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0), DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4), ], - ctx, + cx, ) .unwrap(); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i" ); - view.update(app, |view, ctx| view.split_selection_into_lines(&(), ctx)); + view.update(cx, |view, cx| view.split_selection_into_lines(&(), cx)); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2), @@ -3771,17 +3748,17 @@ mod tests { ] ); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)], ctx) + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(4, 0)..DisplayPoint::new(0, 1)], cx) .unwrap(); - view.split_selection_into_lines(&(), ctx); + view.split_selection_into_lines(&(), cx); }); assert_eq!( - view.read(app).text(app.as_ref()), + view.read(cx).text(cx.as_ref()), "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\n…i" ); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), [ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1), DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5), @@ -3796,98 +3773,98 @@ mod tests { } #[gpui::test] - fn test_add_selection_above_below(app: &mut gpui::MutableAppContext) { - let settings = settings::channel(&app.font_cache()).unwrap().1; - let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", ctx)); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, settings, ctx)); + fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) { + let settings = settings::channel(&cx.font_cache()).unwrap().1; + let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx)); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], ctx) + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], cx) .unwrap(); }); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_above(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) ] ); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_above(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3) ] ); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)] ); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) ] ); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3), DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3) ] ); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], ctx) + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], cx) .unwrap(); }); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) ] ); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3), DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3) ] ); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_above(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] ); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_above(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)] ); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], ctx) + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], cx) .unwrap(); }); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), @@ -3895,9 +3872,9 @@ mod tests { ] ); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), @@ -3906,9 +3883,9 @@ mod tests { ] ); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_above(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3), DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4), @@ -3916,13 +3893,13 @@ mod tests { ] ); - view.update(app, |view, ctx| { - view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], ctx) + view.update(cx, |view, cx| { + view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], cx) .unwrap(); }); - view.update(app, |view, ctx| view.add_selection_above(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_above(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1), DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), @@ -3931,9 +3908,9 @@ mod tests { ] ); - view.update(app, |view, ctx| view.add_selection_below(&(), ctx)); + view.update(cx, |view, cx| view.add_selection_below(&(), cx)); assert_eq!( - view.read(app).selection_ranges(app.as_ref()), + view.read(cx).selection_ranges(cx.as_ref()), vec![ DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1), DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1), @@ -3943,8 +3920,8 @@ mod tests { } #[gpui::test] - async fn test_select_larger_smaller_syntax_node(mut app: gpui::TestAppContext) { - let app_state = app.read(build_app_state); + async fn test_select_larger_smaller_syntax_node(mut cx: gpui::TestAppContext) { + let app_state = cx.read(build_app_state); let lang = app_state.language_registry.select_language("z.rs"); let text = r#" use mod1::mod2::{mod3, mod4}; @@ -3954,28 +3931,28 @@ mod tests { } "# .unindent(); - let buffer = app.add_model(|ctx| { + let buffer = cx.add_model(|cx| { let history = History::new(text.into()); - Buffer::from_history(0, history, None, lang.cloned(), ctx) + Buffer::from_history(0, history, None, lang.cloned(), cx) }); - let (_, view) = app.add_window(|ctx| Editor::for_buffer(buffer, app_state.settings, ctx)); - view.condition(&app, |view, ctx| !view.buffer.read(ctx).is_parsing()) + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, app_state.settings, cx)); + view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing()) .await; - view.update(&mut app, |view, ctx| { + view.update(&mut cx, |view, cx| { view.select_display_ranges( &[ DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18), ], - ctx, + cx, ) .unwrap(); - view.select_larger_syntax_node(&(), ctx); + view.select_larger_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[ DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), @@ -3983,50 +3960,50 @@ mod tests { ] ); - view.update(&mut app, |view, ctx| { - view.select_larger_syntax_node(&(), ctx); + view.update(&mut cx, |view, cx| { + view.select_larger_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[ DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), ] ); - view.update(&mut app, |view, ctx| { - view.select_larger_syntax_node(&(), ctx); + view.update(&mut cx, |view, cx| { + view.select_larger_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] ); // Trying to expand the selected syntax node one more time has no effect. - view.update(&mut app, |view, ctx| { - view.select_larger_syntax_node(&(), ctx); + view.update(&mut cx, |view, cx| { + view.select_larger_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[DisplayPoint::new(0, 0)..DisplayPoint::new(5, 0)] ); - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); + view.update(&mut cx, |view, cx| { + view.select_smaller_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[ DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0), ] ); - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); + view.update(&mut cx, |view, cx| { + view.select_smaller_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[ DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27), DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), @@ -4034,11 +4011,11 @@ mod tests { ] ); - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); + view.update(&mut cx, |view, cx| { + view.select_smaller_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[ DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), @@ -4047,11 +4024,11 @@ mod tests { ); // Trying to shrink the selected syntax node one more time has no effect. - view.update(&mut app, |view, ctx| { - view.select_smaller_syntax_node(&(), ctx); + view.update(&mut cx, |view, cx| { + view.select_smaller_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[ DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25), DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12), @@ -4061,18 +4038,18 @@ mod tests { // Ensure that we keep expanding the selection if the larger selection starts or ends within // a fold. - view.update(&mut app, |view, ctx| { + view.update(&mut cx, |view, cx| { view.fold_ranges( vec![ Point::new(0, 21)..Point::new(0, 24), Point::new(3, 20)..Point::new(3, 22), ], - ctx, + cx, ); - view.select_larger_syntax_node(&(), ctx); + view.select_larger_syntax_node(&(), cx); }); assert_eq!( - view.read_with(&app, |view, ctx| view.selection_ranges(ctx)), + view.read_with(&cx, |view, cx| view.selection_ranges(cx)), &[ DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28), DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7), @@ -4082,8 +4059,8 @@ mod tests { } impl Editor { - fn selection_ranges(&self, app: &AppContext) -> Vec> { - self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app) + fn selection_ranges(&self, cx: &AppContext) -> Vec> { + self.selections_in_range(DisplayPoint::zero()..self.max_point(cx), cx) .collect::>() } } From 2285cba70a89178e8946542a1911f05a78bce840 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 14:56:44 -0700 Subject: [PATCH 04/16] Rename context parameters to `cx` in file_finder.rs --- zed/src/file_finder.rs | 264 ++++++++++++++++++++--------------------- 1 file changed, 132 insertions(+), 132 deletions(-) diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 40b3894d2599af471a7d71ef24274ff99cbda51e..83227f309f5c3560b212957bee37250cd9800534 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -39,15 +39,15 @@ pub struct FileFinder { list_state: UniformListState, } -pub fn init(app: &mut MutableAppContext) { - app.add_action("file_finder:toggle", FileFinder::toggle); - app.add_action("file_finder:confirm", FileFinder::confirm); - app.add_action("file_finder:select", FileFinder::select); - app.add_action("menu:select_prev", FileFinder::select_prev); - app.add_action("menu:select_next", FileFinder::select_next); - app.add_action("uniform_list:scroll", FileFinder::scroll); - - app.add_bindings(vec![ +pub fn init(cx: &mut MutableAppContext) { + cx.add_action("file_finder:toggle", FileFinder::toggle); + cx.add_action("file_finder:confirm", FileFinder::confirm); + cx.add_action("file_finder:select", FileFinder::select); + cx.add_action("menu:select_prev", FileFinder::select_prev); + cx.add_action("menu:select_next", FileFinder::select_next); + cx.add_action("uniform_list:scroll", FileFinder::scroll); + + cx.add_bindings(vec![ Binding::new("cmd-p", "file_finder:toggle", None), Binding::new("escape", "file_finder:toggle", Some("FileFinder")), Binding::new("enter", "file_finder:confirm", Some("FileFinder")), @@ -92,14 +92,14 @@ impl View for FileFinder { .named("file finder") } - fn on_focus(&mut self, ctx: &mut ViewContext) { - ctx.focus(&self.query_buffer); + fn on_focus(&mut self, cx: &mut ViewContext) { + cx.focus(&self.query_buffer); } fn keymap_context(&self, _: &AppContext) -> keymap::Context { - let mut ctx = Self::default_keymap_context(); - ctx.set.insert("menu".into()); - ctx + let mut cx = Self::default_keymap_context(); + cx.set.insert("menu".into()); + cx } } @@ -123,13 +123,13 @@ impl FileFinder { let list = UniformList::new( self.list_state.clone(), self.matches.len(), - move |mut range, items, app| { - let finder = handle.upgrade(app).unwrap(); - let finder = finder.read(app); + move |mut range, items, cx| { + let finder = handle.upgrade(cx).unwrap(); + let finder = finder.read(cx); let start = range.start; range.end = cmp::min(range.end, finder.matches.len()); items.extend(finder.matches[range].iter().enumerate().filter_map( - move |(i, path_match)| finder.render_match(path_match, start + i, app), + move |(i, path_match)| finder.render_match(path_match, start + i, cx), )); }, ); @@ -145,9 +145,9 @@ impl FileFinder { &self, path_match: &PathMatch, index: usize, - app: &AppContext, + cx: &AppContext, ) -> Option { - self.labels_for_match(path_match, app).map( + self.labels_for_match(path_match, cx).map( |(file_name, file_name_positions, full_path, full_path_positions)| { let settings = self.settings.borrow(); let highlight_color = ColorU::from_u32(0x304ee2ff); @@ -208,8 +208,8 @@ impl FileFinder { let entry = (path_match.tree_id, path_match.path.clone()); EventHandler::new(container.boxed()) - .on_mouse_down(move |ctx| { - ctx.dispatch_action("file_finder:select", entry.clone()); + .on_mouse_down(move |cx| { + cx.dispatch_action("file_finder:select", entry.clone()); true }) .named("match") @@ -220,9 +220,9 @@ impl FileFinder { fn labels_for_match( &self, path_match: &PathMatch, - app: &AppContext, + cx: &AppContext, ) -> Option<(String, Vec, String, Vec)> { - self.worktree(path_match.tree_id, app).map(|tree| { + self.worktree(path_match.tree_id, cx).map(|tree| { let prefix = if path_match.include_root_name { tree.root_name() } else { @@ -254,12 +254,12 @@ impl FileFinder { }) } - fn toggle(workspace_view: &mut Workspace, _: &(), ctx: &mut ViewContext) { - workspace_view.toggle_modal(ctx, |ctx, workspace_view| { - let workspace = ctx.handle(); + fn toggle(workspace_view: &mut Workspace, _: &(), cx: &mut ViewContext) { + workspace_view.toggle_modal(cx, |cx, workspace_view| { + let workspace = cx.handle(); let finder = - ctx.add_view(|ctx| Self::new(workspace_view.settings.clone(), workspace, ctx)); - ctx.subscribe_to_view(&finder, Self::on_event); + cx.add_view(|cx| Self::new(workspace_view.settings.clone(), workspace, cx)); + cx.subscribe_to_view(&finder, Self::on_event); finder }); } @@ -268,17 +268,17 @@ impl FileFinder { workspace_view: &mut Workspace, _: ViewHandle, event: &Event, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { match event { Event::Selected(tree_id, path) => { workspace_view - .open_entry((*tree_id, path.clone()), ctx) + .open_entry((*tree_id, path.clone()), cx) .map(|d| d.detach()); - workspace_view.dismiss_modal(ctx); + workspace_view.dismiss_modal(cx); } Event::Dismissed => { - workspace_view.dismiss_modal(ctx); + workspace_view.dismiss_modal(cx); } } } @@ -286,15 +286,15 @@ impl FileFinder { pub fn new( settings: watch::Receiver, workspace: ViewHandle, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self { - ctx.observe_view(&workspace, Self::workspace_updated); + cx.observe_view(&workspace, Self::workspace_updated); - let query_buffer = ctx.add_view(|ctx| Editor::single_line(settings.clone(), ctx)); - ctx.subscribe_to_view(&query_buffer, Self::on_query_editor_event); + let query_buffer = cx.add_view(|cx| Editor::single_line(settings.clone(), cx)); + cx.subscribe_to_view(&query_buffer, Self::on_query_editor_event); Self { - handle: ctx.handle().downgrade(), + handle: cx.handle().downgrade(), settings, workspace: workspace.downgrade(), query_buffer, @@ -309,8 +309,8 @@ impl FileFinder { } } - fn workspace_updated(&mut self, _: ViewHandle, ctx: &mut ViewContext) { - if let Some(task) = self.spawn_search(self.query_buffer.read(ctx).text(ctx.as_ref()), ctx) { + fn workspace_updated(&mut self, _: ViewHandle, cx: &mut ViewContext) { + if let Some(task) = self.spawn_search(self.query_buffer.read(cx).text(cx.as_ref()), cx) { task.detach(); } } @@ -319,22 +319,22 @@ impl FileFinder { &mut self, _: ViewHandle, event: &editor::Event, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { match event { editor::Event::Edited => { - let query = self.query_buffer.read(ctx).text(ctx.as_ref()); + let query = self.query_buffer.read(cx).text(cx.as_ref()); if query.is_empty() { self.latest_search_id = util::post_inc(&mut self.search_count); self.matches.clear(); - ctx.notify(); + cx.notify(); } else { - if let Some(task) = self.spawn_search(query, ctx) { + if let Some(task) = self.spawn_search(query, cx) { task.detach(); } } } - editor::Event::Blurred => ctx.emit(Event::Dismissed), + editor::Event::Blurred => cx.emit(Event::Dismissed), _ => {} } } @@ -352,7 +352,7 @@ impl FileFinder { 0 } - fn select_prev(&mut self, _: &(), ctx: &mut ViewContext) { + fn select_prev(&mut self, _: &(), cx: &mut ViewContext) { let mut selected_index = self.selected_index(); if selected_index > 0 { selected_index -= 1; @@ -360,10 +360,10 @@ impl FileFinder { self.selected = Some((mat.tree_id, mat.path.clone())); } self.list_state.scroll_to(selected_index); - ctx.notify(); + cx.notify(); } - fn select_next(&mut self, _: &(), ctx: &mut ViewContext) { + fn select_next(&mut self, _: &(), cx: &mut ViewContext) { let mut selected_index = self.selected_index(); if selected_index + 1 < self.matches.len() { selected_index += 1; @@ -371,39 +371,39 @@ impl FileFinder { self.selected = Some((mat.tree_id, mat.path.clone())); } self.list_state.scroll_to(selected_index); - ctx.notify(); + cx.notify(); } - fn scroll(&mut self, _: &f32, ctx: &mut ViewContext) { - ctx.notify(); + fn scroll(&mut self, _: &f32, cx: &mut ViewContext) { + cx.notify(); } - fn confirm(&mut self, _: &(), ctx: &mut ViewContext) { + fn confirm(&mut self, _: &(), cx: &mut ViewContext) { if let Some(m) = self.matches.get(self.selected_index()) { - ctx.emit(Event::Selected(m.tree_id, m.path.clone())); + cx.emit(Event::Selected(m.tree_id, m.path.clone())); } } - fn select(&mut self, (tree_id, path): &(usize, Arc), ctx: &mut ViewContext) { - ctx.emit(Event::Selected(*tree_id, path.clone())); + fn select(&mut self, (tree_id, path): &(usize, Arc), cx: &mut ViewContext) { + cx.emit(Event::Selected(*tree_id, path.clone())); } #[must_use] - fn spawn_search(&mut self, query: String, ctx: &mut ViewContext) -> Option> { + fn spawn_search(&mut self, query: String, cx: &mut ViewContext) -> Option> { let snapshots = self .workspace - .upgrade(&ctx)? - .read(ctx) + .upgrade(&cx)? + .read(cx) .worktrees() .iter() - .map(|tree| tree.read(ctx).snapshot()) + .map(|tree| tree.read(cx).snapshot()) .collect::>(); let search_id = util::post_inc(&mut self.search_count); - let pool = ctx.as_ref().thread_pool().clone(); + let pool = cx.as_ref().thread_pool().clone(); self.cancel_flag.store(true, atomic::Ordering::Relaxed); self.cancel_flag = Arc::new(AtomicBool::new(false)); let cancel_flag = self.cancel_flag.clone(); - let background_task = ctx.background_executor().spawn(async move { + let background_task = cx.background_executor().spawn(async move { let include_root_name = snapshots.len() > 1; let matches = match_paths( snapshots.iter(), @@ -419,16 +419,16 @@ impl FileFinder { (search_id, did_cancel, query, matches) }); - Some(ctx.spawn(|this, mut ctx| async move { + Some(cx.spawn(|this, mut cx| async move { let matches = background_task.await; - this.update(&mut ctx, |this, ctx| this.update_matches(matches, ctx)); + this.update(&mut cx, |this, cx| this.update_matches(matches, cx)); })) } fn update_matches( &mut self, (search_id, did_cancel, query, matches): (usize, bool, String, Vec), - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { if search_id >= self.latest_search_id { self.latest_search_id = search_id; @@ -440,17 +440,17 @@ impl FileFinder { self.latest_search_query = query; self.latest_search_did_cancel = did_cancel; self.list_state.scroll_to(self.selected_index()); - ctx.notify(); + cx.notify(); } } - fn worktree<'a>(&'a self, tree_id: usize, app: &'a AppContext) -> Option<&'a Worktree> { + fn worktree<'a>(&'a self, tree_id: usize, cx: &'a AppContext) -> Option<&'a Worktree> { self.workspace - .upgrade(app)? - .read(app) + .upgrade(cx)? + .read(cx) .worktrees() .get(&tree_id) - .map(|worktree| worktree.read(app)) + .map(|worktree| worktree.read(cx)) } } @@ -467,75 +467,75 @@ mod tests { use tempdir::TempDir; #[gpui::test] - async fn test_matching_paths(mut app: gpui::TestAppContext) { + async fn test_matching_paths(mut cx: gpui::TestAppContext) { let tmp_dir = TempDir::new("example").unwrap(); fs::create_dir(tmp_dir.path().join("a")).unwrap(); fs::write(tmp_dir.path().join("a/banana"), "banana").unwrap(); fs::write(tmp_dir.path().join("a/bandana"), "bandana").unwrap(); - app.update(|ctx| { - super::init(ctx); - editor::init(ctx); + cx.update(|cx| { + super::init(cx); + editor::init(cx); }); - let app_state = app.read(build_app_state); - let (window_id, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (window_id, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(tmp_dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(tmp_dir.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; - app.dispatch_action( + cx.dispatch_action( window_id, vec![workspace.id()], "file_finder:toggle".into(), (), ); - let finder = app.read(|ctx| { + let finder = cx.read(|cx| { workspace - .read(ctx) + .read(cx) .modal() .cloned() .unwrap() .downcast::() .unwrap() }); - let query_buffer = app.read(|ctx| finder.read(ctx).query_buffer.clone()); + let query_buffer = cx.read(|cx| finder.read(cx).query_buffer.clone()); let chain = vec![finder.id(), query_buffer.id()]; - app.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string()); - app.dispatch_action(window_id, chain.clone(), "buffer:insert", "n".to_string()); - app.dispatch_action(window_id, chain.clone(), "buffer:insert", "a".to_string()); + cx.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string()); + cx.dispatch_action(window_id, chain.clone(), "buffer:insert", "n".to_string()); + cx.dispatch_action(window_id, chain.clone(), "buffer:insert", "a".to_string()); finder - .condition(&app, |finder, _| finder.matches.len() == 2) + .condition(&cx, |finder, _| finder.matches.len() == 2) .await; - let active_pane = app.read(|ctx| workspace.read(ctx).active_pane().clone()); - app.dispatch_action( + let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); + cx.dispatch_action( window_id, vec![workspace.id(), finder.id()], "menu:select_next", (), ); - app.dispatch_action( + cx.dispatch_action( window_id, vec![workspace.id(), finder.id()], "file_finder:confirm", (), ); active_pane - .condition(&app, |pane, _| pane.active_item().is_some()) + .condition(&cx, |pane, _| pane.active_item().is_some()) .await; - app.read(|ctx| { - let active_item = active_pane.read(ctx).active_item().unwrap(); - assert_eq!(active_item.title(ctx), "bandana"); + cx.read(|cx| { + let active_item = active_pane.read(cx).active_item().unwrap(); + assert_eq!(active_item.title(cx), "bandana"); }); } #[gpui::test] - async fn test_matching_cancellation(mut app: gpui::TestAppContext) { + async fn test_matching_cancellation(mut cx: gpui::TestAppContext) { let tmp_dir = temp_tree(json!({ "hello": "", "goodbye": "", @@ -545,35 +545,35 @@ mod tests { "hi": "", "hiccup": "", })); - let app_state = app.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (_, workspace) = cx.add_window(|cx| { let mut workspace = Workspace::new( 0, app_state.settings.clone(), app_state.language_registry.clone(), - ctx, + cx, ); - workspace.add_worktree(tmp_dir.path(), ctx); + workspace.add_worktree(tmp_dir.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; let (_, finder) = - app.add_window(|ctx| FileFinder::new(app_state.settings, workspace.clone(), ctx)); + cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx)); let query = "hi".to_string(); finder - .update(&mut app, |f, ctx| f.spawn_search(query.clone(), ctx)) + .update(&mut cx, |f, cx| f.spawn_search(query.clone(), cx)) .unwrap() .await; - finder.read_with(&app, |f, _| assert_eq!(f.matches.len(), 5)); + finder.read_with(&cx, |f, _| assert_eq!(f.matches.len(), 5)); - finder.update(&mut app, |finder, ctx| { + finder.update(&mut cx, |finder, cx| { let matches = finder.matches.clone(); // Simulate a search being cancelled after the time limit, // returning only a subset of the matches that would have been found. - finder.spawn_search(query.clone(), ctx).unwrap().detach(); + finder.spawn_search(query.clone(), cx).unwrap().detach(); finder.update_matches( ( finder.latest_search_id, @@ -581,11 +581,11 @@ mod tests { query.clone(), vec![matches[1].clone(), matches[3].clone()], ), - ctx, + cx, ); // Simulate another cancellation. - finder.spawn_search(query.clone(), ctx).unwrap().detach(); + finder.spawn_search(query.clone(), cx).unwrap().detach(); finder.update_matches( ( finder.latest_search_id, @@ -593,7 +593,7 @@ mod tests { query.clone(), vec![matches[0].clone(), matches[2].clone(), matches[3].clone()], ), - ctx, + cx, ); assert_eq!(finder.matches, matches[0..4]) @@ -601,41 +601,41 @@ mod tests { } #[gpui::test] - async fn test_single_file_worktrees(mut app: gpui::TestAppContext) { + async fn test_single_file_worktrees(mut cx: gpui::TestAppContext) { let temp_dir = TempDir::new("test-single-file-worktrees").unwrap(); let dir_path = temp_dir.path().join("the-parent-dir"); let file_path = dir_path.join("the-file"); fs::create_dir(&dir_path).unwrap(); fs::write(&file_path, "").unwrap(); - let app_state = app.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (_, workspace) = cx.add_window(|cx| { let mut workspace = Workspace::new( 0, app_state.settings.clone(), app_state.language_registry.clone(), - ctx, + cx, ); - workspace.add_worktree(&file_path, ctx); + workspace.add_worktree(&file_path, cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; let (_, finder) = - app.add_window(|ctx| FileFinder::new(app_state.settings, workspace.clone(), ctx)); + cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx)); // Even though there is only one worktree, that worktree's filename // is included in the matching, because the worktree is a single file. finder - .update(&mut app, |f, ctx| f.spawn_search("thf".into(), ctx)) + .update(&mut cx, |f, cx| f.spawn_search("thf".into(), cx)) .unwrap() .await; - app.read(|ctx| { - let finder = finder.read(ctx); + cx.read(|cx| { + let finder = finder.read(cx); assert_eq!(finder.matches.len(), 1); let (file_name, file_name_positions, full_path, full_path_positions) = - finder.labels_for_match(&finder.matches[0], ctx).unwrap(); + finder.labels_for_match(&finder.matches[0], cx).unwrap(); assert_eq!(file_name, "the-file"); assert_eq!(file_name_positions, &[0, 1, 4]); assert_eq!(full_path, "the-file"); @@ -645,57 +645,57 @@ mod tests { // Since the worktree root is a file, searching for its name followed by a slash does // not match anything. finder - .update(&mut app, |f, ctx| f.spawn_search("thf/".into(), ctx)) + .update(&mut cx, |f, cx| f.spawn_search("thf/".into(), cx)) .unwrap() .await; - finder.read_with(&app, |f, _| assert_eq!(f.matches.len(), 0)); + finder.read_with(&cx, |f, _| assert_eq!(f.matches.len(), 0)); } #[gpui::test] - async fn test_multiple_matches_with_same_relative_path(mut app: gpui::TestAppContext) { + async fn test_multiple_matches_with_same_relative_path(mut cx: gpui::TestAppContext) { let tmp_dir = temp_tree(json!({ "dir1": { "a.txt": "" }, "dir2": { "a.txt": "" } })); - let app_state = app.read(build_app_state); + let app_state = cx.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let (_, workspace) = cx.add_window(|cx| { Workspace::new( 0, app_state.settings.clone(), app_state.language_registry.clone(), - ctx, + cx, ) }); workspace - .update(&mut app, |workspace, ctx| { + .update(&mut cx, |workspace, cx| { workspace.open_paths( &[tmp_dir.path().join("dir1"), tmp_dir.path().join("dir2")], - ctx, + cx, ) }) .await; - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; let (_, finder) = - app.add_window(|ctx| FileFinder::new(app_state.settings, workspace.clone(), ctx)); + cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx)); // Run a search that matches two files with the same relative path. finder - .update(&mut app, |f, ctx| f.spawn_search("a.t".into(), ctx)) + .update(&mut cx, |f, cx| f.spawn_search("a.t".into(), cx)) .unwrap() .await; // Can switch between different matches with the same relative path. - finder.update(&mut app, |f, ctx| { + finder.update(&mut cx, |f, cx| { assert_eq!(f.matches.len(), 2); assert_eq!(f.selected_index(), 0); - f.select_next(&(), ctx); + f.select_next(&(), cx); assert_eq!(f.selected_index(), 1); - f.select_prev(&(), ctx); + f.select_prev(&(), cx); assert_eq!(f.selected_index(), 0); }); } From bc4f5af0887d45fa8d51b14c7794bd1e48888d09 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 14:59:24 -0700 Subject: [PATCH 05/16] Rename context parameters to `cx` in workspace.rs --- zed/src/workspace.rs | 642 +++++++++++++++++++++---------------------- 1 file changed, 319 insertions(+), 323 deletions(-) diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index 552ee24d26c7048c9a08e1be2a35728ecc2bc1d7..36ef65b1747689564aef5e776c5bbb70e69d95c0 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -26,18 +26,18 @@ use std::{ sync::Arc, }; -pub fn init(app: &mut MutableAppContext) { - app.add_global_action("workspace:open", open); - app.add_global_action("workspace:open_paths", open_paths); - app.add_global_action("app:quit", quit); - app.add_action("workspace:save", Workspace::save_active_item); - app.add_action("workspace:debug_elements", Workspace::debug_elements); - app.add_action("workspace:new_file", Workspace::open_new_file); - app.add_bindings(vec![ +pub fn init(cx: &mut MutableAppContext) { + cx.add_global_action("workspace:open", open); + cx.add_global_action("workspace:open_paths", open_paths); + cx.add_global_action("app:quit", quit); + cx.add_action("workspace:save", Workspace::save_active_item); + cx.add_action("workspace:debug_elements", Workspace::debug_elements); + cx.add_action("workspace:new_file", Workspace::open_new_file); + cx.add_bindings(vec![ Binding::new("cmd-s", "workspace:save", None), Binding::new("cmd-alt-i", "workspace:debug_elements", None), ]); - pane::init(app); + pane::init(cx); } pub struct OpenParams { @@ -45,32 +45,32 @@ pub struct OpenParams { pub app_state: AppState, } -fn open(app_state: &AppState, ctx: &mut MutableAppContext) { +fn open(app_state: &AppState, cx: &mut MutableAppContext) { let app_state = app_state.clone(); - ctx.prompt_for_paths( + cx.prompt_for_paths( PathPromptOptions { files: true, directories: true, multiple: true, }, - move |paths, ctx| { + move |paths, cx| { if let Some(paths) = paths { - ctx.dispatch_global_action("workspace:open_paths", OpenParams { paths, app_state }); + cx.dispatch_global_action("workspace:open_paths", OpenParams { paths, app_state }); } }, ); } -fn open_paths(params: &OpenParams, app: &mut MutableAppContext) { +fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) { log::info!("open paths {:?}", params.paths); // Open paths in existing workspace if possible - for window_id in app.window_ids().collect::>() { - if let Some(handle) = app.root_view::(window_id) { - if handle.update(app, |view, ctx| { - if view.contains_paths(¶ms.paths, ctx.as_ref()) { - let open_paths = view.open_paths(¶ms.paths, ctx); - ctx.foreground().spawn(open_paths).detach(); + for window_id in cx.window_ids().collect::>() { + if let Some(handle) = cx.root_view::(window_id) { + if handle.update(cx, |view, cx| { + if view.contains_paths(¶ms.paths, cx.as_ref()) { + let open_paths = view.open_paths(¶ms.paths, cx); + cx.foreground().spawn(open_paths).detach(); log::info!("open paths on existing workspace"); true } else { @@ -85,21 +85,21 @@ fn open_paths(params: &OpenParams, app: &mut MutableAppContext) { log::info!("open new workspace"); // Add a new workspace if necessary - app.add_window(|ctx| { + cx.add_window(|cx| { let mut view = Workspace::new( 0, params.app_state.settings.clone(), params.app_state.language_registry.clone(), - ctx, + cx, ); - let open_paths = view.open_paths(¶ms.paths, ctx); - ctx.foreground().spawn(open_paths).detach(); + let open_paths = view.open_paths(¶ms.paths, cx); + cx.foreground().spawn(open_paths).detach(); view }); } -fn quit(_: &(), app: &mut MutableAppContext) { - app.platform().quit(); +fn quit(_: &(), cx: &mut MutableAppContext) { + cx.platform().quit(); } pub trait Item: Entity + Sized { @@ -108,15 +108,15 @@ pub trait Item: Entity + Sized { fn build_view( handle: ModelHandle, settings: watch::Receiver, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::View; fn file(&self) -> Option<&FileHandle>; } pub trait ItemView: View { - fn title(&self, app: &AppContext) -> String; - fn entry_id(&self, app: &AppContext) -> Option<(usize, Arc)>; + fn title(&self, cx: &AppContext) -> String; + fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc)>; fn clone_on_split(&self, _: &mut ViewContext) -> Option where Self: Sized, @@ -148,30 +148,30 @@ pub trait ItemHandle: Send + Sync { } pub trait WeakItemHandle: Send + Sync { - fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle>; + fn file<'a>(&'a self, cx: &'a AppContext) -> Option<&'a FileHandle>; fn add_view( &self, window_id: usize, settings: watch::Receiver, - app: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Option>; - fn alive(&self, ctx: &AppContext) -> bool; + fn alive(&self, cx: &AppContext) -> bool; } pub trait ItemViewHandle: Send + Sync { - fn title(&self, app: &AppContext) -> String; - fn entry_id(&self, app: &AppContext) -> Option<(usize, Arc)>; + fn title(&self, cx: &AppContext) -> String; + fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc)>; fn boxed_clone(&self) -> Box; - fn clone_on_split(&self, app: &mut MutableAppContext) -> Option>; - fn set_parent_pane(&self, pane: &ViewHandle, app: &mut MutableAppContext); + fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option>; + fn set_parent_pane(&self, pane: &ViewHandle, cx: &mut MutableAppContext); fn id(&self) -> usize; fn to_any(&self) -> AnyViewHandle; - fn is_dirty(&self, ctx: &AppContext) -> bool; - fn has_conflict(&self, ctx: &AppContext) -> bool; + fn is_dirty(&self, cx: &AppContext) -> bool; + fn has_conflict(&self, cx: &AppContext) -> bool; fn save( &self, file: Option, - ctx: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Task>; } @@ -186,61 +186,61 @@ impl ItemHandle for ModelHandle { } impl WeakItemHandle for WeakModelHandle { - fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle> { - self.upgrade(ctx).and_then(|h| h.read(ctx).file()) + fn file<'a>(&'a self, cx: &'a AppContext) -> Option<&'a FileHandle> { + self.upgrade(cx).and_then(|h| h.read(cx).file()) } fn add_view( &self, window_id: usize, settings: watch::Receiver, - ctx: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Option> { - if let Some(handle) = self.upgrade(ctx.as_ref()) { - Some(Box::new(ctx.add_view(window_id, |ctx| { - T::build_view(handle, settings, ctx) + if let Some(handle) = self.upgrade(cx.as_ref()) { + Some(Box::new(cx.add_view(window_id, |cx| { + T::build_view(handle, settings, cx) }))) } else { None } } - fn alive(&self, ctx: &AppContext) -> bool { - self.upgrade(ctx).is_some() + fn alive(&self, cx: &AppContext) -> bool { + self.upgrade(cx).is_some() } } impl ItemViewHandle for ViewHandle { - fn title(&self, app: &AppContext) -> String { - self.read(app).title(app) + fn title(&self, cx: &AppContext) -> String { + self.read(cx).title(cx) } - fn entry_id(&self, app: &AppContext) -> Option<(usize, Arc)> { - self.read(app).entry_id(app) + fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc)> { + self.read(cx).entry_id(cx) } fn boxed_clone(&self) -> Box { Box::new(self.clone()) } - fn clone_on_split(&self, app: &mut MutableAppContext) -> Option> { - self.update(app, |item, ctx| { - ctx.add_option_view(|ctx| item.clone_on_split(ctx)) + fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option> { + self.update(cx, |item, cx| { + cx.add_option_view(|cx| item.clone_on_split(cx)) }) .map(|handle| Box::new(handle) as Box) } - fn set_parent_pane(&self, pane: &ViewHandle, app: &mut MutableAppContext) { - pane.update(app, |_, ctx| { - ctx.subscribe_to_view(self, |pane, item, event, ctx| { + fn set_parent_pane(&self, pane: &ViewHandle, cx: &mut MutableAppContext) { + pane.update(cx, |_, cx| { + cx.subscribe_to_view(self, |pane, item, event, cx| { if T::should_activate_item_on_event(event) { if let Some(ix) = pane.item_index(&item) { - pane.activate_item(ix, ctx); - pane.activate(ctx); + pane.activate_item(ix, cx); + pane.activate(cx); } } if T::should_update_tab_on_event(event) { - ctx.notify() + cx.notify() } }) }) @@ -249,17 +249,17 @@ impl ItemViewHandle for ViewHandle { fn save( &self, file: Option, - ctx: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Task> { - self.update(ctx, |item, ctx| item.save(file, ctx)) + self.update(cx, |item, cx| item.save(file, cx)) } - fn is_dirty(&self, ctx: &AppContext) -> bool { - self.read(ctx).is_dirty(ctx) + fn is_dirty(&self, cx: &AppContext) -> bool { + self.read(cx).is_dirty(cx) } - fn has_conflict(&self, ctx: &AppContext) -> bool { - self.read(ctx).has_conflict(ctx) + fn has_conflict(&self, cx: &AppContext) -> bool { + self.read(cx).has_conflict(cx) } fn id(&self) -> usize { @@ -310,14 +310,14 @@ impl Workspace { replica_id: ReplicaId, settings: watch::Receiver, language_registry: Arc, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self { - let pane = ctx.add_view(|_| Pane::new(settings.clone())); + let pane = cx.add_view(|_| Pane::new(settings.clone())); let pane_id = pane.id(); - ctx.subscribe_to_view(&pane, move |me, _, event, ctx| { - me.handle_pane_event(pane_id, event, ctx) + cx.subscribe_to_view(&pane, move |me, _, event, cx| { + me.handle_pane_event(pane_id, event, cx) }); - ctx.focus(&pane); + cx.focus(&pane); Workspace { modal: None, @@ -337,21 +337,21 @@ impl Workspace { &self.worktrees } - pub fn contains_paths(&self, paths: &[PathBuf], app: &AppContext) -> bool { - paths.iter().all(|path| self.contains_path(&path, app)) + pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool { + paths.iter().all(|path| self.contains_path(&path, cx)) } - pub fn contains_path(&self, path: &Path, app: &AppContext) -> bool { + pub fn contains_path(&self, path: &Path, cx: &AppContext) -> bool { self.worktrees .iter() - .any(|worktree| worktree.read(app).contains_abs_path(path)) + .any(|worktree| worktree.read(cx).contains_abs_path(path)) } - pub fn worktree_scans_complete(&self, ctx: &AppContext) -> impl Future + 'static { + pub fn worktree_scans_complete(&self, cx: &AppContext) -> impl Future + 'static { let futures = self .worktrees .iter() - .map(|worktree| worktree.read(ctx).scan_complete()) + .map(|worktree| worktree.read(cx).scan_complete()) .collect::>(); async move { for future in futures { @@ -363,27 +363,27 @@ impl Workspace { pub fn open_paths( &mut self, abs_paths: &[PathBuf], - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> impl Future { let entries = abs_paths .iter() .cloned() - .map(|path| self.file_for_path(&path, ctx)) + .map(|path| self.file_for_path(&path, cx)) .collect::>(); - let bg = ctx.background_executor().clone(); + let bg = cx.background_executor().clone(); let tasks = abs_paths .iter() .cloned() .zip(entries.into_iter()) .map(|(abs_path, file)| { let is_file = bg.spawn(async move { abs_path.is_file() }); - ctx.spawn(|this, mut ctx| async move { + cx.spawn(|this, mut cx| async move { let file = file.await; let is_file = is_file.await; - this.update(&mut ctx, |this, ctx| { + this.update(&mut cx, |this, cx| { if is_file { - this.open_entry(file.entry_id(), ctx) + this.open_entry(file.entry_id(), cx) } else { None } @@ -400,74 +400,74 @@ impl Workspace { } } - fn file_for_path(&mut self, abs_path: &Path, ctx: &mut ViewContext) -> Task { + fn file_for_path(&mut self, abs_path: &Path, cx: &mut ViewContext) -> Task { for tree in self.worktrees.iter() { - if let Ok(relative_path) = abs_path.strip_prefix(tree.read(ctx).abs_path()) { - return tree.file(relative_path, ctx.as_mut()); + if let Ok(relative_path) = abs_path.strip_prefix(tree.read(cx).abs_path()) { + return tree.file(relative_path, cx.as_mut()); } } - let worktree = self.add_worktree(&abs_path, ctx); - worktree.file(Path::new(""), ctx.as_mut()) + let worktree = self.add_worktree(&abs_path, cx); + worktree.file(Path::new(""), cx.as_mut()) } pub fn add_worktree( &mut self, path: &Path, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> ModelHandle { - let worktree = ctx.add_model(|ctx| Worktree::new(path, ctx)); - ctx.observe_model(&worktree, |_, _, ctx| ctx.notify()); + let worktree = cx.add_model(|cx| Worktree::new(path, cx)); + cx.observe_model(&worktree, |_, _, cx| cx.notify()); self.worktrees.insert(worktree.clone()); - ctx.notify(); + cx.notify(); worktree } - pub fn toggle_modal(&mut self, ctx: &mut ViewContext, add_view: F) + pub fn toggle_modal(&mut self, cx: &mut ViewContext, add_view: F) where V: 'static + View, F: FnOnce(&mut ViewContext, &mut Self) -> ViewHandle, { if self.modal.as_ref().map_or(false, |modal| modal.is::()) { self.modal.take(); - ctx.focus_self(); + cx.focus_self(); } else { - let modal = add_view(ctx, self); - ctx.focus(&modal); + let modal = add_view(cx, self); + cx.focus(&modal); self.modal = Some(modal.into()); } - ctx.notify(); + cx.notify(); } pub fn modal(&self) -> Option<&AnyViewHandle> { self.modal.as_ref() } - pub fn dismiss_modal(&mut self, ctx: &mut ViewContext) { + pub fn dismiss_modal(&mut self, cx: &mut ViewContext) { if self.modal.take().is_some() { - ctx.focus(&self.active_pane); - ctx.notify(); + cx.focus(&self.active_pane); + cx.notify(); } } - pub fn open_new_file(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = ctx.add_model(|ctx| Buffer::new(self.replica_id, "", ctx)); + pub fn open_new_file(&mut self, _: &(), cx: &mut ViewContext) { + let buffer = cx.add_model(|cx| Buffer::new(self.replica_id, "", cx)); let buffer_view = - ctx.add_view(|ctx| Editor::for_buffer(buffer.clone(), self.settings.clone(), ctx)); + cx.add_view(|cx| Editor::for_buffer(buffer.clone(), self.settings.clone(), cx)); self.items.push(ItemHandle::downgrade(&buffer)); - self.add_item_view(Box::new(buffer_view), ctx); + self.add_item_view(Box::new(buffer_view), cx); } #[must_use] pub fn open_entry( &mut self, entry: (usize, Arc), - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Option> { // If the active pane contains a view for this file, then activate // that item view. if self .active_pane() - .update(ctx, |pane, ctx| pane.activate_entry(entry.clone(), ctx)) + .update(cx, |pane, cx| pane.activate_entry(entry.clone(), cx)) { return None; } @@ -477,14 +477,14 @@ impl Workspace { let settings = self.settings.clone(); let mut view_for_existing_item = None; self.items.retain(|item| { - if item.alive(ctx.as_ref()) { + if item.alive(cx.as_ref()) { if view_for_existing_item.is_none() && item - .file(ctx.as_ref()) + .file(cx.as_ref()) .map_or(false, |f| f.entry_id() == entry) { view_for_existing_item = Some( - item.add_view(ctx.window_id(), settings.clone(), ctx.as_mut()) + item.add_view(cx.window_id(), settings.clone(), cx.as_mut()) .unwrap(), ); } @@ -494,7 +494,7 @@ impl Workspace { } }); if let Some(view) = view_for_existing_item { - self.add_item_view(view, ctx); + self.add_item_view(view, cx); return None; } @@ -508,28 +508,28 @@ impl Workspace { } }; - let file = worktree.file(path.clone(), ctx.as_mut()); + let file = worktree.file(path.clone(), cx.as_mut()); if let Entry::Vacant(entry) = self.loading_items.entry(entry.clone()) { let (mut tx, rx) = postage::watch::channel(); entry.insert(rx); let replica_id = self.replica_id; let language_registry = self.language_registry.clone(); - ctx.as_mut() - .spawn(|mut ctx| async move { + cx.as_mut() + .spawn(|mut cx| async move { let file = file.await; - let history = ctx.read(|ctx| file.load_history(ctx)); - let history = ctx.background_executor().spawn(history).await; + let history = cx.read(|cx| file.load_history(cx)); + let history = cx.background_executor().spawn(history).await; *tx.borrow_mut() = Some(match history { - Ok(history) => Ok(Box::new(ctx.add_model(|ctx| { + Ok(history) => Ok(Box::new(cx.add_model(|cx| { let language = language_registry.select_language(path); Buffer::from_history( replica_id, history, Some(file), language.cloned(), - ctx, + cx, ) }))), Err(error) => Err(Arc::new(error)), @@ -540,7 +540,7 @@ impl Workspace { let mut watch = self.loading_items.get(&entry).unwrap().clone(); - Some(ctx.spawn(|this, mut ctx| async move { + Some(cx.spawn(|this, mut cx| async move { let load_result = loop { if let Some(load_result) = watch.borrow().as_ref() { break load_result.clone(); @@ -548,16 +548,16 @@ impl Workspace { watch.next().await; }; - this.update(&mut ctx, |this, ctx| { + this.update(&mut cx, |this, cx| { this.loading_items.remove(&entry); match load_result { Ok(item) => { let weak_item = item.downgrade(); let view = weak_item - .add_view(ctx.window_id(), settings, ctx.as_mut()) + .add_view(cx.window_id(), settings, cx.as_mut()) .unwrap(); this.items.push(weak_item); - this.add_item_view(view, ctx); + this.add_item_view(view, cx); } Err(error) => { log::error!("error opening item: {}", error); @@ -567,27 +567,27 @@ impl Workspace { })) } - pub fn active_item(&self, ctx: &ViewContext) -> Option> { - self.active_pane().read(ctx).active_item() + pub fn active_item(&self, cx: &ViewContext) -> Option> { + self.active_pane().read(cx).active_item() } - pub fn save_active_item(&mut self, _: &(), ctx: &mut ViewContext) { - if let Some(item) = self.active_item(ctx) { - let handle = ctx.handle(); - if item.entry_id(ctx.as_ref()).is_none() { + pub fn save_active_item(&mut self, _: &(), cx: &mut ViewContext) { + if let Some(item) = self.active_item(cx) { + let handle = cx.handle(); + if item.entry_id(cx.as_ref()).is_none() { let start_path = self .worktrees .iter() .next() - .map_or(Path::new(""), |h| h.read(ctx).abs_path()) + .map_or(Path::new(""), |h| h.read(cx).abs_path()) .to_path_buf(); - ctx.prompt_for_new_path(&start_path, move |path, ctx| { + cx.prompt_for_new_path(&start_path, move |path, cx| { if let Some(path) = path { - ctx.spawn(|mut ctx| async move { + cx.spawn(|mut cx| async move { let file = handle - .update(&mut ctx, |me, ctx| me.file_for_path(&path, ctx)) + .update(&mut cx, |me, cx| me.file_for_path(&path, cx)) .await; - if let Err(error) = ctx.update(|ctx| item.save(Some(file), ctx)).await { + if let Err(error) = cx.update(|cx| item.save(Some(file), cx)).await { error!("failed to save item: {:?}, ", error); } }) @@ -595,17 +595,17 @@ impl Workspace { } }); return; - } else if item.has_conflict(ctx.as_ref()) { + } else if item.has_conflict(cx.as_ref()) { const CONFLICT_MESSAGE: &'static str = "This file has changed on disk since you started editing it. Do you want to overwrite it?"; - ctx.prompt( + cx.prompt( PromptLevel::Warning, CONFLICT_MESSAGE, &["Overwrite", "Cancel"], - move |answer, ctx| { + move |answer, cx| { if answer == 0 { - ctx.spawn(|mut ctx| async move { - if let Err(error) = ctx.update(|ctx| item.save(None, ctx)).await { + cx.spawn(|mut cx| async move { + if let Err(error) = cx.update(|cx| item.save(None, cx)).await { error!("failed to save item: {:?}, ", error); } }) @@ -614,8 +614,8 @@ impl Workspace { }, ); } else { - ctx.spawn(|_, mut ctx| async move { - if let Err(error) = ctx.update(|ctx| item.save(None, ctx)).await { + cx.spawn(|_, mut cx| async move { + if let Err(error) = cx.update(|cx| item.save(None, cx)).await { error!("failed to save item: {:?}, ", error); } }) @@ -624,11 +624,11 @@ impl Workspace { } } - pub fn debug_elements(&mut self, _: &(), ctx: &mut ViewContext) { - match to_string_pretty(&ctx.debug_elements()) { + pub fn debug_elements(&mut self, _: &(), cx: &mut ViewContext) { + match to_string_pretty(&cx.debug_elements()) { Ok(json) => { let kib = json.len() as f32 / 1024.; - ctx.as_mut().write_to_clipboard(ClipboardItem::new(json)); + cx.as_mut().write_to_clipboard(ClipboardItem::new(json)); log::info!( "copied {:.1} KiB of element debug JSON to the clipboard", kib @@ -640,39 +640,39 @@ impl Workspace { }; } - fn add_pane(&mut self, ctx: &mut ViewContext) -> ViewHandle { - let pane = ctx.add_view(|_| Pane::new(self.settings.clone())); + fn add_pane(&mut self, cx: &mut ViewContext) -> ViewHandle { + let pane = cx.add_view(|_| Pane::new(self.settings.clone())); let pane_id = pane.id(); - ctx.subscribe_to_view(&pane, move |me, _, event, ctx| { - me.handle_pane_event(pane_id, event, ctx) + cx.subscribe_to_view(&pane, move |me, _, event, cx| { + me.handle_pane_event(pane_id, event, cx) }); self.panes.push(pane.clone()); - self.activate_pane(pane.clone(), ctx); + self.activate_pane(pane.clone(), cx); pane } - fn activate_pane(&mut self, pane: ViewHandle, ctx: &mut ViewContext) { + fn activate_pane(&mut self, pane: ViewHandle, cx: &mut ViewContext) { self.active_pane = pane; - ctx.focus(&self.active_pane); - ctx.notify(); + cx.focus(&self.active_pane); + cx.notify(); } fn handle_pane_event( &mut self, pane_id: usize, event: &pane::Event, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { if let Some(pane) = self.pane(pane_id) { match event { pane::Event::Split(direction) => { - self.split_pane(pane, *direction, ctx); + self.split_pane(pane, *direction, cx); } pane::Event::Remove => { - self.remove_pane(pane, ctx); + self.remove_pane(pane, cx); } pane::Event::Activate => { - self.activate_pane(pane, ctx); + self.activate_pane(pane, cx); } } } else { @@ -684,26 +684,26 @@ impl Workspace { &mut self, pane: ViewHandle, direction: SplitDirection, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> ViewHandle { - let new_pane = self.add_pane(ctx); - self.activate_pane(new_pane.clone(), ctx); - if let Some(item) = pane.read(ctx).active_item() { - if let Some(clone) = item.clone_on_split(ctx.as_mut()) { - self.add_item_view(clone, ctx); + let new_pane = self.add_pane(cx); + self.activate_pane(new_pane.clone(), cx); + if let Some(item) = pane.read(cx).active_item() { + if let Some(clone) = item.clone_on_split(cx.as_mut()) { + self.add_item_view(clone, cx); } } self.center .split(pane.id(), new_pane.id(), direction) .unwrap(); - ctx.notify(); + cx.notify(); new_pane } - fn remove_pane(&mut self, pane: ViewHandle, ctx: &mut ViewContext) { + fn remove_pane(&mut self, pane: ViewHandle, cx: &mut ViewContext) { if self.center.remove(pane.id()).unwrap() { self.panes.retain(|p| p != &pane); - self.activate_pane(self.panes.last().unwrap().clone(), ctx); + self.activate_pane(self.panes.last().unwrap().clone(), cx); } } @@ -715,12 +715,12 @@ impl Workspace { &self.active_pane } - fn add_item_view(&self, item: Box, ctx: &mut ViewContext) { + fn add_item_view(&self, item: Box, cx: &mut ViewContext) { let active_pane = self.active_pane(); - item.set_parent_pane(&active_pane, ctx.as_mut()); - active_pane.update(ctx, |pane, ctx| { - let item_idx = pane.add_item(item, ctx); - pane.activate_item(item_idx, ctx); + item.set_parent_pane(&active_pane, cx.as_mut()); + active_pane.update(cx, |pane, cx| { + let item_idx = pane.add_item(item, cx); + pane.activate_item(item_idx, cx); }); } } @@ -746,25 +746,25 @@ impl View for Workspace { .named("workspace") } - fn on_focus(&mut self, ctx: &mut ViewContext) { - ctx.focus(&self.active_pane); + fn on_focus(&mut self, cx: &mut ViewContext) { + cx.focus(&self.active_pane); } } #[cfg(test)] pub trait WorkspaceHandle { - fn file_entries(&self, app: &AppContext) -> Vec<(usize, Arc)>; + fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc)>; } #[cfg(test)] impl WorkspaceHandle for ViewHandle { - fn file_entries(&self, app: &AppContext) -> Vec<(usize, Arc)> { - self.read(app) + fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc)> { + self.read(cx) .worktrees() .iter() .flat_map(|tree| { let tree_id = tree.id(); - tree.read(app) + tree.read(cx) .files(0) .map(move |f| (tree_id, f.path().clone())) }) @@ -784,10 +784,10 @@ mod tests { use tempdir::TempDir; #[gpui::test] - fn test_open_paths_action(app: &mut gpui::MutableAppContext) { - let app_state = build_app_state(app.as_ref()); + fn test_open_paths_action(cx: &mut gpui::MutableAppContext) { + let app_state = build_app_state(cx.as_ref()); - init(app); + init(cx); let dir = temp_tree(json!({ "a": { @@ -804,7 +804,7 @@ mod tests { }, })); - app.dispatch_global_action( + cx.dispatch_global_action( "workspace:open_paths", OpenParams { paths: vec![ @@ -814,22 +814,22 @@ mod tests { app_state: app_state.clone(), }, ); - assert_eq!(app.window_ids().count(), 1); + assert_eq!(cx.window_ids().count(), 1); - app.dispatch_global_action( + cx.dispatch_global_action( "workspace:open_paths", OpenParams { paths: vec![dir.path().join("a").to_path_buf()], app_state: app_state.clone(), }, ); - assert_eq!(app.window_ids().count(), 1); - let workspace_view_1 = app - .root_view::(app.window_ids().next().unwrap()) + assert_eq!(cx.window_ids().count(), 1); + let workspace_view_1 = cx + .root_view::(cx.window_ids().next().unwrap()) .unwrap(); - assert_eq!(workspace_view_1.read(app).worktrees().len(), 2); + assert_eq!(workspace_view_1.read(cx).worktrees().len(), 2); - app.dispatch_global_action( + cx.dispatch_global_action( "workspace:open_paths", OpenParams { paths: vec![ @@ -839,11 +839,11 @@ mod tests { app_state: app_state.clone(), }, ); - assert_eq!(app.window_ids().count(), 2); + assert_eq!(cx.window_ids().count(), 2); } #[gpui::test] - async fn test_open_entry(mut app: gpui::TestAppContext) { + async fn test_open_entry(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "a": { "file1": "contents 1", @@ -852,31 +852,31 @@ mod tests { }, })); - let app_state = app.read(build_app_state); + let app_state = cx.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let (_, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; - let entries = app.read(|ctx| workspace.file_entries(ctx)); + let entries = cx.read(|cx| workspace.file_entries(cx)); let file1 = entries[0].clone(); let file2 = entries[1].clone(); let file3 = entries[2].clone(); // Open the first entry workspace - .update(&mut app, |w, ctx| w.open_entry(file1.clone(), ctx)) + .update(&mut cx, |w, cx| w.open_entry(file1.clone(), cx)) .unwrap() .await; - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file1.clone()) ); assert_eq!(pane.items().len(), 1); @@ -884,72 +884,72 @@ mod tests { // Open the second entry workspace - .update(&mut app, |w, ctx| w.open_entry(file2.clone(), ctx)) + .update(&mut cx, |w, cx| w.open_entry(file2.clone(), cx)) .unwrap() .await; - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file2.clone()) ); assert_eq!(pane.items().len(), 2); }); // Open the first entry again. The existing pane item is activated. - workspace.update(&mut app, |w, ctx| { - assert!(w.open_entry(file1.clone(), ctx).is_none()) + workspace.update(&mut cx, |w, cx| { + assert!(w.open_entry(file1.clone(), cx).is_none()) }); - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file1.clone()) ); assert_eq!(pane.items().len(), 2); }); // Split the pane with the first entry, then open the second entry again. - workspace.update(&mut app, |w, ctx| { - w.split_pane(w.active_pane().clone(), SplitDirection::Right, ctx); - assert!(w.open_entry(file2.clone(), ctx).is_none()); + workspace.update(&mut cx, |w, cx| { + w.split_pane(w.active_pane().clone(), SplitDirection::Right, cx); + assert!(w.open_entry(file2.clone(), cx).is_none()); assert_eq!( w.active_pane() - .read(ctx) + .read(cx) .active_item() .unwrap() - .entry_id(ctx.as_ref()), + .entry_id(cx.as_ref()), Some(file2.clone()) ); }); // Open the third entry twice concurrently. Two pane items // are added. - let (t1, t2) = workspace.update(&mut app, |w, ctx| { + let (t1, t2) = workspace.update(&mut cx, |w, cx| { ( - w.open_entry(file3.clone(), ctx).unwrap(), - w.open_entry(file3.clone(), ctx).unwrap(), + w.open_entry(file3.clone(), cx).unwrap(), + w.open_entry(file3.clone(), cx).unwrap(), ) }); t1.await; t2.await; - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file3.clone()) ); let pane_entries = pane .items() .iter() - .map(|i| i.entry_id(ctx).unwrap()) + .map(|i| i.entry_id(cx).unwrap()) .collect::>(); assert_eq!(pane_entries, &[file1, file2, file3.clone(), file3]); }); } #[gpui::test] - async fn test_open_paths(mut app: gpui::TestAppContext) { + async fn test_open_paths(mut cx: gpui::TestAppContext) { let dir1 = temp_tree(json!({ "a.txt": "", })); @@ -957,49 +957,49 @@ mod tests { "b.txt": "", })); - let app_state = app.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (_, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir1.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir1.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; // Open a file within an existing worktree. - app.update(|ctx| { - workspace.update(ctx, |view, ctx| { - view.open_paths(&[dir1.path().join("a.txt")], ctx) + cx.update(|cx| { + workspace.update(cx, |view, cx| { + view.open_paths(&[dir1.path().join("a.txt")], cx) }) }) .await; - app.read(|ctx| { + cx.read(|cx| { assert_eq!( workspace - .read(ctx) + .read(cx) .active_pane() - .read(ctx) + .read(cx) .active_item() .unwrap() - .title(ctx), + .title(cx), "a.txt" ); }); // Open a file outside of any existing worktree. - app.update(|ctx| { - workspace.update(ctx, |view, ctx| { - view.open_paths(&[dir2.path().join("b.txt")], ctx) + cx.update(|cx| { + workspace.update(cx, |view, cx| { + view.open_paths(&[dir2.path().join("b.txt")], cx) }) }) .await; - app.read(|ctx| { + cx.read(|cx| { let worktree_roots = workspace - .read(ctx) + .read(cx) .worktrees() .iter() - .map(|w| w.read(ctx).abs_path()) + .map(|w| w.read(cx).abs_path()) .collect::>(); assert_eq!( worktree_roots, @@ -1009,163 +1009,159 @@ mod tests { ); assert_eq!( workspace - .read(ctx) + .read(cx) .active_pane() - .read(ctx) + .read(cx) .active_item() .unwrap() - .title(ctx), + .title(cx), "b.txt" ); }); } #[gpui::test] - async fn test_save_conflicting_item(mut app: gpui::TestAppContext) { + async fn test_save_conflicting_item(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "a.txt": "", })); - let app_state = app.read(build_app_state); - let (window_id, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (window_id, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - let tree = app.read(|ctx| { - let mut trees = workspace.read(ctx).worktrees().iter(); + let tree = cx.read(|cx| { + let mut trees = workspace.read(cx).worktrees().iter(); trees.next().unwrap().clone() }); - tree.flush_fs_events(&app).await; + tree.flush_fs_events(&cx).await; // Open a file within an existing worktree. - app.update(|ctx| { - workspace.update(ctx, |view, ctx| { - view.open_paths(&[dir.path().join("a.txt")], ctx) + cx.update(|cx| { + workspace.update(cx, |view, cx| { + view.open_paths(&[dir.path().join("a.txt")], cx) }) }) .await; - let editor = app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + let editor = cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); let item = pane.active_item().unwrap(); item.to_any().downcast::().unwrap() }); - app.update(|ctx| editor.update(ctx, |editor, ctx| editor.insert(&"x".to_string(), ctx))); + cx.update(|cx| editor.update(cx, |editor, cx| editor.insert(&"x".to_string(), cx))); fs::write(dir.path().join("a.txt"), "changed").unwrap(); editor - .condition(&app, |editor, ctx| editor.has_conflict(ctx)) + .condition(&cx, |editor, cx| editor.has_conflict(cx)) .await; - app.read(|ctx| assert!(editor.is_dirty(ctx))); + cx.read(|cx| assert!(editor.is_dirty(cx))); - app.update(|ctx| workspace.update(ctx, |w, ctx| w.save_active_item(&(), ctx))); - app.simulate_prompt_answer(window_id, 0); + cx.update(|cx| workspace.update(cx, |w, cx| w.save_active_item(&(), cx))); + cx.simulate_prompt_answer(window_id, 0); editor - .condition(&app, |editor, ctx| !editor.is_dirty(ctx)) + .condition(&cx, |editor, cx| !editor.is_dirty(cx)) .await; - app.read(|ctx| assert!(!editor.has_conflict(ctx))); + cx.read(|cx| assert!(!editor.has_conflict(cx))); } #[gpui::test] - async fn test_open_and_save_new_file(mut app: gpui::TestAppContext) { + async fn test_open_and_save_new_file(mut cx: gpui::TestAppContext) { let dir = TempDir::new("test-new-file").unwrap(); - let app_state = app.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (_, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - let tree = app.read(|ctx| { + let tree = cx.read(|cx| { workspace - .read(ctx) + .read(cx) .worktrees() .iter() .next() .unwrap() .clone() }); - tree.flush_fs_events(&app).await; + tree.flush_fs_events(&cx).await; // Create a new untitled buffer - let editor = workspace.update(&mut app, |workspace, ctx| { - workspace.open_new_file(&(), ctx); + let editor = workspace.update(&mut cx, |workspace, cx| { + workspace.open_new_file(&(), cx); workspace - .active_item(ctx) + .active_item(cx) .unwrap() .to_any() .downcast::() .unwrap() }); - editor.update(&mut app, |editor, ctx| { - assert!(!editor.is_dirty(ctx.as_ref())); - assert_eq!(editor.title(ctx.as_ref()), "untitled"); - editor.insert(&"hi".to_string(), ctx); - assert!(editor.is_dirty(ctx.as_ref())); + editor.update(&mut cx, |editor, cx| { + assert!(!editor.is_dirty(cx.as_ref())); + assert_eq!(editor.title(cx.as_ref()), "untitled"); + editor.insert(&"hi".to_string(), cx); + assert!(editor.is_dirty(cx.as_ref())); }); // Save the buffer. This prompts for a filename. - workspace.update(&mut app, |workspace, ctx| { - workspace.save_active_item(&(), ctx) - }); - app.simulate_new_path_selection(|parent_dir| { + workspace.update(&mut cx, |workspace, cx| workspace.save_active_item(&(), cx)); + cx.simulate_new_path_selection(|parent_dir| { assert_eq!(parent_dir, dir.path()); Some(parent_dir.join("the-new-name")) }); - app.read(|ctx| { - assert!(editor.is_dirty(ctx)); - assert_eq!(editor.title(ctx), "untitled"); + cx.read(|cx| { + assert!(editor.is_dirty(cx)); + assert_eq!(editor.title(cx), "untitled"); }); // When the save completes, the buffer's title is updated. editor - .condition(&app, |editor, ctx| !editor.is_dirty(ctx)) + .condition(&cx, |editor, cx| !editor.is_dirty(cx)) .await; - app.read(|ctx| { - assert!(!editor.is_dirty(ctx)); - assert_eq!(editor.title(ctx), "the-new-name"); + cx.read(|cx| { + assert!(!editor.is_dirty(cx)); + assert_eq!(editor.title(cx), "the-new-name"); }); // Edit the file and save it again. This time, there is no filename prompt. - editor.update(&mut app, |editor, ctx| { - editor.insert(&" there".to_string(), ctx); - assert_eq!(editor.is_dirty(ctx.as_ref()), true); - }); - workspace.update(&mut app, |workspace, ctx| { - workspace.save_active_item(&(), ctx) + editor.update(&mut cx, |editor, cx| { + editor.insert(&" there".to_string(), cx); + assert_eq!(editor.is_dirty(cx.as_ref()), true); }); - assert!(!app.did_prompt_for_new_path()); + workspace.update(&mut cx, |workspace, cx| workspace.save_active_item(&(), cx)); + assert!(!cx.did_prompt_for_new_path()); editor - .condition(&app, |editor, ctx| !editor.is_dirty(ctx)) + .condition(&cx, |editor, cx| !editor.is_dirty(cx)) .await; - app.read(|ctx| assert_eq!(editor.title(ctx), "the-new-name")); + cx.read(|cx| assert_eq!(editor.title(cx), "the-new-name")); // Open the same newly-created file in another pane item. The new editor should reuse // the same buffer. - workspace.update(&mut app, |workspace, ctx| { - workspace.open_new_file(&(), ctx); - workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, ctx); + workspace.update(&mut cx, |workspace, cx| { + workspace.open_new_file(&(), cx); + workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx); assert!(workspace - .open_entry((tree.id(), Path::new("the-new-name").into()), ctx) + .open_entry((tree.id(), Path::new("the-new-name").into()), cx) .is_none()); }); - let editor2 = workspace.update(&mut app, |workspace, ctx| { + let editor2 = workspace.update(&mut cx, |workspace, cx| { workspace - .active_item(ctx) + .active_item(cx) .unwrap() .to_any() .downcast::() .unwrap() }); - app.read(|ctx| { - assert_eq!(editor2.read(ctx).buffer(), editor.read(ctx).buffer()); + cx.read(|cx| { + assert_eq!(editor2.read(cx).buffer(), editor.read(cx).buffer()); }) } #[gpui::test] - async fn test_pane_actions(mut app: gpui::TestAppContext) { - app.update(|ctx| pane::init(ctx)); + async fn test_pane_actions(mut cx: gpui::TestAppContext) { + cx.update(|cx| pane::init(cx)); let dir = temp_tree(json!({ "a": { @@ -1175,41 +1171,41 @@ mod tests { }, })); - let app_state = app.read(build_app_state); - let (window_id, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (window_id, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; - let entries = app.read(|ctx| workspace.file_entries(ctx)); + let entries = cx.read(|cx| workspace.file_entries(cx)); let file1 = entries[0].clone(); - let pane_1 = app.read(|ctx| workspace.read(ctx).active_pane().clone()); + let pane_1 = cx.read(|cx| workspace.read(cx).active_pane().clone()); workspace - .update(&mut app, |w, ctx| w.open_entry(file1.clone(), ctx)) + .update(&mut cx, |w, cx| w.open_entry(file1.clone(), cx)) .unwrap() .await; - app.read(|ctx| { + cx.read(|cx| { assert_eq!( - pane_1.read(ctx).active_item().unwrap().entry_id(ctx), + pane_1.read(cx).active_item().unwrap().entry_id(cx), Some(file1.clone()) ); }); - app.dispatch_action(window_id, vec![pane_1.id()], "pane:split_right", ()); - app.update(|ctx| { - let pane_2 = workspace.read(ctx).active_pane().clone(); + cx.dispatch_action(window_id, vec![pane_1.id()], "pane:split_right", ()); + cx.update(|cx| { + let pane_2 = workspace.read(cx).active_pane().clone(); assert_ne!(pane_1, pane_2); - let pane2_item = pane_2.read(ctx).active_item().unwrap(); - assert_eq!(pane2_item.entry_id(ctx.as_ref()), Some(file1.clone())); + let pane2_item = pane_2.read(cx).active_item().unwrap(); + assert_eq!(pane2_item.entry_id(cx.as_ref()), Some(file1.clone())); - ctx.dispatch_action(window_id, vec![pane_2.id()], "pane:close_active_item", ()); - let workspace_view = workspace.read(ctx); + cx.dispatch_action(window_id, vec![pane_2.id()], "pane:close_active_item", ()); + let workspace_view = workspace.read(cx); assert_eq!(workspace_view.panes.len(), 1); assert_eq!(workspace_view.active_pane(), &pane_1); }); From e8deed44abc672b39b596e8e5ef81e3d41cb9cf1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:01:35 -0700 Subject: [PATCH 06/16] Rename context parameters to `cx` in worktree.rs --- zed/src/worktree.rs | 177 ++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 90 deletions(-) diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index a50dacc4683de41d7a8c02f627746ab229122f5c..f8bf316d544b10abd26ad0891c80e7ee0cd04251 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -67,10 +67,10 @@ struct FileHandleState { } impl Worktree { - pub fn new(path: impl Into>, ctx: &mut ModelContext) -> Self { + pub fn new(path: impl Into>, cx: &mut ModelContext) -> Self { let abs_path = path.into(); let (scan_state_tx, scan_state_rx) = smol::channel::unbounded(); - let id = ctx.model_id(); + let id = cx.model_id(); let snapshot = Snapshot { id, scan_id: 0, @@ -99,14 +99,13 @@ impl Worktree { scanner.run(event_stream) }); - ctx.spawn(|this, mut ctx| { + cx.spawn(|this, mut cx| { let this = this.downgrade(); async move { while let Ok(scan_state) = scan_state_rx.recv().await { - let alive = ctx.update(|ctx| { - if let Some(handle) = this.upgrade(&ctx) { - handle - .update(ctx, |this, ctx| this.observe_scan_state(scan_state, ctx)); + let alive = cx.update(|cx| { + if let Some(handle) = this.upgrade(&cx) { + handle.update(cx, |this, cx| this.observe_scan_state(scan_state, cx)); true } else { false @@ -134,21 +133,21 @@ impl Worktree { } } - fn observe_scan_state(&mut self, scan_state: ScanState, ctx: &mut ModelContext) { + fn observe_scan_state(&mut self, scan_state: ScanState, cx: &mut ModelContext) { let _ = self.scan_state.0.blocking_send(scan_state); - self.poll_entries(ctx); + self.poll_entries(cx); } - fn poll_entries(&mut self, ctx: &mut ModelContext) { + fn poll_entries(&mut self, cx: &mut ModelContext) { self.snapshot = self.background_snapshot.lock().clone(); - ctx.notify(); + cx.notify(); if self.is_scanning() && !self.poll_scheduled { - ctx.spawn(|this, mut ctx| async move { + cx.spawn(|this, mut cx| async move { smol::Timer::after(Duration::from_millis(100)).await; - this.update(&mut ctx, |this, ctx| { + this.update(&mut cx, |this, cx| { this.poll_scheduled = false; - this.poll_entries(ctx); + this.poll_entries(cx); }) }) .detach(); @@ -187,11 +186,11 @@ impl Worktree { pub fn load_history( &self, path: &Path, - ctx: &AppContext, + cx: &AppContext, ) -> impl Future> { let path = path.to_path_buf(); let abs_path = self.absolutize(&path); - ctx.background_executor().spawn(async move { + cx.background_executor().spawn(async move { let mut file = fs::File::open(&abs_path)?; let mut base_text = String::new(); file.read_to_string(&mut base_text)?; @@ -199,11 +198,11 @@ impl Worktree { }) } - pub fn save<'a>(&self, path: &Path, content: Rope, ctx: &AppContext) -> Task> { + pub fn save<'a>(&self, path: &Path, content: Rope, cx: &AppContext) -> Task> { let handles = self.handles.clone(); let path = path.to_path_buf(); let abs_path = self.absolutize(&path); - ctx.background_executor().spawn(async move { + cx.background_executor().spawn(async move { let buffer_size = content.summary().bytes.min(10 * 1024); let file = fs::File::create(&abs_path)?; let mut writer = io::BufWriter::with_capacity(buffer_size, &file); @@ -430,12 +429,12 @@ impl FileHandle { /// Returns the last component of this handle's absolute path. If this handle refers to the root /// of its worktree, then this method will return the name of the worktree itself. - pub fn file_name<'a>(&'a self, ctx: &'a AppContext) -> Option { + pub fn file_name<'a>(&'a self, cx: &'a AppContext) -> Option { self.state .lock() .path .file_name() - .or_else(|| self.worktree.read(ctx).abs_path().file_name()) + .or_else(|| self.worktree.read(cx).abs_path().file_name()) .map(Into::into) } @@ -451,13 +450,13 @@ impl FileHandle { !self.is_deleted() } - pub fn load_history(&self, ctx: &AppContext) -> impl Future> { - self.worktree.read(ctx).load_history(&self.path(), ctx) + pub fn load_history(&self, cx: &AppContext) -> impl Future> { + self.worktree.read(cx).load_history(&self.path(), cx) } - pub fn save<'a>(&self, content: Rope, ctx: &AppContext) -> Task> { - let worktree = self.worktree.read(ctx); - worktree.save(&self.path(), content, ctx) + pub fn save<'a>(&self, content: Rope, cx: &AppContext) -> Task> { + let worktree = self.worktree.read(cx); + worktree.save(&self.path(), content, cx) } pub fn worktree_id(&self) -> usize { @@ -470,12 +469,12 @@ impl FileHandle { pub fn observe_from_model( &self, - ctx: &mut ModelContext, + cx: &mut ModelContext, mut callback: impl FnMut(&mut T, FileHandle, &mut ModelContext) + 'static, ) { let mut prev_state = self.state.lock().clone(); let cur_state = Arc::downgrade(&self.state); - ctx.observe(&self.worktree, move |observer, worktree, ctx| { + cx.observe(&self.worktree, move |observer, worktree, cx| { if let Some(cur_state) = cur_state.upgrade() { let cur_state_unlocked = cur_state.lock(); if *cur_state_unlocked != prev_state { @@ -487,7 +486,7 @@ impl FileHandle { worktree, state: cur_state, }, - ctx, + cx, ); } } @@ -1201,23 +1200,23 @@ struct UpdateIgnoreStatusJob { } pub trait WorktreeHandle { - fn file(&self, path: impl AsRef, app: &mut MutableAppContext) -> Task; + fn file(&self, path: impl AsRef, cx: &mut MutableAppContext) -> Task; #[cfg(test)] fn flush_fs_events<'a>( &self, - app: &'a gpui::TestAppContext, + cx: &'a gpui::TestAppContext, ) -> futures_core::future::LocalBoxFuture<'a, ()>; } impl WorktreeHandle for ModelHandle { - fn file(&self, path: impl AsRef, app: &mut MutableAppContext) -> Task { + fn file(&self, path: impl AsRef, cx: &mut MutableAppContext) -> Task { let path = Arc::from(path.as_ref()); let handle = self.clone(); - let tree = self.read(app); + let tree = self.read(cx); let abs_path = tree.absolutize(&path); - app.spawn(|ctx| async move { - let mtime = ctx + cx.spawn(|cx| async move { + let mtime = cx .background_executor() .spawn(async move { if let Ok(metadata) = fs::metadata(&abs_path) { @@ -1227,7 +1226,7 @@ impl WorktreeHandle for ModelHandle { } }) .await; - let state = handle.read_with(&ctx, |tree, _| { + let state = handle.read_with(&cx, |tree, _| { let mut handles = tree.handles.lock(); if let Some(state) = handles.get(&path).and_then(Weak::upgrade) { state @@ -1267,23 +1266,23 @@ impl WorktreeHandle for ModelHandle { #[cfg(test)] fn flush_fs_events<'a>( &self, - app: &'a gpui::TestAppContext, + cx: &'a gpui::TestAppContext, ) -> futures_core::future::LocalBoxFuture<'a, ()> { use smol::future::FutureExt; let filename = "fs-event-sentinel"; - let root_path = app.read(|ctx| self.read(ctx).abs_path.clone()); + let root_path = cx.read(|cx| self.read(cx).abs_path.clone()); let tree = self.clone(); async move { fs::write(root_path.join(filename), "").unwrap(); - tree.condition(&app, |tree, _| tree.entry_for_path(filename).is_some()) + tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_some()) .await; fs::remove_file(root_path.join(filename)).unwrap(); - tree.condition(&app, |tree, _| tree.entry_for_path(filename).is_none()) + tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_none()) .await; - app.read(|ctx| tree.read(ctx).scan_complete()).await; + cx.read(|cx| tree.read(cx).scan_complete()).await; } .boxed_local() } @@ -1408,7 +1407,7 @@ mod tests { use std::time::{SystemTime, UNIX_EPOCH}; #[gpui::test] - async fn test_populate_and_search(mut app: gpui::TestAppContext) { + async fn test_populate_and_search(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "root": { "apple": "", @@ -1432,11 +1431,11 @@ mod tests { ) .unwrap(); - let tree = app.add_model(|ctx| Worktree::new(root_link_path, ctx)); + let tree = cx.add_model(|cx| Worktree::new(root_link_path, cx)); - app.read(|ctx| tree.read(ctx).scan_complete()).await; - app.read(|ctx| { - let tree = tree.read(ctx); + cx.read(|cx| tree.read(cx).scan_complete()).await; + cx.read(|cx| { + let tree = tree.read(cx); assert_eq!(tree.file_count(), 5); assert_eq!( @@ -1452,7 +1451,7 @@ mod tests { false, 10, Default::default(), - ctx.thread_pool().clone(), + cx.thread_pool().clone(), ) .into_iter() .map(|result| result.path) @@ -1468,60 +1467,58 @@ mod tests { } #[gpui::test] - async fn test_save_file(mut app: gpui::TestAppContext) { + async fn test_save_file(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "file1": "the old contents", })); - let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx)); - app.read(|ctx| tree.read(ctx).scan_complete()).await; - app.read(|ctx| assert_eq!(tree.read(ctx).file_count(), 1)); + let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx)); + cx.read(|cx| tree.read(cx).scan_complete()).await; + cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1)); - let buffer = - app.add_model(|ctx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), ctx)); + let buffer = cx.add_model(|cx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), cx)); - let path = tree.update(&mut app, |tree, ctx| { + let path = tree.update(&mut cx, |tree, cx| { let path = tree.files(0).next().unwrap().path().clone(); assert_eq!(path.file_name().unwrap(), "file1"); - smol::block_on(tree.save(&path, buffer.read(ctx).snapshot().text(), ctx.as_ref())) + smol::block_on(tree.save(&path, buffer.read(cx).snapshot().text(), cx.as_ref())) .unwrap(); path }); - let history = app - .read(|ctx| tree.read(ctx).load_history(&path, ctx)) + let history = cx + .read(|cx| tree.read(cx).load_history(&path, cx)) .await .unwrap(); - app.read(|ctx| { - assert_eq!(history.base_text.as_ref(), buffer.read(ctx).text()); + cx.read(|cx| { + assert_eq!(history.base_text.as_ref(), buffer.read(cx).text()); }); } #[gpui::test] - async fn test_save_in_single_file_worktree(mut app: gpui::TestAppContext) { + async fn test_save_in_single_file_worktree(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "file1": "the old contents", })); - let tree = app.add_model(|ctx| Worktree::new(dir.path().join("file1"), ctx)); - app.read(|ctx| tree.read(ctx).scan_complete()).await; - app.read(|ctx| assert_eq!(tree.read(ctx).file_count(), 1)); + let tree = cx.add_model(|cx| Worktree::new(dir.path().join("file1"), cx)); + cx.read(|cx| tree.read(cx).scan_complete()).await; + cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1)); - let buffer = - app.add_model(|ctx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), ctx)); + let buffer = cx.add_model(|cx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), cx)); - let file = app.update(|ctx| tree.file("", ctx)).await; - app.update(|ctx| { + let file = cx.update(|cx| tree.file("", cx)).await; + cx.update(|cx| { assert_eq!(file.path().file_name(), None); - smol::block_on(file.save(buffer.read(ctx).snapshot().text(), ctx.as_ref())).unwrap(); + smol::block_on(file.save(buffer.read(cx).snapshot().text(), cx.as_ref())).unwrap(); }); - let history = app.read(|ctx| file.load_history(ctx)).await.unwrap(); - app.read(|ctx| assert_eq!(history.base_text.as_ref(), buffer.read(ctx).text())); + let history = cx.read(|cx| file.load_history(cx)).await.unwrap(); + cx.read(|cx| assert_eq!(history.base_text.as_ref(), buffer.read(cx).text())); } #[gpui::test] - async fn test_rescan_simple(mut app: gpui::TestAppContext) { + async fn test_rescan_simple(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "a": { "file1": "", @@ -1536,31 +1533,31 @@ mod tests { } })); - let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx)); - let file2 = app.update(|ctx| tree.file("a/file2", ctx)).await; - let file3 = app.update(|ctx| tree.file("a/file3", ctx)).await; - let file4 = app.update(|ctx| tree.file("b/c/file4", ctx)).await; - let file5 = app.update(|ctx| tree.file("b/c/file5", ctx)).await; - let non_existent_file = app.update(|ctx| tree.file("a/file_x", ctx)).await; + let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx)); + let file2 = cx.update(|cx| tree.file("a/file2", cx)).await; + let file3 = cx.update(|cx| tree.file("a/file3", cx)).await; + let file4 = cx.update(|cx| tree.file("b/c/file4", cx)).await; + let file5 = cx.update(|cx| tree.file("b/c/file5", cx)).await; + let non_existent_file = cx.update(|cx| tree.file("a/file_x", cx)).await; // After scanning, the worktree knows which files exist and which don't. - app.read(|ctx| tree.read(ctx).scan_complete()).await; + cx.read(|cx| tree.read(cx).scan_complete()).await; assert!(!file2.is_deleted()); assert!(!file3.is_deleted()); assert!(!file4.is_deleted()); assert!(!file5.is_deleted()); assert!(non_existent_file.is_deleted()); - tree.flush_fs_events(&app).await; + tree.flush_fs_events(&cx).await; std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap(); std::fs::remove_file(dir.path().join("b/c/file5")).unwrap(); std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap(); std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap(); - tree.flush_fs_events(&app).await; + tree.flush_fs_events(&cx).await; - app.read(|ctx| { + cx.read(|cx| { assert_eq!( - tree.read(ctx) + tree.read(cx) .paths() .map(|p| p.to_str().unwrap()) .collect::>(), @@ -1591,7 +1588,7 @@ mod tests { } #[gpui::test] - async fn test_rescan_with_gitignore(mut app: gpui::TestAppContext) { + async fn test_rescan_with_gitignore(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ ".git": {}, ".gitignore": "ignored-dir\n", @@ -1603,11 +1600,11 @@ mod tests { } })); - let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx)); - app.read(|ctx| tree.read(ctx).scan_complete()).await; - tree.flush_fs_events(&app).await; - app.read(|ctx| { - let tree = tree.read(ctx); + let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx)); + cx.read(|cx| tree.read(cx).scan_complete()).await; + tree.flush_fs_events(&cx).await; + cx.read(|cx| { + let tree = tree.read(cx); let tracked = tree.entry_for_path("tracked-dir/tracked-file1").unwrap(); let ignored = tree.entry_for_path("ignored-dir/ignored-file1").unwrap(); assert_eq!(tracked.is_ignored(), false); @@ -1616,9 +1613,9 @@ mod tests { fs::write(dir.path().join("tracked-dir/tracked-file2"), "").unwrap(); fs::write(dir.path().join("ignored-dir/ignored-file2"), "").unwrap(); - tree.flush_fs_events(&app).await; - app.read(|ctx| { - let tree = tree.read(ctx); + tree.flush_fs_events(&cx).await; + cx.read(|cx| { + let tree = tree.read(cx); let dot_git = tree.entry_for_path(".git").unwrap(); let tracked = tree.entry_for_path("tracked-dir/tracked-file2").unwrap(); let ignored = tree.entry_for_path("ignored-dir/ignored-file2").unwrap(); From b4430d18ed350a5e9a72d3f80f1916406b472569 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:03:13 -0700 Subject: [PATCH 07/16] Rename context parameters to `cx` in buffer.rs --- zed/src/editor/buffer.rs | 440 +++++++++++++++++++-------------------- 1 file changed, 218 insertions(+), 222 deletions(-) diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index 65b8075a35d438ec42ab476a6e998307c977dfaa..7fd9c4c9d6d81f0511dc430eea4afbce0dc70d60 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -416,9 +416,9 @@ impl Buffer { pub fn new>>( replica_id: ReplicaId, base_text: T, - ctx: &mut ModelContext, + cx: &mut ModelContext, ) -> Self { - Self::build(replica_id, History::new(base_text.into()), None, None, ctx) + Self::build(replica_id, History::new(base_text.into()), None, None, cx) } pub fn from_history( @@ -426,9 +426,9 @@ impl Buffer { history: History, file: Option, language: Option>, - ctx: &mut ModelContext, + cx: &mut ModelContext, ) -> Self { - Self::build(replica_id, history, file, language, ctx) + Self::build(replica_id, history, file, language, cx) } fn build( @@ -436,31 +436,31 @@ impl Buffer { history: History, file: Option, language: Option>, - ctx: &mut ModelContext, + cx: &mut ModelContext, ) -> Self { let saved_mtime; if let Some(file) = file.as_ref() { saved_mtime = file.mtime(); - file.observe_from_model(ctx, |this, file, ctx| { + file.observe_from_model(cx, |this, file, cx| { let version = this.version.clone(); if this.version == this.saved_version { if file.is_deleted() { - ctx.emit(Event::Dirtied); + cx.emit(Event::Dirtied); } else { - ctx.spawn(|handle, mut ctx| async move { - let (current_version, history) = handle.read_with(&ctx, |this, ctx| { - (this.version.clone(), file.load_history(ctx.as_ref())) + cx.spawn(|handle, mut cx| async move { + let (current_version, history) = handle.read_with(&cx, |this, cx| { + (this.version.clone(), file.load_history(cx.as_ref())) }); if let (Ok(history), true) = (history.await, current_version == version) { let diff = handle - .read_with(&ctx, |this, ctx| this.diff(history.base_text, ctx)) + .read_with(&cx, |this, cx| this.diff(history.base_text, cx)) .await; - handle.update(&mut ctx, |this, ctx| { - if let Some(_ops) = this.set_text_via_diff(diff, ctx) { + handle.update(&mut cx, |this, cx| { + if let Some(_ops) = this.set_text_via_diff(diff, cx) { this.saved_version = this.version.clone(); this.saved_mtime = file.mtime(); - ctx.emit(Event::Reloaded); + cx.emit(Event::Reloaded); } }); } @@ -468,7 +468,7 @@ impl Buffer { .detach(); } } - ctx.emit(Event::FileHandleChanged); + cx.emit(Event::FileHandleChanged); }); } else { saved_mtime = UNIX_EPOCH; @@ -547,7 +547,7 @@ impl Buffer { local_clock: time::Local::new(replica_id), lamport_clock: time::Lamport::new(replica_id), }; - result.reparse(ctx); + result.reparse(cx); result } @@ -567,17 +567,17 @@ impl Buffer { pub fn save( &mut self, new_file: Option, - ctx: &mut ModelContext, + cx: &mut ModelContext, ) -> Task> { let text = self.visible_text.clone(); let version = self.version.clone(); let file = self.file.clone(); - ctx.spawn(|handle, mut ctx| async move { + cx.spawn(|handle, mut cx| async move { if let Some(file) = new_file.as_ref().or(file.as_ref()) { - let result = ctx.read(|ctx| file.save(text, ctx.as_ref())).await; + let result = cx.read(|cx| file.save(text, cx.as_ref())).await; if result.is_ok() { - handle.update(&mut ctx, |me, ctx| me.did_save(version, new_file, ctx)); + handle.update(&mut cx, |me, cx| me.did_save(version, new_file, cx)); } result } else { @@ -590,7 +590,7 @@ impl Buffer { &mut self, version: time::Global, file: Option, - ctx: &mut ModelContext, + cx: &mut ModelContext, ) { if file.is_some() { self.file = file; @@ -599,7 +599,7 @@ impl Buffer { self.saved_mtime = file.mtime(); } self.saved_version = version; - ctx.emit(Event::Saved); + cx.emit(Event::Saved); } pub fn syntax_tree(&self) -> Option { @@ -647,7 +647,7 @@ impl Buffer { } } - fn reparse(&mut self, ctx: &mut ModelContext) { + fn reparse(&mut self, cx: &mut ModelContext) { // Avoid spawning a new parsing task if the buffer is already being reparsed // due to an earlier edit. if self.is_parsing { @@ -656,16 +656,16 @@ impl Buffer { if let Some(language) = self.language.clone() { self.is_parsing = true; - ctx.spawn(|handle, mut ctx| async move { - while handle.read_with(&ctx, |this, _| this.should_reparse()) { + cx.spawn(|handle, mut cx| async move { + while handle.read_with(&cx, |this, _| this.should_reparse()) { // The parse tree is out of date, so grab the syntax tree to synchronously // splice all the edits that have happened since the last parse. - let new_tree = handle.update(&mut ctx, |this, _| this.syntax_tree()); + let new_tree = handle.update(&mut cx, |this, _| this.syntax_tree()); let (new_text, new_version) = handle - .read_with(&ctx, |this, _| (this.visible_text.clone(), this.version())); + .read_with(&cx, |this, _| (this.visible_text.clone(), this.version())); // Parse the current text in a background thread. - let new_tree = ctx + let new_tree = cx .background_executor() .spawn({ let language = language.clone(); @@ -673,17 +673,17 @@ impl Buffer { }) .await; - handle.update(&mut ctx, |this, ctx| { + handle.update(&mut cx, |this, cx| { *this.syntax_tree.lock() = Some(SyntaxTree { tree: new_tree, parsed: true, version: new_version, }); - ctx.emit(Event::Reparsed); - ctx.notify(); + cx.emit(Event::Reparsed); + cx.notify(); }); } - handle.update(&mut ctx, |this, _| this.is_parsing = false); + handle.update(&mut cx, |this, _| this.is_parsing = false); }) .detach(); } @@ -750,11 +750,11 @@ impl Buffer { .min_by_key(|(open_range, close_range)| close_range.end - open_range.start) } - fn diff(&self, new_text: Arc, ctx: &AppContext) -> Task { + fn diff(&self, new_text: Arc, cx: &AppContext) -> Task { // TODO: it would be nice to not allocate here. let old_text = self.text(); let base_version = self.version(); - ctx.background_executor().spawn(async move { + cx.background_executor().spawn(async move { let changes = TextDiff::from_lines(old_text.as_str(), new_text.as_ref()) .iter_all_changes() .map(|c| (c.tag(), c.value().len())) @@ -770,7 +770,7 @@ impl Buffer { fn set_text_via_diff( &mut self, diff: Diff, - ctx: &mut ModelContext, + cx: &mut ModelContext, ) -> Option> { if self.version == diff.base_version { self.start_transaction(None).unwrap(); @@ -780,19 +780,20 @@ impl Buffer { let range = offset..(offset + len); match tag { ChangeTag::Equal => offset += len, - ChangeTag::Delete => operations - .extend_from_slice(&self.edit(Some(range), "", Some(ctx)).unwrap()), + ChangeTag::Delete => { + operations.extend_from_slice(&self.edit(Some(range), "", Some(cx)).unwrap()) + } ChangeTag::Insert => { operations.extend_from_slice( &self - .edit(Some(offset..offset), &diff.new_text[range], Some(ctx)) + .edit(Some(offset..offset), &diff.new_text[range], Some(cx)) .unwrap(), ); offset += len; } } } - self.end_transaction(None, Some(ctx)).unwrap(); + self.end_transaction(None, Some(cx)).unwrap(); Some(operations) } else { None @@ -909,16 +910,16 @@ impl Buffer { pub fn end_transaction( &mut self, set_id: Option, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> Result<()> { - self.end_transaction_at(set_id, Instant::now(), ctx) + self.end_transaction_at(set_id, Instant::now(), cx) } fn end_transaction_at( &mut self, set_id: Option, now: Instant, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> Result<()> { let selections = if let Some(set_id) = set_id { let selections = self @@ -935,12 +936,12 @@ impl Buffer { let was_dirty = transaction.buffer_was_dirty; self.history.group(); - if let Some(ctx) = ctx { - ctx.notify(); + if let Some(cx) = cx { + cx.notify(); if self.edits_since(since).next().is_some() { - self.did_edit(was_dirty, ctx); - self.reparse(ctx); + self.did_edit(was_dirty, cx); + self.reparse(cx); } } } @@ -952,7 +953,7 @@ impl Buffer { &mut self, old_ranges: I, new_text: T, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> Result> where I: IntoIterator>, @@ -997,22 +998,22 @@ impl Buffer { } } - self.end_transaction_at(None, Instant::now(), ctx)?; + self.end_transaction_at(None, Instant::now(), cx)?; Ok(ops) } - fn did_edit(&self, was_dirty: bool, ctx: &mut ModelContext) { - ctx.emit(Event::Edited); + fn did_edit(&self, was_dirty: bool, cx: &mut ModelContext) { + cx.emit(Event::Edited); if !was_dirty { - ctx.emit(Event::Dirtied); + cx.emit(Event::Dirtied); } } pub fn add_selection_set( &mut self, selections: impl Into>, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> (SelectionSetId, Operation) { let selections = selections.into(); let lamport_timestamp = self.lamport_clock.tick(); @@ -1020,8 +1021,8 @@ impl Buffer { .insert(lamport_timestamp, Arc::clone(&selections)); self.selections_last_update += 1; - if let Some(ctx) = ctx { - ctx.notify(); + if let Some(cx) = cx { + cx.notify(); } ( @@ -1038,7 +1039,7 @@ impl Buffer { &mut self, set_id: SelectionSetId, selections: impl Into>, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> Result { let selections = selections.into(); self.selections.insert(set_id, selections.clone()); @@ -1046,8 +1047,8 @@ impl Buffer { let lamport_timestamp = self.lamport_clock.tick(); self.selections_last_update += 1; - if let Some(ctx) = ctx { - ctx.notify(); + if let Some(cx) = cx { + cx.notify(); } Ok(Operation::UpdateSelections { @@ -1060,7 +1061,7 @@ impl Buffer { pub fn remove_selection_set( &mut self, set_id: SelectionSetId, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> Result { self.selections .remove(&set_id) @@ -1068,8 +1069,8 @@ impl Buffer { let lamport_timestamp = self.lamport_clock.tick(); self.selections_last_update += 1; - if let Some(ctx) = ctx { - ctx.notify(); + if let Some(cx) = cx { + cx.notify(); } Ok(Operation::UpdateSelections { @@ -1089,7 +1090,7 @@ impl Buffer { pub fn apply_ops>( &mut self, ops: I, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> Result<()> { let was_dirty = self.is_dirty(); let old_version = self.version.clone(); @@ -1106,11 +1107,11 @@ impl Buffer { self.deferred_ops.insert(deferred_ops); self.flush_deferred_ops()?; - if let Some(ctx) = ctx { - ctx.notify(); + if let Some(cx) = cx { + cx.notify(); if self.edits_since(old_version).next().is_some() { - self.did_edit(was_dirty, ctx); - self.reparse(ctx); + self.did_edit(was_dirty, cx); + self.reparse(cx); } } @@ -1316,7 +1317,7 @@ impl Buffer { Ok(()) } - pub fn undo(&mut self, mut ctx: Option<&mut ModelContext>) -> Vec { + pub fn undo(&mut self, mut cx: Option<&mut ModelContext>) -> Vec { let was_dirty = self.is_dirty(); let old_version = self.version.clone(); @@ -1328,22 +1329,22 @@ impl Buffer { } if let Some((set_id, selections)) = selections { - let _ = self.update_selection_set(set_id, selections, ctx.as_deref_mut()); + let _ = self.update_selection_set(set_id, selections, cx.as_deref_mut()); } } - if let Some(ctx) = ctx { - ctx.notify(); + if let Some(cx) = cx { + cx.notify(); if self.edits_since(old_version).next().is_some() { - self.did_edit(was_dirty, ctx); - self.reparse(ctx); + self.did_edit(was_dirty, cx); + self.reparse(cx); } } ops } - pub fn redo(&mut self, mut ctx: Option<&mut ModelContext>) -> Vec { + pub fn redo(&mut self, mut cx: Option<&mut ModelContext>) -> Vec { let was_dirty = self.is_dirty(); let old_version = self.version.clone(); @@ -1355,15 +1356,15 @@ impl Buffer { } if let Some((set_id, selections)) = selections { - let _ = self.update_selection_set(set_id, selections, ctx.as_deref_mut()); + let _ = self.update_selection_set(set_id, selections, cx.as_deref_mut()); } } - if let Some(ctx) = ctx { - ctx.notify(); + if let Some(cx) = cx { + cx.notify(); if self.edits_since(old_version).next().is_some() { - self.did_edit(was_dirty, ctx); - self.reparse(ctx); + self.did_edit(was_dirty, cx); + self.reparse(cx); } } @@ -2712,9 +2713,9 @@ mod tests { }; #[gpui::test] - fn test_edit(ctx: &mut gpui::MutableAppContext) { - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "abc", ctx); + fn test_edit(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { + let mut buffer = Buffer::new(0, "abc", cx); assert_eq!(buffer.text(), "abc"); buffer.edit(vec![3..3], "def", None).unwrap(); assert_eq!(buffer.text(), "abcdef"); @@ -2731,51 +2732,51 @@ mod tests { } #[gpui::test] - fn test_edit_events(app: &mut gpui::MutableAppContext) { + fn test_edit_events(cx: &mut gpui::MutableAppContext) { let mut now = Instant::now(); let buffer_1_events = Rc::new(RefCell::new(Vec::new())); let buffer_2_events = Rc::new(RefCell::new(Vec::new())); - let buffer1 = app.add_model(|ctx| Buffer::new(0, "abcdef", ctx)); - let buffer2 = app.add_model(|ctx| Buffer::new(1, "abcdef", ctx)); + let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx)); + let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx)); let mut buffer_ops = Vec::new(); - buffer1.update(app, |buffer, ctx| { + buffer1.update(cx, |buffer, cx| { let buffer_1_events = buffer_1_events.clone(); - ctx.subscribe(&buffer1, move |_, event, _| { + cx.subscribe(&buffer1, move |_, event, _| { buffer_1_events.borrow_mut().push(event.clone()) }); let buffer_2_events = buffer_2_events.clone(); - ctx.subscribe(&buffer2, move |_, event, _| { + cx.subscribe(&buffer2, move |_, event, _| { buffer_2_events.borrow_mut().push(event.clone()) }); // An edit emits an edited event, followed by a dirtied event, // since the buffer was previously in a clean state. - let ops = buffer.edit(Some(2..4), "XYZ", Some(ctx)).unwrap(); + let ops = buffer.edit(Some(2..4), "XYZ", Some(cx)).unwrap(); buffer_ops.extend_from_slice(&ops); // An empty transaction does not emit any events. buffer.start_transaction(None).unwrap(); - buffer.end_transaction(None, Some(ctx)).unwrap(); + buffer.end_transaction(None, Some(cx)).unwrap(); // A transaction containing two edits emits one edited event. now += Duration::from_secs(1); buffer.start_transaction_at(None, now).unwrap(); - let ops = buffer.edit(Some(5..5), "u", Some(ctx)).unwrap(); + let ops = buffer.edit(Some(5..5), "u", Some(cx)).unwrap(); buffer_ops.extend_from_slice(&ops); - let ops = buffer.edit(Some(6..6), "w", Some(ctx)).unwrap(); + let ops = buffer.edit(Some(6..6), "w", Some(cx)).unwrap(); buffer_ops.extend_from_slice(&ops); - buffer.end_transaction_at(None, now, Some(ctx)).unwrap(); + buffer.end_transaction_at(None, now, Some(cx)).unwrap(); // Undoing a transaction emits one edited event. - let ops = buffer.undo(Some(ctx)); + let ops = buffer.undo(Some(cx)); buffer_ops.extend_from_slice(&ops); }); // Incorporating a set of remote ops emits a single edited event, // followed by a dirtied event. - buffer2.update(app, |buffer, ctx| { - buffer.apply_ops(buffer_ops, Some(ctx)).unwrap(); + buffer2.update(cx, |buffer, cx| { + buffer.apply_ops(buffer_ops, Some(cx)).unwrap(); }); let buffer_1_events = buffer_1_events.borrow(); @@ -2789,7 +2790,7 @@ mod tests { } #[gpui::test] - fn test_random_edits(ctx: &mut gpui::MutableAppContext) { + fn test_random_edits(cx: &mut gpui::MutableAppContext) { for seed in 0..100 { println!("{:?}", seed); let mut rng = &mut StdRng::seed_from_u64(seed); @@ -2798,8 +2799,8 @@ mod tests { let mut reference_string = RandomCharIter::new(&mut rng) .take(reference_string_len) .collect::(); - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, reference_string.as_str(), ctx); + cx.add_model(|cx| { + let mut buffer = Buffer::new(0, reference_string.as_str(), cx); let mut buffer_versions = Vec::new(); for _i in 0..10 { let (old_ranges, new_text, _) = buffer.randomly_mutate(rng, None); @@ -2851,9 +2852,9 @@ mod tests { } #[gpui::test] - fn test_line_len(ctx: &mut gpui::MutableAppContext) { - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + fn test_line_len(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { + let mut buffer = Buffer::new(0, "", cx); buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap(); buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); buffer.edit(vec![18..18], "\npqrs\n", None).unwrap(); @@ -2870,9 +2871,9 @@ mod tests { } #[gpui::test] - fn test_text_summary_for_range(ctx: &mut gpui::MutableAppContext) { - ctx.add_model(|ctx| { - let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz", ctx); + fn test_text_summary_for_range(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { + let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz", cx); assert_eq!( buffer.text_summary_for_range(1..3), TextSummary { @@ -2933,9 +2934,9 @@ mod tests { } #[gpui::test] - fn test_chars_at(ctx: &mut gpui::MutableAppContext) { - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + fn test_chars_at(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { + let mut buffer = Buffer::new(0, "", cx); buffer.edit(vec![0..0], "abcd\nefgh\nij", None).unwrap(); buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); buffer.edit(vec![18..18], "\npqrs", None).unwrap(); @@ -2957,7 +2958,7 @@ mod tests { assert_eq!(chars.collect::(), "PQrs"); // Regression test: - let mut buffer = Buffer::new(0, "", ctx); + let mut buffer = Buffer::new(0, "", cx); buffer.edit(vec![0..0], "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n", None).unwrap(); buffer.edit(vec![60..60], "\n", None).unwrap(); @@ -2989,9 +2990,9 @@ mod tests { } #[gpui::test] - fn test_anchors(ctx: &mut gpui::MutableAppContext) { - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + fn test_anchors(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { + let mut buffer = Buffer::new(0, "", cx); buffer.edit(vec![0..0], "abc", None).unwrap(); let left_anchor = buffer.anchor_before(2); let right_anchor = buffer.anchor_after(2); @@ -3128,9 +3129,9 @@ mod tests { } #[gpui::test] - fn test_anchors_at_start_and_end(ctx: &mut gpui::MutableAppContext) { - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + fn test_anchors_at_start_and_end(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { + let mut buffer = Buffer::new(0, "", cx); let before_start_anchor = buffer.anchor_before(0); let after_end_anchor = buffer.anchor_after(0); @@ -3155,25 +3156,25 @@ mod tests { #[test] fn test_is_dirty() { - App::test_async((), |mut app| async move { + App::test_async((), |mut cx| async move { let dir = temp_tree(json!({ "file1": "", "file2": "", "file3": "", })); - let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx)); - tree.flush_fs_events(&app).await; - app.read(|ctx| tree.read(ctx).scan_complete()).await; + let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx)); + tree.flush_fs_events(&cx).await; + cx.read(|cx| tree.read(cx).scan_complete()).await; - let file1 = app.update(|ctx| tree.file("file1", ctx)).await; - let buffer1 = app.add_model(|ctx| { - Buffer::from_history(0, History::new("abc".into()), Some(file1), None, ctx) + let file1 = cx.update(|cx| tree.file("file1", cx)).await; + let buffer1 = cx.add_model(|cx| { + Buffer::from_history(0, History::new("abc".into()), Some(file1), None, cx) }); let events = Rc::new(RefCell::new(Vec::new())); // initially, the buffer isn't dirty. - buffer1.update(&mut app, |buffer, ctx| { - ctx.subscribe(&buffer1, { + buffer1.update(&mut cx, |buffer, cx| { + cx.subscribe(&buffer1, { let events = events.clone(); move |_, event, _| events.borrow_mut().push(event.clone()) }); @@ -3181,31 +3182,31 @@ mod tests { assert!(!buffer.is_dirty()); assert!(events.borrow().is_empty()); - buffer.edit(vec![1..2], "", Some(ctx)).unwrap(); + buffer.edit(vec![1..2], "", Some(cx)).unwrap(); }); // after the first edit, the buffer is dirty, and emits a dirtied event. - buffer1.update(&mut app, |buffer, ctx| { + buffer1.update(&mut cx, |buffer, cx| { assert!(buffer.text() == "ac"); assert!(buffer.is_dirty()); assert_eq!(*events.borrow(), &[Event::Edited, Event::Dirtied]); events.borrow_mut().clear(); - buffer.did_save(buffer.version(), None, ctx); + buffer.did_save(buffer.version(), None, cx); }); // after saving, the buffer is not dirty, and emits a saved event. - buffer1.update(&mut app, |buffer, ctx| { + buffer1.update(&mut cx, |buffer, cx| { assert!(!buffer.is_dirty()); assert_eq!(*events.borrow(), &[Event::Saved]); events.borrow_mut().clear(); - buffer.edit(vec![1..1], "B", Some(ctx)).unwrap(); - buffer.edit(vec![2..2], "D", Some(ctx)).unwrap(); + buffer.edit(vec![1..1], "B", Some(cx)).unwrap(); + buffer.edit(vec![2..2], "D", Some(cx)).unwrap(); }); // after editing again, the buffer is dirty, and emits another dirty event. - buffer1.update(&mut app, |buffer, ctx| { + buffer1.update(&mut cx, |buffer, cx| { assert!(buffer.text() == "aBDc"); assert!(buffer.is_dirty()); assert_eq!( @@ -3216,7 +3217,7 @@ mod tests { // TODO - currently, after restoring the buffer to its // previously-saved state, the is still considered dirty. - buffer.edit(vec![1..3], "", Some(ctx)).unwrap(); + buffer.edit(vec![1..3], "", Some(cx)).unwrap(); assert!(buffer.text() == "ac"); assert!(buffer.is_dirty()); }); @@ -3225,18 +3226,18 @@ mod tests { // When a file is deleted, the buffer is considered dirty. let events = Rc::new(RefCell::new(Vec::new())); - let file2 = app.update(|ctx| tree.file("file2", ctx)).await; - let buffer2 = app.add_model(|ctx: &mut ModelContext| { - ctx.subscribe(&ctx.handle(), { + let file2 = cx.update(|cx| tree.file("file2", cx)).await; + let buffer2 = cx.add_model(|cx: &mut ModelContext| { + cx.subscribe(&cx.handle(), { let events = events.clone(); move |_, event, _| events.borrow_mut().push(event.clone()) }); - Buffer::from_history(0, History::new("abc".into()), Some(file2), None, ctx) + Buffer::from_history(0, History::new("abc".into()), Some(file2), None, cx) }); fs::remove_file(dir.path().join("file2")).unwrap(); - buffer2.condition(&app, |b, _| b.is_dirty()).await; + buffer2.condition(&cx, |b, _| b.is_dirty()).await; assert_eq!( *events.borrow(), &[Event::Dirtied, Event::FileHandleChanged] @@ -3244,51 +3245,51 @@ mod tests { // When a file is already dirty when deleted, we don't emit a Dirtied event. let events = Rc::new(RefCell::new(Vec::new())); - let file3 = app.update(|ctx| tree.file("file3", ctx)).await; - let buffer3 = app.add_model(|ctx: &mut ModelContext| { - ctx.subscribe(&ctx.handle(), { + let file3 = cx.update(|cx| tree.file("file3", cx)).await; + let buffer3 = cx.add_model(|cx: &mut ModelContext| { + cx.subscribe(&cx.handle(), { let events = events.clone(); move |_, event, _| events.borrow_mut().push(event.clone()) }); - Buffer::from_history(0, History::new("abc".into()), Some(file3), None, ctx) + Buffer::from_history(0, History::new("abc".into()), Some(file3), None, cx) }); - tree.flush_fs_events(&app).await; - buffer3.update(&mut app, |buffer, ctx| { - buffer.edit(Some(0..0), "x", Some(ctx)).unwrap(); + tree.flush_fs_events(&cx).await; + buffer3.update(&mut cx, |buffer, cx| { + buffer.edit(Some(0..0), "x", Some(cx)).unwrap(); }); events.borrow_mut().clear(); fs::remove_file(dir.path().join("file3")).unwrap(); buffer3 - .condition(&app, |_, _| !events.borrow().is_empty()) + .condition(&cx, |_, _| !events.borrow().is_empty()) .await; assert_eq!(*events.borrow(), &[Event::FileHandleChanged]); - app.read(|ctx| assert!(buffer3.read(ctx).is_dirty())); + cx.read(|cx| assert!(buffer3.read(cx).is_dirty())); }); } #[gpui::test] - async fn test_file_changes_on_disk(mut app: gpui::TestAppContext) { + async fn test_file_changes_on_disk(mut cx: gpui::TestAppContext) { let initial_contents = "aaa\nbbbbb\nc\n"; let dir = temp_tree(json!({ "the-file": initial_contents })); - let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx)); - app.read(|ctx| tree.read(ctx).scan_complete()).await; + let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx)); + cx.read(|cx| tree.read(cx).scan_complete()).await; let abs_path = dir.path().join("the-file"); - let file = app.update(|ctx| tree.file("the-file", ctx)).await; - let buffer = app.add_model(|ctx| { + let file = cx.update(|cx| tree.file("the-file", cx)).await; + let buffer = cx.add_model(|cx| { Buffer::from_history( 0, History::new(initial_contents.into()), Some(file), None, - ctx, + cx, ) }); // Add a cursor at the start of each row. - let (selection_set_id, _) = buffer.update(&mut app, |buffer, ctx| { + let (selection_set_id, _) = buffer.update(&mut cx, |buffer, cx| { assert!(!buffer.is_dirty()); buffer.add_selection_set( (0..3) @@ -3303,13 +3304,13 @@ mod tests { } }) .collect::>(), - Some(ctx), + Some(cx), ) }); // Change the file on disk, adding two new lines of text, and removing // one line. - buffer.read_with(&app, |buffer, _| { + buffer.read_with(&cx, |buffer, _| { assert!(!buffer.is_dirty()); assert!(!buffer.has_conflict()); }); @@ -3320,10 +3321,10 @@ mod tests { // contents are edited according to the diff between the old and new // file contents. buffer - .condition(&app, |buffer, _| buffer.text() != initial_contents) + .condition(&cx, |buffer, _| buffer.text() != initial_contents) .await; - buffer.update(&mut app, |buffer, _| { + buffer.update(&mut cx, |buffer, _| { assert_eq!(buffer.text(), new_contents); assert!(!buffer.is_dirty()); assert!(!buffer.has_conflict()); @@ -3343,8 +3344,8 @@ mod tests { }); // Modify the buffer - buffer.update(&mut app, |buffer, ctx| { - buffer.edit(vec![0..0], " ", Some(ctx)).unwrap(); + buffer.update(&mut cx, |buffer, cx| { + buffer.edit(vec![0..0], " ", Some(cx)).unwrap(); assert!(buffer.is_dirty()); }); @@ -3354,34 +3355,30 @@ mod tests { // Becaues the buffer is modified, it doesn't reload from disk, but is // marked as having a conflict. buffer - .condition(&app, |buffer, _| buffer.has_conflict()) + .condition(&cx, |buffer, _| buffer.has_conflict()) .await; } #[gpui::test] - async fn test_set_text_via_diff(mut app: gpui::TestAppContext) { + async fn test_set_text_via_diff(mut cx: gpui::TestAppContext) { let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n"; - let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); let text = "a\nccc\ndddd\nffffff\n"; - let diff = buffer - .read_with(&app, |b, ctx| b.diff(text.into(), ctx)) - .await; - buffer.update(&mut app, |b, ctx| b.set_text_via_diff(diff, ctx)); - app.read(|ctx| assert_eq!(buffer.read(ctx).text(), text)); + let diff = buffer.read_with(&cx, |b, cx| b.diff(text.into(), cx)).await; + buffer.update(&mut cx, |b, cx| b.set_text_via_diff(diff, cx)); + cx.read(|cx| assert_eq!(buffer.read(cx).text(), text)); let text = "a\n1\n\nccc\ndd2dd\nffffff\n"; - let diff = buffer - .read_with(&app, |b, ctx| b.diff(text.into(), ctx)) - .await; - buffer.update(&mut app, |b, ctx| b.set_text_via_diff(diff, ctx)); - app.read(|ctx| assert_eq!(buffer.read(ctx).text(), text)); + let diff = buffer.read_with(&cx, |b, cx| b.diff(text.into(), cx)).await; + buffer.update(&mut cx, |b, cx| b.set_text_via_diff(diff, cx)); + cx.read(|cx| assert_eq!(buffer.read(cx).text(), text)); } #[gpui::test] - fn test_undo_redo(app: &mut gpui::MutableAppContext) { - app.add_model(|ctx| { - let mut buffer = Buffer::new(0, "1234", ctx); + fn test_undo_redo(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { + let mut buffer = Buffer::new(0, "1234", cx); let edit1 = buffer.edit(vec![1..1], "abx", None).unwrap(); let edit2 = buffer.edit(vec![3..4], "yzef", None).unwrap(); @@ -3414,10 +3411,10 @@ mod tests { } #[gpui::test] - fn test_history(app: &mut gpui::MutableAppContext) { - app.add_model(|ctx| { + fn test_history(cx: &mut gpui::MutableAppContext) { + cx.add_model(|cx| { let mut now = Instant::now(); - let mut buffer = Buffer::new(0, "123456", ctx); + let mut buffer = Buffer::new(0, "123456", cx); let (set_id, _) = buffer.add_selection_set(buffer.selections_from_ranges(vec![4..4]).unwrap(), None); @@ -3482,7 +3479,7 @@ mod tests { } #[gpui::test] - fn test_random_concurrent_edits(ctx: &mut gpui::MutableAppContext) { + fn test_random_concurrent_edits(cx: &mut gpui::MutableAppContext) { use crate::test::Network; const PEERS: usize = 5; @@ -3499,8 +3496,7 @@ mod tests { let mut buffers = Vec::new(); let mut network = Network::new(); for i in 0..PEERS { - let buffer = - ctx.add_model(|ctx| Buffer::new(i as ReplicaId, base_text.as_str(), ctx)); + let buffer = cx.add_model(|cx| Buffer::new(i as ReplicaId, base_text.as_str(), cx)); buffers.push(buffer); replica_ids.push(i as u16); network.add_peer(i as u16); @@ -3510,7 +3506,7 @@ mod tests { loop { let replica_index = rng.gen_range(0..PEERS); let replica_id = replica_ids[replica_index]; - buffers[replica_index].update(ctx, |buffer, _| match rng.gen_range(0..=100) { + buffers[replica_index].update(cx, |buffer, _| match rng.gen_range(0..=100) { 0..=50 if mutation_count != 0 => { let (_, _, ops) = buffer.randomly_mutate(&mut rng, None); network.broadcast(replica_id, ops, &mut rng); @@ -3534,9 +3530,9 @@ mod tests { } } - let first_buffer = buffers[0].read(ctx); + let first_buffer = buffers[0].read(cx); for buffer in &buffers[1..] { - let buffer = buffer.read(ctx); + let buffer = buffer.read(cx); assert_eq!(buffer.text(), first_buffer.text()); assert_eq!( buffer.all_selections().collect::>(), @@ -3553,14 +3549,14 @@ mod tests { } #[gpui::test] - async fn test_reparse(mut ctx: gpui::TestAppContext) { - let app_state = ctx.read(build_app_state); + async fn test_reparse(mut cx: gpui::TestAppContext) { + let app_state = cx.read(build_app_state); let rust_lang = app_state.language_registry.select_language("test.rs"); assert!(rust_lang.is_some()); - let buffer = ctx.add_model(|ctx| { + let buffer = cx.add_model(|cx| { let text = "fn a() {}".into(); - let buffer = Buffer::from_history(0, History::new(text), None, rust_lang.cloned(), ctx); + let buffer = Buffer::from_history(0, History::new(text), None, rust_lang.cloned(), cx); assert!(buffer.is_parsing()); assert!(buffer.syntax_tree().is_none()); buffer @@ -3568,10 +3564,10 @@ mod tests { // Wait for the initial text to parse buffer - .condition(&ctx, |buffer, _| !buffer.is_parsing()) + .condition(&cx, |buffer, _| !buffer.is_parsing()) .await; assert_eq!( - get_tree_sexp(&buffer, &ctx), + get_tree_sexp(&buffer, &cx), concat!( "(source_file (function_item name: (identifier) ", "parameters: (parameters) ", @@ -3581,26 +3577,26 @@ mod tests { // Perform some edits (add parameter and variable reference) // Parsing doesn't begin until the transaction is complete - buffer.update(&mut ctx, |buf, ctx| { + buffer.update(&mut cx, |buf, cx| { buf.start_transaction(None).unwrap(); let offset = buf.text().find(")").unwrap(); - buf.edit(vec![offset..offset], "b: C", Some(ctx)).unwrap(); + buf.edit(vec![offset..offset], "b: C", Some(cx)).unwrap(); assert!(!buf.is_parsing()); let offset = buf.text().find("}").unwrap(); - buf.edit(vec![offset..offset], " d; ", Some(ctx)).unwrap(); + buf.edit(vec![offset..offset], " d; ", Some(cx)).unwrap(); assert!(!buf.is_parsing()); - buf.end_transaction(None, Some(ctx)).unwrap(); + buf.end_transaction(None, Some(cx)).unwrap(); assert_eq!(buf.text(), "fn a(b: C) { d; }"); assert!(buf.is_parsing()); }); buffer - .condition(&ctx, |buffer, _| !buffer.is_parsing()) + .condition(&cx, |buffer, _| !buffer.is_parsing()) .await; assert_eq!( - get_tree_sexp(&buffer, &ctx), + get_tree_sexp(&buffer, &cx), concat!( "(source_file (function_item name: (identifier) ", "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ", @@ -3612,29 +3608,29 @@ mod tests { // * turn identifier into a field expression // * turn field expression into a method call // * add a turbofish to the method call - buffer.update(&mut ctx, |buf, ctx| { + buffer.update(&mut cx, |buf, cx| { let offset = buf.text().find(";").unwrap(); - buf.edit(vec![offset..offset], ".e", Some(ctx)).unwrap(); + buf.edit(vec![offset..offset], ".e", Some(cx)).unwrap(); assert_eq!(buf.text(), "fn a(b: C) { d.e; }"); assert!(buf.is_parsing()); }); - buffer.update(&mut ctx, |buf, ctx| { + buffer.update(&mut cx, |buf, cx| { let offset = buf.text().find(";").unwrap(); - buf.edit(vec![offset..offset], "(f)", Some(ctx)).unwrap(); + buf.edit(vec![offset..offset], "(f)", Some(cx)).unwrap(); assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }"); assert!(buf.is_parsing()); }); - buffer.update(&mut ctx, |buf, ctx| { + buffer.update(&mut cx, |buf, cx| { let offset = buf.text().find("(f)").unwrap(); - buf.edit(vec![offset..offset], "::", Some(ctx)).unwrap(); + buf.edit(vec![offset..offset], "::", Some(cx)).unwrap(); assert_eq!(buf.text(), "fn a(b: C) { d.e::(f); }"); assert!(buf.is_parsing()); }); buffer - .condition(&ctx, |buffer, _| !buffer.is_parsing()) + .condition(&cx, |buffer, _| !buffer.is_parsing()) .await; assert_eq!( - get_tree_sexp(&buffer, &ctx), + get_tree_sexp(&buffer, &cx), concat!( "(source_file (function_item name: (identifier) ", "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ", @@ -3646,16 +3642,16 @@ mod tests { ) ); - buffer.update(&mut ctx, |buf, ctx| { - buf.undo(Some(ctx)); + buffer.update(&mut cx, |buf, cx| { + buf.undo(Some(cx)); assert_eq!(buf.text(), "fn a() {}"); assert!(buf.is_parsing()); }); buffer - .condition(&ctx, |buffer, _| !buffer.is_parsing()) + .condition(&cx, |buffer, _| !buffer.is_parsing()) .await; assert_eq!( - get_tree_sexp(&buffer, &ctx), + get_tree_sexp(&buffer, &cx), concat!( "(source_file (function_item name: (identifier) ", "parameters: (parameters) ", @@ -3663,16 +3659,16 @@ mod tests { ) ); - buffer.update(&mut ctx, |buf, ctx| { - buf.redo(Some(ctx)); + buffer.update(&mut cx, |buf, cx| { + buf.redo(Some(cx)); assert_eq!(buf.text(), "fn a(b: C) { d.e::(f); }"); assert!(buf.is_parsing()); }); buffer - .condition(&ctx, |buffer, _| !buffer.is_parsing()) + .condition(&cx, |buffer, _| !buffer.is_parsing()) .await; assert_eq!( - get_tree_sexp(&buffer, &ctx), + get_tree_sexp(&buffer, &cx), concat!( "(source_file (function_item name: (identifier) ", "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ", @@ -3684,22 +3680,22 @@ mod tests { ) ); - fn get_tree_sexp(buffer: &ModelHandle, ctx: &gpui::TestAppContext) -> String { - buffer.read_with(ctx, |buffer, _| { + fn get_tree_sexp(buffer: &ModelHandle, cx: &gpui::TestAppContext) -> String { + buffer.read_with(cx, |buffer, _| { buffer.syntax_tree().unwrap().root_node().to_sexp() }) } } #[gpui::test] - async fn test_enclosing_bracket_ranges(mut ctx: gpui::TestAppContext) { + async fn test_enclosing_bracket_ranges(mut cx: gpui::TestAppContext) { use unindent::Unindent as _; - let app_state = ctx.read(build_app_state); + let app_state = cx.read(build_app_state); let rust_lang = app_state.language_registry.select_language("test.rs"); assert!(rust_lang.is_some()); - let buffer = ctx.add_model(|ctx| { + let buffer = cx.add_model(|cx| { let text = " mod x { mod y { @@ -3709,12 +3705,12 @@ mod tests { " .unindent() .into(); - Buffer::from_history(0, History::new(text), None, rust_lang.cloned(), ctx) + Buffer::from_history(0, History::new(text), None, rust_lang.cloned(), cx) }); buffer - .condition(&ctx, |buffer, _| !buffer.is_parsing()) + .condition(&cx, |buffer, _| !buffer.is_parsing()) .await; - buffer.read_with(&ctx, |buf, _| { + buffer.read_with(&cx, |buf, _| { assert_eq!( buf.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)), Some(( @@ -3750,7 +3746,7 @@ mod tests { &mut self, rng: &mut T, old_range_count: usize, - ctx: Option<&mut ModelContext>, + cx: Option<&mut ModelContext>, ) -> (Vec>, String, Vec) where T: Rng, @@ -3767,7 +3763,7 @@ mod tests { let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect(); let operations = self - .edit(old_ranges.iter().cloned(), new_text.as_str(), ctx) + .edit(old_ranges.iter().cloned(), new_text.as_str(), cx) .unwrap(); (old_ranges, new_text, operations) @@ -3776,14 +3772,14 @@ mod tests { pub fn randomly_mutate( &mut self, rng: &mut T, - mut ctx: Option<&mut ModelContext>, + mut cx: Option<&mut ModelContext>, ) -> (Vec>, String, Vec) where T: Rng, { // Randomly edit let (old_ranges, new_text, mut operations) = - self.randomly_edit(rng, 5, ctx.as_deref_mut()); + self.randomly_edit(rng, 5, cx.as_deref_mut()); // Randomly add, remove or mutate selection sets. let replica_selection_sets = &self From ca87dccf479c5824481e718e2d08d56aca7b12a3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:04:34 -0700 Subject: [PATCH 08/16] Rename context parameters to `cx` in display_map.rs --- zed/src/editor/display_map.rs | 189 +++++++++++++++++----------------- 1 file changed, 94 insertions(+), 95 deletions(-) diff --git a/zed/src/editor/display_map.rs b/zed/src/editor/display_map.rs index 4b5fcd36abe8f6b84fda783e5d6f1e580f5db730..ccb8b7c4080ca8fcb25bc2d1f7c055e4bcb3ad00 100644 --- a/zed/src/editor/display_map.rs +++ b/zed/src/editor/display_map.rs @@ -15,17 +15,17 @@ pub struct DisplayMap { } impl DisplayMap { - pub fn new(buffer: ModelHandle, tab_size: usize, ctx: &AppContext) -> Self { + pub fn new(buffer: ModelHandle, tab_size: usize, cx: &AppContext) -> Self { DisplayMap { buffer: buffer.clone(), - fold_map: FoldMap::new(buffer, ctx), + fold_map: FoldMap::new(buffer, cx), tab_size, } } - pub fn snapshot(&self, ctx: &AppContext) -> DisplayMapSnapshot { + pub fn snapshot(&self, cx: &AppContext) -> DisplayMapSnapshot { DisplayMapSnapshot { - folds_snapshot: self.fold_map.snapshot(ctx), + folds_snapshot: self.fold_map.snapshot(cx), tab_size: self.tab_size, } } @@ -33,46 +33,46 @@ impl DisplayMap { pub fn folds_in_range<'a, T>( &'a self, range: Range, - app: &'a AppContext, + cx: &'a AppContext, ) -> impl Iterator> where T: ToOffset, { - self.fold_map.folds_in_range(range, app) + self.fold_map.folds_in_range(range, cx) } pub fn fold( &mut self, ranges: impl IntoIterator>, - ctx: &AppContext, + cx: &AppContext, ) { - self.fold_map.fold(ranges, ctx) + self.fold_map.fold(ranges, cx) } pub fn unfold( &mut self, ranges: impl IntoIterator>, - ctx: &AppContext, + cx: &AppContext, ) { - self.fold_map.unfold(ranges, ctx) + self.fold_map.unfold(ranges, cx) } - pub fn intersects_fold(&self, offset: T, ctx: &AppContext) -> bool { - self.fold_map.intersects_fold(offset, ctx) + pub fn intersects_fold(&self, offset: T, cx: &AppContext) -> bool { + self.fold_map.intersects_fold(offset, cx) } - pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool { - self.fold_map.is_line_folded(display_row, ctx) + pub fn is_line_folded(&self, display_row: u32, cx: &AppContext) -> bool { + self.fold_map.is_line_folded(display_row, cx) } - pub fn text(&self, ctx: &AppContext) -> String { - self.snapshot(ctx).chunks_at(DisplayPoint::zero()).collect() + pub fn text(&self, cx: &AppContext) -> String { + self.snapshot(cx).chunks_at(DisplayPoint::zero()).collect() } - pub fn line(&self, display_row: u32, ctx: &AppContext) -> String { + pub fn line(&self, display_row: u32, cx: &AppContext) -> String { let mut result = String::new(); for chunk in self - .snapshot(ctx) + .snapshot(cx) .chunks_at(DisplayPoint::new(display_row, 0)) { if let Some(ix) = chunk.find('\n') { @@ -85,11 +85,11 @@ impl DisplayMap { result } - pub fn line_indent(&self, display_row: u32, ctx: &AppContext) -> (u32, bool) { + pub fn line_indent(&self, display_row: u32, cx: &AppContext) -> (u32, bool) { let mut indent = 0; let mut is_blank = true; for c in self - .snapshot(ctx) + .snapshot(cx) .chars_at(DisplayPoint::new(display_row, 0)) { if c == ' ' { @@ -102,30 +102,30 @@ impl DisplayMap { (indent, is_blank) } - pub fn line_len(&self, row: u32, ctx: &AppContext) -> u32 { - DisplayPoint::new(row, self.fold_map.line_len(row, ctx)) - .expand_tabs(self, ctx) + pub fn line_len(&self, row: u32, cx: &AppContext) -> u32 { + DisplayPoint::new(row, self.fold_map.line_len(row, cx)) + .expand_tabs(self, cx) .column() } - pub fn max_point(&self, ctx: &AppContext) -> DisplayPoint { - self.snapshot(ctx).max_point().expand_tabs(self, ctx) + pub fn max_point(&self, cx: &AppContext) -> DisplayPoint { + self.snapshot(cx).max_point().expand_tabs(self, cx) } - pub fn longest_row(&self, ctx: &AppContext) -> u32 { - self.fold_map.longest_row(ctx) + pub fn longest_row(&self, cx: &AppContext) -> u32 { + self.fold_map.longest_row(cx) } - pub fn anchor_before(&self, point: DisplayPoint, bias: Bias, app: &AppContext) -> Anchor { + pub fn anchor_before(&self, point: DisplayPoint, bias: Bias, cx: &AppContext) -> Anchor { self.buffer - .read(app) - .anchor_before(point.to_buffer_point(self, bias, app)) + .read(cx) + .anchor_before(point.to_buffer_point(self, bias, cx)) } - pub fn anchor_after(&self, point: DisplayPoint, bias: Bias, app: &AppContext) -> Anchor { + pub fn anchor_after(&self, point: DisplayPoint, bias: Bias, cx: &AppContext) -> Anchor { self.buffer - .read(app) - .anchor_after(point.to_buffer_point(self, bias, app)) + .read(cx) + .anchor_after(point.to_buffer_point(self, bias, cx)) } } @@ -257,29 +257,29 @@ impl DisplayPoint { &mut self.0.column } - pub fn to_buffer_point(self, map: &DisplayMap, bias: Bias, ctx: &AppContext) -> Point { + pub fn to_buffer_point(self, map: &DisplayMap, bias: Bias, cx: &AppContext) -> Point { map.fold_map - .to_buffer_point(self.collapse_tabs(map, bias, ctx), ctx) + .to_buffer_point(self.collapse_tabs(map, bias, cx), cx) } - pub fn to_buffer_offset(self, map: &DisplayMap, bias: Bias, ctx: &AppContext) -> usize { + pub fn to_buffer_offset(self, map: &DisplayMap, bias: Bias, cx: &AppContext) -> usize { map.fold_map - .to_buffer_offset(self.collapse_tabs(&map, bias, ctx), ctx) + .to_buffer_offset(self.collapse_tabs(&map, bias, cx), cx) } - fn expand_tabs(self, map: &DisplayMap, ctx: &AppContext) -> Self { - map.snapshot(ctx).expand_tabs(self) + fn expand_tabs(self, map: &DisplayMap, cx: &AppContext) -> Self { + map.snapshot(cx).expand_tabs(self) } - fn collapse_tabs(self, map: &DisplayMap, bias: Bias, ctx: &AppContext) -> Self { - map.snapshot(ctx).collapse_tabs(self, bias).0 + fn collapse_tabs(self, map: &DisplayMap, bias: Bias, cx: &AppContext) -> Self { + map.snapshot(cx).collapse_tabs(self, bias).0 } } impl Point { - pub fn to_display_point(self, map: &DisplayMap, ctx: &AppContext) -> DisplayPoint { - let mut display_point = map.fold_map.to_display_point(self, ctx); - let snapshot = map.fold_map.snapshot(ctx); + pub fn to_display_point(self, map: &DisplayMap, cx: &AppContext) -> DisplayPoint { + let mut display_point = map.fold_map.to_display_point(self, cx); + let snapshot = map.fold_map.snapshot(cx); let chars = snapshot.chars_at(DisplayPoint::new(display_point.row(), 0)); *display_point.column_mut() = expand_tabs(chars, display_point.column() as usize, map.tab_size) as u32; @@ -288,9 +288,8 @@ impl Point { } impl Anchor { - pub fn to_display_point(&self, map: &DisplayMap, app: &AppContext) -> DisplayPoint { - self.to_point(map.buffer.read(app)) - .to_display_point(map, app) + pub fn to_display_point(&self, map: &DisplayMap, cx: &AppContext) -> DisplayPoint { + self.to_point(map.buffer.read(cx)).to_display_point(map, cx) } } @@ -463,12 +462,12 @@ mod tests { use std::sync::Arc; #[gpui::test] - fn test_chunks_at(app: &mut gpui::MutableAppContext) { + fn test_chunks_at(cx: &mut gpui::MutableAppContext) { let text = sample_text(6, 6); - let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); - let map = DisplayMap::new(buffer.clone(), 4, app.as_ref()); + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let map = DisplayMap::new(buffer.clone(), 4, cx.as_ref()); buffer - .update(app, |buffer, ctx| { + .update(cx, |buffer, cx| { buffer.edit( vec![ Point::new(1, 0)..Point::new(1, 0), @@ -476,25 +475,25 @@ mod tests { Point::new(2, 1)..Point::new(2, 1), ], "\t", - Some(ctx), + Some(cx), ) }) .unwrap(); assert_eq!( - &map.snapshot(app.as_ref()) + &map.snapshot(cx.as_ref()) .chunks_at(DisplayPoint::new(1, 0)) .collect::()[0..10], " b bb" ); assert_eq!( - &map.snapshot(app.as_ref()) + &map.snapshot(cx.as_ref()) .chunks_at(DisplayPoint::new(1, 2)) .collect::()[0..10], " b bbbb" ); assert_eq!( - &map.snapshot(app.as_ref()) + &map.snapshot(cx.as_ref()) .chunks_at(DisplayPoint::new(1, 6)) .collect::()[0..13], " bbbbb\nc c" @@ -502,7 +501,7 @@ mod tests { } #[gpui::test] - async fn test_highlighted_chunks_at(mut app: gpui::TestAppContext) { + async fn test_highlighted_chunks_at(mut cx: gpui::TestAppContext) { use unindent::Unindent as _; let grammar = tree_sitter_rust::language(); @@ -540,14 +539,14 @@ mod tests { }); lang.set_theme(&theme); - let buffer = app.add_model(|ctx| { - Buffer::from_history(0, History::new(text.into()), None, Some(lang), ctx) + let buffer = cx.add_model(|cx| { + Buffer::from_history(0, History::new(text.into()), None, Some(lang), cx) }); - buffer.condition(&app, |buf, _| !buf.is_parsing()).await; + buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; - let mut map = app.read(|ctx| DisplayMap::new(buffer, 2, ctx)); + let mut map = cx.read(|cx| DisplayMap::new(buffer, 2, cx)); assert_eq!( - app.read(|ctx| highlighted_chunks(0..5, &map, &theme, ctx)), + cx.read(|cx| highlighted_chunks(0..5, &map, &theme, cx)), vec![ ("fn ".to_string(), None), ("outer".to_string(), Some("fn.name")), @@ -558,7 +557,7 @@ mod tests { ] ); assert_eq!( - app.read(|ctx| highlighted_chunks(3..5, &map, &theme, ctx)), + cx.read(|cx| highlighted_chunks(3..5, &map, &theme, cx)), vec![ (" fn ".to_string(), Some("mod.body")), ("inner".to_string(), Some("fn.name")), @@ -566,9 +565,9 @@ mod tests { ] ); - app.read(|ctx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], ctx)); + cx.read(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)); assert_eq!( - app.read(|ctx| highlighted_chunks(0..2, &map, &theme, ctx)), + cx.read(|cx| highlighted_chunks(0..2, &map, &theme, cx)), vec![ ("fn ".to_string(), None), ("out".to_string(), Some("fn.name")), @@ -583,10 +582,10 @@ mod tests { rows: Range, map: &DisplayMap, theme: &'a Theme, - ctx: &AppContext, + cx: &AppContext, ) -> Vec<(String, Option<&'a str>)> { let mut chunks: Vec<(String, Option<&str>)> = Vec::new(); - for (chunk, style_id) in map.snapshot(ctx).highlighted_chunks_for_rows(rows) { + for (chunk, style_id) in map.snapshot(cx).highlighted_chunks_for_rows(rows) { let style_name = theme.syntax_style_name(style_id); if let Some((last_chunk, last_style_name)) = chunks.last_mut() { if style_name == *last_style_name { @@ -603,17 +602,17 @@ mod tests { } #[gpui::test] - fn test_clip_point(app: &mut gpui::MutableAppContext) { + fn test_clip_point(cx: &mut gpui::MutableAppContext) { use Bias::{Left, Right}; let text = "\n'a', 'α',\t'✋',\t'❎', '🍐'\n"; let display_text = "\n'a', 'α', '✋', '❎', '🍐'\n"; - let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); - let ctx = app.as_ref(); - let map = DisplayMap::new(buffer.clone(), 4, ctx); - assert_eq!(map.text(ctx), display_text); + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let cx = cx.as_ref(); + let map = DisplayMap::new(buffer.clone(), 4, cx); + assert_eq!(map.text(cx), display_text); - let map = map.snapshot(ctx); + let map = map.snapshot(cx); for (input_column, bias, output_column) in vec![ ("'a', '".len(), Left, "'a', '".len()), ("'a', '".len() + 1, Left, "'a', '".len()), @@ -648,53 +647,53 @@ mod tests { } #[gpui::test] - fn test_tabs_with_multibyte_chars(app: &mut gpui::MutableAppContext) { + fn test_tabs_with_multibyte_chars(cx: &mut gpui::MutableAppContext) { let text = "✅\t\tα\nβ\t\n🏀β\t\tγ"; - let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); - let ctx = app.as_ref(); - let map = DisplayMap::new(buffer.clone(), 4, ctx); - assert_eq!(map.text(ctx), "✅ α\nβ \n🏀β γ"); + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let cx = cx.as_ref(); + let map = DisplayMap::new(buffer.clone(), 4, cx); + assert_eq!(map.text(cx), "✅ α\nβ \n🏀β γ"); let point = Point::new(0, "✅\t\t".len() as u32); let display_point = DisplayPoint::new(0, "✅ ".len() as u32); - assert_eq!(point.to_display_point(&map, ctx), display_point); - assert_eq!(display_point.to_buffer_point(&map, Bias::Left, ctx), point,); + assert_eq!(point.to_display_point(&map, cx), display_point); + assert_eq!(display_point.to_buffer_point(&map, Bias::Left, cx), point,); let point = Point::new(1, "β\t".len() as u32); let display_point = DisplayPoint::new(1, "β ".len() as u32); - assert_eq!(point.to_display_point(&map, ctx), display_point); - assert_eq!(display_point.to_buffer_point(&map, Bias::Left, ctx), point,); + assert_eq!(point.to_display_point(&map, cx), display_point); + assert_eq!(display_point.to_buffer_point(&map, Bias::Left, cx), point,); let point = Point::new(2, "🏀β\t\t".len() as u32); let display_point = DisplayPoint::new(2, "🏀β ".len() as u32); - assert_eq!(point.to_display_point(&map, ctx), display_point); - assert_eq!(display_point.to_buffer_point(&map, Bias::Left, ctx), point,); + assert_eq!(point.to_display_point(&map, cx), display_point); + assert_eq!(display_point.to_buffer_point(&map, Bias::Left, cx), point,); // Display points inside of expanded tabs assert_eq!( - DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Right, ctx), + DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Right, cx), Point::new(0, "✅\t\t".len() as u32), ); assert_eq!( - DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Left, ctx), + DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Left, cx), Point::new(0, "✅\t".len() as u32), ); assert_eq!( - map.snapshot(ctx) + map.snapshot(cx) .chunks_at(DisplayPoint::new(0, "✅ ".len() as u32)) .collect::(), " α\nβ \n🏀β γ" ); assert_eq!( - DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Right, ctx), + DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Right, cx), Point::new(0, "✅\t".len() as u32), ); assert_eq!( - DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Left, ctx), + DisplayPoint::new(0, "✅ ".len() as u32).to_buffer_point(&map, Bias::Left, cx), Point::new(0, "✅".len() as u32), ); assert_eq!( - map.snapshot(ctx) + map.snapshot(cx) .chunks_at(DisplayPoint::new(0, "✅ ".len() as u32)) .collect::(), " α\nβ \n🏀β γ" @@ -702,21 +701,21 @@ mod tests { // Clipping display points inside of multi-byte characters assert_eq!( - map.snapshot(ctx) + map.snapshot(cx) .clip_point(DisplayPoint::new(0, "✅".len() as u32 - 1), Bias::Left), DisplayPoint::new(0, 0) ); assert_eq!( - map.snapshot(ctx) + map.snapshot(cx) .clip_point(DisplayPoint::new(0, "✅".len() as u32 - 1), Bias::Right), DisplayPoint::new(0, "✅".len() as u32) ); } #[gpui::test] - fn test_max_point(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaa\n\t\tbbb", ctx)); - let map = DisplayMap::new(buffer.clone(), 4, app.as_ref()); - assert_eq!(map.max_point(app.as_ref()), DisplayPoint::new(1, 11)) + fn test_max_point(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "aaa\n\t\tbbb", cx)); + let map = DisplayMap::new(buffer.clone(), 4, cx.as_ref()); + assert_eq!(map.max_point(cx.as_ref()), DisplayPoint::new(1, 11)) } } From 765a8d0636302739cc4edf01965711aa0b484223 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:05:46 -0700 Subject: [PATCH 09/16] Rename context parameters to `cx` in editor/element.rs --- zed/src/editor/element.rs | 165 +++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 83 deletions(-) diff --git a/zed/src/editor/element.rs b/zed/src/editor/element.rs index 5cd93cf57cf7fd0f4acbbb694c3d04d832afddaa..47080b8137846acd6e649968ea6e02bcf8b1982c 100644 --- a/zed/src/editor/element.rs +++ b/zed/src/editor/element.rs @@ -25,8 +25,8 @@ impl EditorElement { Self { view } } - fn view<'a>(&self, ctx: &'a AppContext) -> &'a Editor { - self.view.upgrade(ctx).unwrap().read(ctx) + fn view<'a>(&self, cx: &'a AppContext) -> &'a Editor { + self.view.upgrade(cx).unwrap().read(cx) } fn mouse_down( @@ -35,22 +35,21 @@ impl EditorElement { cmd: bool, layout: &mut LayoutState, paint: &mut PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { if paint.text_bounds.contains_point(position) { - let view = self.view(ctx.app); - let position = - paint.point_for_position(view, layout, position, ctx.font_cache, ctx.app); - ctx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd }); + let view = self.view(cx.app); + let position = paint.point_for_position(view, layout, position, cx.font_cache, cx.app); + cx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd }); true } else { false } } - fn mouse_up(&self, _position: Vector2F, ctx: &mut EventContext) -> bool { - if self.view(ctx.app).is_selecting() { - ctx.dispatch_action("buffer:select", SelectAction::End); + fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool { + if self.view(cx.app).is_selecting() { + cx.dispatch_action("buffer:select", SelectAction::End); true } else { false @@ -62,15 +61,15 @@ impl EditorElement { position: Vector2F, layout: &mut LayoutState, paint: &mut PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - let view = self.view(ctx.app); + let view = self.view(cx.app); if view.is_selecting() { let rect = paint.text_bounds; let mut scroll_delta = Vector2F::zero(); - let vertical_margin = view.line_height(ctx.font_cache).min(rect.height() / 3.0); + let vertical_margin = view.line_height(cx.font_cache).min(rect.height() / 3.0); let top = rect.origin_y() + vertical_margin; let bottom = rect.lower_left().y() - vertical_margin; if position.y() < top { @@ -80,7 +79,7 @@ impl EditorElement { scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom)) } - let horizontal_margin = view.line_height(ctx.font_cache).min(rect.width() / 3.0); + let horizontal_margin = view.line_height(cx.font_cache).min(rect.width() / 3.0); let left = rect.origin_x() + horizontal_margin; let right = rect.upper_right().x() - horizontal_margin; if position.x() < left { @@ -94,19 +93,19 @@ impl EditorElement { )) } - ctx.dispatch_action( + cx.dispatch_action( "buffer:select", SelectAction::Update { position: paint.point_for_position( view, layout, position, - ctx.font_cache, - ctx.app, + cx.font_cache, + cx.app, ), scroll_position: (view.scroll_position() + scroll_delta).clamp( Vector2F::zero(), - layout.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, ctx.app), + layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app), ), }, ); @@ -116,17 +115,17 @@ impl EditorElement { } } - fn key_down(&self, chars: &str, ctx: &mut EventContext) -> bool { - let view = self.view.upgrade(ctx.app).unwrap(); + fn key_down(&self, chars: &str, cx: &mut EventContext) -> bool { + let view = self.view.upgrade(cx.app).unwrap(); - if view.is_focused(ctx.app) { + if view.is_focused(cx.app) { if chars.is_empty() { false } else { if chars.chars().any(|c| c.is_control()) { false } else { - ctx.dispatch_action("buffer:insert", chars.to_string()); + cx.dispatch_action("buffer:insert", chars.to_string()); true } } @@ -142,15 +141,15 @@ impl EditorElement { precise: bool, layout: &mut LayoutState, paint: &mut PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { if !paint.bounds.contains_point(position) { return false; } - let view = self.view(ctx.app); - let font_cache = &ctx.font_cache; - let layout_cache = &ctx.text_layout_cache; + let view = self.view(cx.app); + let font_cache = &cx.font_cache; + let layout_cache = &cx.text_layout_cache; let max_glyph_width = view.em_width(font_cache); let line_height = view.line_height(font_cache); if !precise { @@ -161,21 +160,21 @@ impl EditorElement { let y = (view.scroll_position().y() * line_height - delta.y()) / line_height; let scroll_position = vec2f(x, y).clamp( Vector2F::zero(), - layout.scroll_max(view, font_cache, layout_cache, ctx.app), + layout.scroll_max(view, font_cache, layout_cache, cx.app), ); - ctx.dispatch_action("buffer:scroll", scroll_position); + cx.dispatch_action("buffer:scroll", scroll_position); true } - fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, ctx: &mut PaintContext) { - let view = self.view(ctx.app); - let line_height = view.line_height(ctx.font_cache); + fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, cx: &mut PaintContext) { + let view = self.view(cx.app); + let line_height = view.line_height(cx.font_cache); let scroll_top = view.scroll_position().y() * line_height; - ctx.scene.push_layer(Some(rect)); - ctx.scene.push_quad(Quad { + cx.scene.push_layer(Some(rect)); + cx.scene.push_quad(Quad { bounds: rect, background: Some(ColorU::white()), border: Border::new(0., ColorU::transparent_black()), @@ -191,25 +190,25 @@ impl EditorElement { line.paint( line_origin, RectF::new(vec2f(0., 0.), vec2f(line.width(), line_height)), - ctx, + cx, ); } - ctx.scene.pop_layer(); + cx.scene.pop_layer(); } - fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, ctx: &mut PaintContext) { - let view = self.view(ctx.app); - let line_height = view.line_height(ctx.font_cache); - let descent = view.font_descent(ctx.font_cache); + fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) { + let view = self.view(cx.app); + let line_height = view.line_height(cx.font_cache); + let descent = view.font_descent(cx.font_cache); let start_row = view.scroll_position().y() as u32; let scroll_top = view.scroll_position().y() * line_height; let end_row = ((scroll_top + bounds.height()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen - let max_glyph_width = view.em_width(ctx.font_cache); + let max_glyph_width = view.em_width(cx.font_cache); let scroll_left = view.scroll_position().x() * max_glyph_width; - ctx.scene.push_layer(Some(bounds)); - ctx.scene.push_quad(Quad { + cx.scene.push_layer(Some(bounds)); + cx.scene.push_quad(Quad { bounds, background: Some(ColorU::white()), border: Border::new(0., ColorU::transparent_black()), @@ -224,7 +223,7 @@ impl EditorElement { for selection in view.selections_in_range( DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0), - ctx.app, + cx.app, ) { if selection.start != selection.end { let range_start = cmp::min(selection.start, selection.end); @@ -263,7 +262,7 @@ impl EditorElement { .collect(), }; - selection.paint(bounds, ctx.scene); + selection.paint(bounds, cx.scene); } if view.cursors_visible() { @@ -288,17 +287,17 @@ impl EditorElement { line.paint( content_origin + vec2f(-scroll_left, row as f32 * line_height - scroll_top), RectF::new(vec2f(scroll_left, 0.), vec2f(bounds.width(), line_height)), - ctx, + cx, ); } - ctx.scene.push_layer(Some(bounds)); + cx.scene.push_layer(Some(bounds)); for cursor in cursors { - cursor.paint(ctx); + cursor.paint(cx); } - ctx.scene.pop_layer(); + cx.scene.pop_layer(); - ctx.scene.pop_layer(); + cx.scene.pop_layer(); } } @@ -309,28 +308,28 @@ impl Element for EditorElement { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - let app = ctx.app; + let app = cx.app; let mut size = constraint.max; if size.y().is_infinite() { let view = self.view(app); - size.set_y((view.max_point(app).row() + 1) as f32 * view.line_height(ctx.font_cache)); + size.set_y((view.max_point(app).row() + 1) as f32 * view.line_height(cx.font_cache)); } if size.x().is_infinite() { unimplemented!("we don't yet handle an infinite width constraint on buffer elements"); } let view = self.view(app); - let font_cache = &ctx.font_cache; - let layout_cache = &ctx.text_layout_cache; + let font_cache = &cx.font_cache; + let layout_cache = &cx.text_layout_cache; let line_height = view.line_height(font_cache); let gutter_padding; let gutter_width; if view.is_gutter_visible() { - gutter_padding = view.em_width(ctx.font_cache); - match view.max_line_number_width(ctx.font_cache, ctx.text_layout_cache, app) { + gutter_padding = view.em_width(cx.font_cache); + match view.max_line_number_width(cx.font_cache, cx.text_layout_cache, app) { Err(error) => { log::error!("error computing max line number width: {}", error); return (size, None); @@ -348,7 +347,7 @@ impl Element for EditorElement { let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, app); let line_number_layouts = if view.is_gutter_visible() { - match view.layout_line_numbers(size.y(), ctx.font_cache, ctx.text_layout_cache, app) { + match view.layout_line_numbers(size.y(), cx.font_cache, cx.text_layout_cache, app) { Err(error) => { log::error!("error laying out line numbers: {}", error); return (size, None); @@ -400,15 +399,15 @@ impl Element for EditorElement { &mut self, _: Vector2F, layout: &mut Option, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { if let Some(layout) = layout { - let app = ctx.app.as_ref(); + let app = cx.app.as_ref(); let view = self.view(app); view.clamp_scroll_left( layout - .scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app) + .scroll_max(view, cx.font_cache, cx.text_layout_cache, app) .x(), ); @@ -416,8 +415,8 @@ impl Element for EditorElement { view.autoscroll_horizontally( view.scroll_position().y() as u32, layout.text_size.x(), - layout.scroll_width(view, ctx.font_cache, ctx.text_layout_cache, app), - view.em_width(ctx.font_cache), + layout.scroll_width(view, cx.font_cache, cx.text_layout_cache, app), + view.em_width(cx.font_cache), &layout.line_layouts, app, ); @@ -429,7 +428,7 @@ impl Element for EditorElement { &mut self, bounds: RectF, layout: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { if let Some(layout) = layout { let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size); @@ -438,10 +437,10 @@ impl Element for EditorElement { layout.text_size, ); - if self.view(ctx.app).is_gutter_visible() { - self.paint_gutter(gutter_bounds, layout, ctx); + if self.view(cx.app).is_gutter_visible() { + self.paint_gutter(gutter_bounds, layout, cx); } - self.paint_text(text_bounds, layout, ctx); + self.paint_text(text_bounds, layout, cx); Some(PaintState { bounds, @@ -458,23 +457,23 @@ impl Element for EditorElement { _: RectF, layout: &mut Self::LayoutState, paint: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { if let (Some(layout), Some(paint)) = (layout, paint) { match event { Event::LeftMouseDown { position, cmd } => { - self.mouse_down(*position, *cmd, layout, paint, ctx) + self.mouse_down(*position, *cmd, layout, paint, cx) } - Event::LeftMouseUp { position } => self.mouse_up(*position, ctx), + Event::LeftMouseUp { position } => self.mouse_up(*position, cx), Event::LeftMouseDragged { position } => { - self.mouse_dragged(*position, layout, paint, ctx) + self.mouse_dragged(*position, layout, paint, cx) } Event::ScrollWheel { position, delta, precise, - } => self.scroll(*position, *delta, *precise, layout, paint, ctx), - Event::KeyDown { chars, .. } => self.key_down(chars, ctx), + } => self.scroll(*position, *delta, *precise, layout, paint, cx), + Event::KeyDown { chars, .. } => self.key_down(chars, cx), _ => false, } } else { @@ -513,11 +512,11 @@ impl LayoutState { view: &Editor, font_cache: &FontCache, layout_cache: &TextLayoutCache, - app: &AppContext, + cx: &AppContext, ) -> f32 { - let row = view.longest_row(app); + let row = view.longest_row(cx); let longest_line_width = view - .layout_line(row, font_cache, layout_cache, app) + .layout_line(row, font_cache, layout_cache, cx) .unwrap() .width(); longest_line_width.max(self.max_visible_line_width) + view.em_width(font_cache) @@ -528,13 +527,13 @@ impl LayoutState { view: &Editor, font_cache: &FontCache, layout_cache: &TextLayoutCache, - app: &AppContext, + cx: &AppContext, ) -> Vector2F { vec2f( - ((self.scroll_width(view, font_cache, layout_cache, app) - self.text_size.x()) + ((self.scroll_width(view, font_cache, layout_cache, cx) - self.text_size.x()) / view.em_width(font_cache)) .max(0.0), - view.max_point(app).row().saturating_sub(1) as f32, + view.max_point(cx).row().saturating_sub(1) as f32, ) } } @@ -551,20 +550,20 @@ impl PaintState { layout: &LayoutState, position: Vector2F, font_cache: &FontCache, - app: &AppContext, + cx: &AppContext, ) -> DisplayPoint { let scroll_position = view.scroll_position(); let position = position - self.text_bounds.origin(); let y = position.y().max(0.0).min(layout.size.y()); let row = ((y / view.line_height(font_cache)) + scroll_position.y()) as u32; - let row = cmp::min(row, view.max_point(app).row()); + let row = cmp::min(row, view.max_point(cx).row()); let line = &layout.line_layouts[(row - scroll_position.y() as u32) as usize]; let x = position.x() + (scroll_position.x() * view.em_width(font_cache)); let column = if x >= 0.0 { line.index_for_x(x) .map(|ix| ix as u32) - .unwrap_or(view.line_len(row, app)) + .unwrap_or(view.line_len(row, cx)) } else { 0 }; @@ -579,8 +578,8 @@ struct Cursor { } impl Cursor { - fn paint(&self, ctx: &mut PaintContext) { - ctx.scene.push_quad(Quad { + fn paint(&self, cx: &mut PaintContext) { + cx.scene.push_quad(Quad { bounds: RectF::new(self.origin, vec2f(2.0, self.line_height)), background: Some(ColorU::black()), border: Border::new(0., ColorU::black()), From 71489251f459255c5133bc584ea10636a6f24712 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:06:32 -0700 Subject: [PATCH 10/16] Rename context parameters to `cx` in movement.rs --- zed/src/editor/movement.rs | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/zed/src/editor/movement.rs b/zed/src/editor/movement.rs index f7e89776ecf1d3fd24dc90e03b689ea5f63de22f..d7af40858b91edc86827b863dca9810dc00861d9 100644 --- a/zed/src/editor/movement.rs +++ b/zed/src/editor/movement.rs @@ -2,34 +2,34 @@ use super::{Bias, DisplayMap, DisplayPoint, SelectionGoal}; use anyhow::Result; use gpui::AppContext; -pub fn left(map: &DisplayMap, mut point: DisplayPoint, app: &AppContext) -> Result { +pub fn left(map: &DisplayMap, mut point: DisplayPoint, cx: &AppContext) -> Result { if point.column() > 0 { *point.column_mut() -= 1; } else if point.row() > 0 { *point.row_mut() -= 1; - *point.column_mut() = map.line_len(point.row(), app); + *point.column_mut() = map.line_len(point.row(), cx); } - Ok(map.snapshot(app).clip_point(point, Bias::Left)) + Ok(map.snapshot(cx).clip_point(point, Bias::Left)) } -pub fn right(map: &DisplayMap, mut point: DisplayPoint, app: &AppContext) -> Result { - let max_column = map.line_len(point.row(), app); +pub fn right(map: &DisplayMap, mut point: DisplayPoint, cx: &AppContext) -> Result { + let max_column = map.line_len(point.row(), cx); if point.column() < max_column { *point.column_mut() += 1; - } else if point.row() < map.max_point(app).row() { + } else if point.row() < map.max_point(cx).row() { *point.row_mut() += 1; *point.column_mut() = 0; } - Ok(map.snapshot(app).clip_point(point, Bias::Right)) + Ok(map.snapshot(cx).clip_point(point, Bias::Right)) } pub fn up( map: &DisplayMap, mut point: DisplayPoint, goal: SelectionGoal, - app: &AppContext, + cx: &AppContext, ) -> Result<(DisplayPoint, SelectionGoal)> { - let map = map.snapshot(app); + let map = map.snapshot(cx); let goal_column = if let SelectionGoal::Column(column) = goal { column } else { @@ -50,10 +50,10 @@ pub fn down( map: &DisplayMap, mut point: DisplayPoint, goal: SelectionGoal, - app: &AppContext, + cx: &AppContext, ) -> Result<(DisplayPoint, SelectionGoal)> { - let max_point = map.max_point(app); - let map = map.snapshot(app); + let max_point = map.max_point(cx); + let map = map.snapshot(cx); let goal_column = if let SelectionGoal::Column(column) = goal { column } else { @@ -74,9 +74,9 @@ pub fn line_beginning( map: &DisplayMap, point: DisplayPoint, toggle_indent: bool, - app: &AppContext, + cx: &AppContext, ) -> Result { - let (indent, is_blank) = map.line_indent(point.row(), app); + let (indent, is_blank) = map.line_indent(point.row(), cx); if toggle_indent && !is_blank && point.column() != indent { Ok(DisplayPoint::new(point.row(), indent)) } else { @@ -84,30 +84,30 @@ pub fn line_beginning( } } -pub fn line_end(map: &DisplayMap, point: DisplayPoint, app: &AppContext) -> Result { +pub fn line_end(map: &DisplayMap, point: DisplayPoint, cx: &AppContext) -> Result { Ok(DisplayPoint::new( point.row(), - map.line_len(point.row(), app), + map.line_len(point.row(), cx), )) } pub fn prev_word_boundary( map: &DisplayMap, point: DisplayPoint, - app: &AppContext, + cx: &AppContext, ) -> Result { if point.column() == 0 { if point.row() == 0 { Ok(DisplayPoint::new(0, 0)) } else { let row = point.row() - 1; - Ok(DisplayPoint::new(row, map.line_len(row, app))) + Ok(DisplayPoint::new(row, map.line_len(row, cx))) } } else { let mut boundary = DisplayPoint::new(point.row(), 0); let mut column = 0; let mut prev_c = None; - for c in map.snapshot(app).chars_at(boundary) { + for c in map.snapshot(cx).chars_at(boundary) { if column >= point.column() { break; } @@ -126,10 +126,10 @@ pub fn prev_word_boundary( pub fn next_word_boundary( map: &DisplayMap, mut point: DisplayPoint, - app: &AppContext, + cx: &AppContext, ) -> Result { let mut prev_c = None; - for c in map.snapshot(app).chars_at(point) { + for c in map.snapshot(cx).chars_at(point) { if prev_c.is_some() && (c == '\n' || char_kind(prev_c.unwrap()) != char_kind(c)) { break; } From a4aba3f2c37e4342bb8fb18f9396442d868cdaf6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:06:58 -0700 Subject: [PATCH 11/16] Rename context parameters to `cx` in selection.rs --- zed/src/editor/buffer/selection.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/zed/src/editor/buffer/selection.rs b/zed/src/editor/buffer/selection.rs index 2064b84cca4d9b57d18509fc431e65fb93933299..f0251fad1e18be4e9c55bd65e0c9106ff5d54746 100644 --- a/zed/src/editor/buffer/selection.rs +++ b/zed/src/editor/buffer/selection.rs @@ -81,9 +81,9 @@ impl Selection { } } - pub fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range { - let start = self.start.to_display_point(map, app); - let end = self.end.to_display_point(map, app); + pub fn display_range(&self, map: &DisplayMap, cx: &AppContext) -> Range { + let start = self.start.to_display_point(map, cx); + let end = self.end.to_display_point(map, cx); if self.reversed { end..start } else { @@ -95,22 +95,22 @@ impl Selection { &self, include_end_if_at_line_start: bool, map: &DisplayMap, - ctx: &AppContext, + cx: &AppContext, ) -> (Range, Range) { - let display_start = self.start.to_display_point(map, ctx); + let display_start = self.start.to_display_point(map, cx); let buffer_start = - DisplayPoint::new(display_start.row(), 0).to_buffer_point(map, Bias::Left, ctx); + DisplayPoint::new(display_start.row(), 0).to_buffer_point(map, Bias::Left, cx); - let mut display_end = self.end.to_display_point(map, ctx); + let mut display_end = self.end.to_display_point(map, cx); if !include_end_if_at_line_start - && display_end.row() != map.max_point(ctx).row() + && display_end.row() != map.max_point(cx).row() && display_start.row() != display_end.row() && display_end.column() == 0 { *display_end.row_mut() -= 1; } - let buffer_end = DisplayPoint::new(display_end.row(), map.line_len(display_end.row(), ctx)) - .to_buffer_point(map, Bias::Left, ctx); + let buffer_end = DisplayPoint::new(display_end.row(), map.line_len(display_end.row(), cx)) + .to_buffer_point(map, Bias::Left, cx); ( buffer_start.row..buffer_end.row + 1, From 16c6400145b66c6f913eda3d10b2851f313ba132 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:08:01 -0700 Subject: [PATCH 12/16] Rename context parameters to `cx` in fold_map.rs --- zed/src/editor/display_map/fold_map.rs | 290 ++++++++++++------------- 1 file changed, 143 insertions(+), 147 deletions(-) diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 3f8c8be58045e2f98197921ddde4efcbc675511d..6fc3c7175beb92626312209897e8c505cd0a4e20 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -23,8 +23,8 @@ pub struct FoldMap { } impl FoldMap { - pub fn new(buffer_handle: ModelHandle, ctx: &AppContext) -> Self { - let buffer = buffer_handle.read(ctx); + pub fn new(buffer_handle: ModelHandle, cx: &AppContext) -> Self { + let buffer = buffer_handle.read(cx); let text_summary = buffer.text_summary(); Self { buffer: buffer_handle, @@ -43,56 +43,56 @@ impl FoldMap { } } - pub fn snapshot(&self, ctx: &AppContext) -> FoldMapSnapshot { + pub fn snapshot(&self, cx: &AppContext) -> FoldMapSnapshot { FoldMapSnapshot { - transforms: self.sync(ctx).clone(), - buffer: self.buffer.read(ctx).snapshot(), + transforms: self.sync(cx).clone(), + buffer: self.buffer.read(cx).snapshot(), } } - pub fn len(&self, ctx: &AppContext) -> usize { - self.sync(ctx).summary().display.bytes + pub fn len(&self, cx: &AppContext) -> usize { + self.sync(cx).summary().display.bytes } - pub fn line_len(&self, row: u32, ctx: &AppContext) -> u32 { - let line_start = self.to_display_offset(DisplayPoint::new(row, 0), ctx).0; - let line_end = if row >= self.max_point(ctx).row() { - self.len(ctx) + pub fn line_len(&self, row: u32, cx: &AppContext) -> u32 { + let line_start = self.to_display_offset(DisplayPoint::new(row, 0), cx).0; + let line_end = if row >= self.max_point(cx).row() { + self.len(cx) } else { - self.to_display_offset(DisplayPoint::new(row + 1, 0), ctx).0 - 1 + self.to_display_offset(DisplayPoint::new(row + 1, 0), cx).0 - 1 }; (line_end - line_start) as u32 } - pub fn max_point(&self, ctx: &AppContext) -> DisplayPoint { - DisplayPoint(self.sync(ctx).summary().display.lines) + pub fn max_point(&self, cx: &AppContext) -> DisplayPoint { + DisplayPoint(self.sync(cx).summary().display.lines) } - pub fn longest_row(&self, ctx: &AppContext) -> u32 { - self.sync(ctx).summary().display.longest_row + pub fn longest_row(&self, cx: &AppContext) -> u32 { + self.sync(cx).summary().display.longest_row } pub fn folds_in_range<'a, T>( &'a self, range: Range, - ctx: &'a AppContext, + cx: &'a AppContext, ) -> impl Iterator> where T: ToOffset, { - self.intersecting_folds(range, ctx).map(|f| &f.0) + self.intersecting_folds(range, cx).map(|f| &f.0) } pub fn fold( &mut self, ranges: impl IntoIterator>, - ctx: &AppContext, + cx: &AppContext, ) { - let _ = self.sync(ctx); + let _ = self.sync(cx); let mut edits = Vec::new(); let mut folds = Vec::new(); - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); for range in ranges.into_iter() { let range = range.start.to_offset(buffer)..range.end.to_offset(buffer); if range.start != range.end { @@ -124,23 +124,23 @@ impl FoldMap { new_tree.push_tree(cursor.suffix(buffer), buffer); new_tree }; - self.apply_edits(edits, ctx); + self.apply_edits(edits, cx); } pub fn unfold( &mut self, ranges: impl IntoIterator>, - ctx: &AppContext, + cx: &AppContext, ) { - let _ = self.sync(ctx); + let _ = self.sync(cx); - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); let mut edits = Vec::new(); let mut fold_ixs_to_delete = Vec::new(); for range in ranges.into_iter() { // Remove intersecting folds and add their ranges to edits that are passed to apply_edits. - let mut folds_cursor = self.intersecting_folds(range, ctx); + let mut folds_cursor = self.intersecting_folds(range, cx); while let Some(fold) = folds_cursor.item() { let offset_range = fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer); edits.push(Edit { @@ -172,18 +172,18 @@ impl FoldMap { folds.push_tree(cursor.suffix(buffer), buffer); folds }; - self.apply_edits(edits, ctx); + self.apply_edits(edits, cx); } fn intersecting_folds<'a, T>( &self, range: Range, - ctx: &'a AppContext, + cx: &'a AppContext, ) -> FilterCursor bool, Fold, usize> where T: ToOffset, { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); let start = buffer.anchor_before(range.start.to_offset(buffer)); let end = buffer.anchor_after(range.end.to_offset(buffer)); self.folds.filter::<_, usize>(move |summary| { @@ -192,20 +192,20 @@ impl FoldMap { }) } - pub fn intersects_fold(&self, offset: T, ctx: &AppContext) -> bool + pub fn intersects_fold(&self, offset: T, cx: &AppContext) -> bool where T: ToOffset, { - let buffer = self.buffer.read(ctx); + let buffer = self.buffer.read(cx); let offset = offset.to_offset(buffer); - let transforms = self.sync(ctx); + let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); cursor.seek(&offset, SeekBias::Right, &()); cursor.item().map_or(false, |t| t.display_text.is_some()) } - pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool { - let transforms = self.sync(ctx); + pub fn is_line_folded(&self, display_row: u32, cx: &AppContext) -> bool { + let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); cursor.seek(&DisplayPoint::new(display_row, 0), SeekBias::Right, &()); while let Some(transform) = cursor.item() { @@ -221,24 +221,24 @@ impl FoldMap { false } - pub fn to_buffer_offset(&self, point: DisplayPoint, ctx: &AppContext) -> usize { - self.snapshot(ctx).to_buffer_offset(point) + pub fn to_buffer_offset(&self, point: DisplayPoint, cx: &AppContext) -> usize { + self.snapshot(cx).to_buffer_offset(point) } - pub fn to_display_offset(&self, point: DisplayPoint, ctx: &AppContext) -> DisplayOffset { - self.snapshot(ctx).to_display_offset(point) + pub fn to_display_offset(&self, point: DisplayPoint, cx: &AppContext) -> DisplayOffset { + self.snapshot(cx).to_display_offset(point) } - pub fn to_buffer_point(&self, display_point: DisplayPoint, ctx: &AppContext) -> Point { - let transforms = self.sync(ctx); + pub fn to_buffer_point(&self, display_point: DisplayPoint, cx: &AppContext) -> Point { + let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); cursor.seek(&display_point, SeekBias::Right, &()); let overshoot = display_point.0 - cursor.start().display.lines; cursor.start().buffer.lines + overshoot } - pub fn to_display_point(&self, point: Point, ctx: &AppContext) -> DisplayPoint { - let transforms = self.sync(ctx); + pub fn to_display_point(&self, point: Point, cx: &AppContext) -> DisplayPoint { + let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); cursor.seek(&point, SeekBias::Right, &()); let overshoot = point - cursor.start().buffer.lines; @@ -248,18 +248,18 @@ impl FoldMap { )) } - fn sync(&self, ctx: &AppContext) -> MutexGuard> { - let buffer = self.buffer.read(ctx); + fn sync(&self, cx: &AppContext) -> MutexGuard> { + let buffer = self.buffer.read(cx); let mut edits = buffer.edits_since(self.last_sync.lock().clone()).peekable(); if edits.peek().is_some() { - self.apply_edits(edits, ctx); + self.apply_edits(edits, cx); } *self.last_sync.lock() = buffer.version(); self.transforms.lock() } - fn apply_edits(&self, edits: impl IntoIterator, ctx: &AppContext) { - let buffer = self.buffer.read(ctx); + fn apply_edits(&self, edits: impl IntoIterator, cx: &AppContext) { + let buffer = self.buffer.read(cx); let mut edits = edits.into_iter().peekable(); let mut new_transforms = SumTree::new(); @@ -846,20 +846,20 @@ mod tests { use crate::test::sample_text; #[gpui::test] - fn test_basic_folds(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + fn test_basic_folds(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx)); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); map.fold( vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(2, 4)..Point::new(4, 1), ], - app.as_ref(), + cx.as_ref(), ); - assert_eq!(map.text(app.as_ref()), "aa…cc…eeeee"); + assert_eq!(map.text(cx.as_ref()), "aa…cc…eeeee"); - buffer.update(app, |buffer, ctx| { + buffer.update(cx, |buffer, cx| { buffer .edit( vec![ @@ -867,70 +867,70 @@ mod tests { Point::new(2, 3)..Point::new(2, 3), ], "123", - Some(ctx), + Some(cx), ) .unwrap(); }); - assert_eq!(map.text(app.as_ref()), "123a…c123c…eeeee"); + assert_eq!(map.text(cx.as_ref()), "123a…c123c…eeeee"); - buffer.update(app, |buffer, ctx| { + buffer.update(cx, |buffer, cx| { let start_version = buffer.version.clone(); buffer - .edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(ctx)) + .edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(cx)) .unwrap(); buffer.edits_since(start_version).collect::>() }); - assert_eq!(map.text(app.as_ref()), "123a…c123456eee"); + assert_eq!(map.text(cx.as_ref()), "123a…c123456eee"); - map.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), app.as_ref()); - assert_eq!(map.text(app.as_ref()), "123aaaaa\nbbbbbb\nccc123456eee"); + map.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), cx.as_ref()); + assert_eq!(map.text(cx.as_ref()), "123aaaaa\nbbbbbb\nccc123456eee"); } #[gpui::test] - fn test_adjacent_folds(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, "abcdefghijkl", ctx)); + fn test_adjacent_folds(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, "abcdefghijkl", cx)); { - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); - map.fold(vec![5..8], app.as_ref()); - map.check_invariants(app.as_ref()); - assert_eq!(map.text(app.as_ref()), "abcde…ijkl"); + map.fold(vec![5..8], cx.as_ref()); + map.check_invariants(cx.as_ref()); + assert_eq!(map.text(cx.as_ref()), "abcde…ijkl"); // Create an fold adjacent to the start of the first fold. - map.fold(vec![0..1, 2..5], app.as_ref()); - map.check_invariants(app.as_ref()); - assert_eq!(map.text(app.as_ref()), "…b…ijkl"); + map.fold(vec![0..1, 2..5], cx.as_ref()); + map.check_invariants(cx.as_ref()); + assert_eq!(map.text(cx.as_ref()), "…b…ijkl"); // Create an fold adjacent to the end of the first fold. - map.fold(vec![11..11, 8..10], app.as_ref()); - map.check_invariants(app.as_ref()); - assert_eq!(map.text(app.as_ref()), "…b…kl"); + map.fold(vec![11..11, 8..10], cx.as_ref()); + map.check_invariants(cx.as_ref()); + assert_eq!(map.text(cx.as_ref()), "…b…kl"); } { - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); // Create two adjacent folds. - map.fold(vec![0..2, 2..5], app.as_ref()); - map.check_invariants(app.as_ref()); - assert_eq!(map.text(app.as_ref()), "…fghijkl"); + map.fold(vec![0..2, 2..5], cx.as_ref()); + map.check_invariants(cx.as_ref()); + assert_eq!(map.text(cx.as_ref()), "…fghijkl"); // Edit within one of the folds. - buffer.update(app, |buffer, ctx| { + buffer.update(cx, |buffer, cx| { let version = buffer.version(); - buffer.edit(vec![0..1], "12345", Some(ctx)).unwrap(); + buffer.edit(vec![0..1], "12345", Some(cx)).unwrap(); buffer.edits_since(version).collect::>() }); - map.check_invariants(app.as_ref()); - assert_eq!(map.text(app.as_ref()), "12345…fghijkl"); + map.check_invariants(cx.as_ref()); + assert_eq!(map.text(cx.as_ref()), "12345…fghijkl"); } } #[gpui::test] - fn test_overlapping_folds(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + fn test_overlapping_folds(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx)); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); map.fold( vec![ Point::new(0, 2)..Point::new(2, 2), @@ -938,38 +938,38 @@ mod tests { Point::new(1, 2)..Point::new(3, 2), Point::new(3, 1)..Point::new(4, 1), ], - app.as_ref(), + cx.as_ref(), ); - assert_eq!(map.text(app.as_ref()), "aa…eeeee"); + assert_eq!(map.text(cx.as_ref()), "aa…eeeee"); } #[gpui::test] - fn test_merging_folds_via_edit(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + fn test_merging_folds_via_edit(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx)); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); map.fold( vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(3, 1)..Point::new(4, 1), ], - app.as_ref(), + cx.as_ref(), ); - assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee"); + assert_eq!(map.text(cx.as_ref()), "aa…cccc\nd…eeeee"); - buffer.update(app, |buffer, ctx| { + buffer.update(cx, |buffer, cx| { buffer - .edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(ctx)) + .edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(cx)) .unwrap(); }); - assert_eq!(map.text(app.as_ref()), "aa…eeeee"); + assert_eq!(map.text(cx.as_ref()), "aa…eeeee"); } #[gpui::test] - fn test_folds_in_range(app: &mut gpui::MutableAppContext) { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); - let buffer = buffer.read(app); + fn test_folds_in_range(cx: &mut gpui::MutableAppContext) { + let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx)); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); + let buffer = buffer.read(cx); map.fold( vec![ @@ -978,10 +978,10 @@ mod tests { Point::new(1, 2)..Point::new(3, 2), Point::new(3, 1)..Point::new(4, 1), ], - app.as_ref(), + cx.as_ref(), ); let fold_ranges = map - .folds_in_range(Point::new(1, 0)..Point::new(1, 3), app.as_ref()) + .folds_in_range(Point::new(1, 0)..Point::new(1, 3), cx.as_ref()) .map(|fold| fold.start.to_point(buffer)..fold.end.to_point(buffer)) .collect::>(); assert_eq!( @@ -994,7 +994,7 @@ mod tests { } #[gpui::test] - fn test_random_folds(app: &mut gpui::MutableAppContext) { + fn test_random_folds(cx: &mut gpui::MutableAppContext) { use crate::editor::ToPoint; use crate::util::RandomCharIter; use rand::prelude::*; @@ -1018,18 +1018,18 @@ mod tests { dbg!(seed); let mut rng = StdRng::seed_from_u64(seed); - let buffer = app.add_model(|ctx| { + let buffer = cx.add_model(|cx| { let len = rng.gen_range(0..10); let text = RandomCharIter::new(&mut rng).take(len).collect::(); - Buffer::new(0, text, ctx) + Buffer::new(0, text, cx) }); - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); for _ in 0..operations { - log::info!("text: {:?}", buffer.read(app).text()); + log::info!("text: {:?}", buffer.read(cx).text()); match rng.gen_range(0..=100) { 0..=34 => { - let buffer = buffer.read(app); + let buffer = buffer.read(cx); let mut to_fold = Vec::new(); for _ in 0..rng.gen_range(1..=5) { let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right); @@ -1037,10 +1037,10 @@ mod tests { to_fold.push(start..end); } log::info!("folding {:?}", to_fold); - map.fold(to_fold, app.as_ref()); + map.fold(to_fold, cx.as_ref()); } 35..=59 if !map.folds.is_empty() => { - let buffer = buffer.read(app); + let buffer = buffer.read(cx); let mut to_unfold = Vec::new(); for _ in 0..rng.gen_range(1..=3) { let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right); @@ -1048,25 +1048,25 @@ mod tests { to_unfold.push(start..end); } log::info!("unfolding {:?}", to_unfold); - map.unfold(to_unfold, app.as_ref()); + map.unfold(to_unfold, cx.as_ref()); } _ => { - let edits = buffer.update(app, |buffer, ctx| { + let edits = buffer.update(cx, |buffer, cx| { let start_version = buffer.version.clone(); let edit_count = rng.gen_range(1..=5); - buffer.randomly_edit(&mut rng, edit_count, Some(ctx)); + buffer.randomly_edit(&mut rng, edit_count, Some(cx)); buffer.edits_since(start_version).collect::>() }); log::info!("editing {:?}", edits); } } - map.check_invariants(app.as_ref()); + map.check_invariants(cx.as_ref()); - let buffer = map.buffer.read(app); + let buffer = map.buffer.read(cx); let mut expected_text = buffer.text(); let mut expected_buffer_rows = Vec::new(); let mut next_row = buffer.max_point().row; - for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() { + for fold_range in map.merged_fold_ranges(cx.as_ref()).into_iter().rev() { let fold_start = buffer.point_for_offset(fold_range.start).unwrap(); let fold_end = buffer.point_for_offset(fold_range.end).unwrap(); expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev()); @@ -1077,14 +1077,14 @@ mod tests { expected_buffer_rows.extend((0..=next_row).rev()); expected_buffer_rows.reverse(); - assert_eq!(map.text(app.as_ref()), expected_text); + assert_eq!(map.text(cx.as_ref()), expected_text); for (display_row, line) in expected_text.lines().enumerate() { - let line_len = map.line_len(display_row as u32, app.as_ref()); + let line_len = map.line_len(display_row as u32, cx.as_ref()); assert_eq!(line_len, line.len() as u32); } - let longest_row = map.longest_row(app.as_ref()); + let longest_row = map.longest_row(cx.as_ref()); let longest_char_column = expected_text .split('\n') .nth(longest_row as usize) @@ -1095,22 +1095,22 @@ mod tests { let mut display_offset = DisplayOffset(0); let mut char_column = 0; for c in expected_text.chars() { - let buffer_point = map.to_buffer_point(display_point, app.as_ref()); + let buffer_point = map.to_buffer_point(display_point, cx.as_ref()); let buffer_offset = buffer_point.to_offset(buffer); assert_eq!( - map.to_display_point(buffer_point, app.as_ref()), + map.to_display_point(buffer_point, cx.as_ref()), display_point, "to_display_point({:?})", buffer_point, ); assert_eq!( - map.to_buffer_offset(display_point, app.as_ref()), + map.to_buffer_offset(display_point, cx.as_ref()), buffer_offset, "to_buffer_offset({:?})", display_point, ); assert_eq!( - map.to_display_offset(display_point, app.as_ref()), + map.to_display_offset(display_point, cx.as_ref()), display_offset, "to_display_offset({:?})", display_point, @@ -1137,12 +1137,12 @@ mod tests { } for _ in 0..5 { - let offset = map.snapshot(app.as_ref()).clip_offset( - DisplayOffset(rng.gen_range(0..=map.len(app.as_ref()))), + let offset = map.snapshot(cx.as_ref()).clip_offset( + DisplayOffset(rng.gen_range(0..=map.len(cx.as_ref()))), Bias::Right, ); assert_eq!( - map.snapshot(app.as_ref()) + map.snapshot(cx.as_ref()) .chunks_at(offset) .collect::(), &expected_text[offset.0..], @@ -1151,20 +1151,20 @@ mod tests { for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() { let display_row = map - .to_display_point(Point::new(*buffer_row, 0), app.as_ref()) + .to_display_point(Point::new(*buffer_row, 0), cx.as_ref()) .row(); assert_eq!( - map.snapshot(app.as_ref()) + map.snapshot(cx.as_ref()) .buffer_rows(display_row) .collect::>(), expected_buffer_rows[idx..], ); } - for fold_range in map.merged_fold_ranges(app.as_ref()) { + for fold_range in map.merged_fold_ranges(cx.as_ref()) { let display_point = - map.to_display_point(fold_range.start.to_point(buffer), app.as_ref()); - assert!(map.is_line_folded(display_point.row(), app.as_ref())); + map.to_display_point(fold_range.start.to_point(buffer), cx.as_ref()); + assert!(map.is_line_folded(display_point.row(), cx.as_ref())); } for _ in 0..5 { @@ -1184,7 +1184,7 @@ mod tests { .collect::>(); assert_eq!( - map.folds_in_range(start..end, app.as_ref()) + map.folds_in_range(start..end, cx.as_ref()) .cloned() .collect::>(), expected_folds @@ -1195,42 +1195,38 @@ mod tests { } #[gpui::test] - fn test_buffer_rows(app: &mut gpui::MutableAppContext) { + fn test_buffer_rows(cx: &mut gpui::MutableAppContext) { let text = sample_text(6, 6) + "\n"; - let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); - let mut map = FoldMap::new(buffer.clone(), app.as_ref()); + let mut map = FoldMap::new(buffer.clone(), cx.as_ref()); map.fold( vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(3, 1)..Point::new(4, 1), ], - app.as_ref(), + cx.as_ref(), ); - assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee\nffffff\n"); + assert_eq!(map.text(cx.as_ref()), "aa…cccc\nd…eeeee\nffffff\n"); assert_eq!( - map.snapshot(app.as_ref()) - .buffer_rows(0) - .collect::>(), + map.snapshot(cx.as_ref()).buffer_rows(0).collect::>(), vec![0, 3, 5, 6] ); assert_eq!( - map.snapshot(app.as_ref()) - .buffer_rows(3) - .collect::>(), + map.snapshot(cx.as_ref()).buffer_rows(3).collect::>(), vec![6] ); } impl FoldMap { - fn text(&self, app: &AppContext) -> String { - self.snapshot(app).chunks_at(DisplayOffset(0)).collect() + fn text(&self, cx: &AppContext) -> String { + self.snapshot(cx).chunks_at(DisplayOffset(0)).collect() } - fn merged_fold_ranges(&self, app: &AppContext) -> Vec> { - let buffer = self.buffer.read(app); + fn merged_fold_ranges(&self, cx: &AppContext) -> Vec> { + let buffer = self.buffer.read(cx); let mut folds = self.folds.items(); // Ensure sorting doesn't change how folds get merged and displayed. folds.sort_by(|a, b| a.0.cmp(&b.0, buffer).unwrap()); @@ -1258,9 +1254,9 @@ mod tests { merged_ranges } - fn check_invariants(&self, ctx: &AppContext) { - let transforms = self.sync(ctx); - let buffer = self.buffer.read(ctx); + fn check_invariants(&self, cx: &AppContext) { + let transforms = self.sync(cx); + let buffer = self.buffer.read(cx); assert_eq!( transforms.summary().buffer.bytes, buffer.len(), From 5fe3081e7cc0c09b9e9d94dbf103322b1f2915aa Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:09:52 -0700 Subject: [PATCH 13/16] Rename context parameters to `cx` in pane.rs --- zed/src/workspace/pane.rs | 153 ++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 87 deletions(-) diff --git a/zed/src/workspace/pane.rs b/zed/src/workspace/pane.rs index 4108ac67a540b69ac204b9a3de43d258dac215b9..16b1520a2bb70e4487f3e02ac301c3fb164c9331 100644 --- a/zed/src/workspace/pane.rs +++ b/zed/src/workspace/pane.rs @@ -10,42 +10,39 @@ use gpui::{ use postage::watch; use std::{cmp, path::Path, sync::Arc}; -pub fn init(app: &mut MutableAppContext) { - app.add_action( +pub fn init(cx: &mut MutableAppContext) { + cx.add_action( "pane:activate_item", - |pane: &mut Pane, index: &usize, ctx| { - pane.activate_item(*index, ctx); + |pane: &mut Pane, index: &usize, cx| { + pane.activate_item(*index, cx); }, ); - app.add_action("pane:activate_prev_item", |pane: &mut Pane, _: &(), ctx| { - pane.activate_prev_item(ctx); + cx.add_action("pane:activate_prev_item", |pane: &mut Pane, _: &(), cx| { + pane.activate_prev_item(cx); }); - app.add_action("pane:activate_next_item", |pane: &mut Pane, _: &(), ctx| { - pane.activate_next_item(ctx); + cx.add_action("pane:activate_next_item", |pane: &mut Pane, _: &(), cx| { + pane.activate_next_item(cx); }); - app.add_action("pane:close_active_item", |pane: &mut Pane, _: &(), ctx| { - pane.close_active_item(ctx); + cx.add_action("pane:close_active_item", |pane: &mut Pane, _: &(), cx| { + pane.close_active_item(cx); }); - app.add_action( - "pane:close_item", - |pane: &mut Pane, item_id: &usize, ctx| { - pane.close_item(*item_id, ctx); - }, - ); - app.add_action("pane:split_up", |pane: &mut Pane, _: &(), ctx| { - pane.split(SplitDirection::Up, ctx); + cx.add_action("pane:close_item", |pane: &mut Pane, item_id: &usize, cx| { + pane.close_item(*item_id, cx); + }); + cx.add_action("pane:split_up", |pane: &mut Pane, _: &(), cx| { + pane.split(SplitDirection::Up, cx); }); - app.add_action("pane:split_down", |pane: &mut Pane, _: &(), ctx| { - pane.split(SplitDirection::Down, ctx); + cx.add_action("pane:split_down", |pane: &mut Pane, _: &(), cx| { + pane.split(SplitDirection::Down, cx); }); - app.add_action("pane:split_left", |pane: &mut Pane, _: &(), ctx| { - pane.split(SplitDirection::Left, ctx); + cx.add_action("pane:split_left", |pane: &mut Pane, _: &(), cx| { + pane.split(SplitDirection::Left, cx); }); - app.add_action("pane:split_right", |pane: &mut Pane, _: &(), ctx| { - pane.split(SplitDirection::Right, ctx); + cx.add_action("pane:split_right", |pane: &mut Pane, _: &(), cx| { + pane.split(SplitDirection::Right, cx); }); - app.add_bindings(vec![ + cx.add_bindings(vec![ Binding::new("shift-cmd-{", "pane:activate_prev_item", Some("Pane")), Binding::new("shift-cmd-}", "pane:activate_next_item", Some("Pane")), Binding::new("cmd-w", "pane:close_active_item", Some("Pane")), @@ -88,18 +85,14 @@ impl Pane { } } - pub fn activate(&self, ctx: &mut ViewContext) { - ctx.emit(Event::Activate); + pub fn activate(&self, cx: &mut ViewContext) { + cx.emit(Event::Activate); } - pub fn add_item( - &mut self, - item: Box, - ctx: &mut ViewContext, - ) -> usize { + pub fn add_item(&mut self, item: Box, cx: &mut ViewContext) -> usize { let item_idx = cmp::min(self.active_item + 1, self.items.len()); self.items.insert(item_idx, item); - ctx.notify(); + cx.notify(); item_idx } @@ -115,13 +108,13 @@ impl Pane { pub fn activate_entry( &mut self, entry_id: (usize, Arc), - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> bool { if let Some(index) = self.items.iter().position(|item| { - item.entry_id(ctx.as_ref()) + item.entry_id(cx.as_ref()) .map_or(false, |id| id == entry_id) }) { - self.activate_item(index, ctx); + self.activate_item(index, cx); true } else { false @@ -132,64 +125,64 @@ impl Pane { self.items.iter().position(|i| i.id() == item.id()) } - pub fn activate_item(&mut self, index: usize, ctx: &mut ViewContext) { + pub fn activate_item(&mut self, index: usize, cx: &mut ViewContext) { if index < self.items.len() { self.active_item = index; - self.focus_active_item(ctx); - ctx.notify(); + self.focus_active_item(cx); + cx.notify(); } } - pub fn activate_prev_item(&mut self, ctx: &mut ViewContext) { + pub fn activate_prev_item(&mut self, cx: &mut ViewContext) { if self.active_item > 0 { self.active_item -= 1; } else if self.items.len() > 0 { self.active_item = self.items.len() - 1; } - self.focus_active_item(ctx); - ctx.notify(); + self.focus_active_item(cx); + cx.notify(); } - pub fn activate_next_item(&mut self, ctx: &mut ViewContext) { + pub fn activate_next_item(&mut self, cx: &mut ViewContext) { if self.active_item + 1 < self.items.len() { self.active_item += 1; } else { self.active_item = 0; } - self.focus_active_item(ctx); - ctx.notify(); + self.focus_active_item(cx); + cx.notify(); } - pub fn close_active_item(&mut self, ctx: &mut ViewContext) { + pub fn close_active_item(&mut self, cx: &mut ViewContext) { if !self.items.is_empty() { - self.close_item(self.items[self.active_item].id(), ctx) + self.close_item(self.items[self.active_item].id(), cx) } } - pub fn close_item(&mut self, item_id: usize, ctx: &mut ViewContext) { + pub fn close_item(&mut self, item_id: usize, cx: &mut ViewContext) { self.items.retain(|item| item.id() != item_id); self.active_item = cmp::min(self.active_item, self.items.len().saturating_sub(1)); if self.items.is_empty() { - ctx.emit(Event::Remove); + cx.emit(Event::Remove); } - ctx.notify(); + cx.notify(); } - fn focus_active_item(&mut self, ctx: &mut ViewContext) { + fn focus_active_item(&mut self, cx: &mut ViewContext) { if let Some(active_item) = self.active_item() { - ctx.focus(active_item.to_any()); + cx.focus(active_item.to_any()); } } - pub fn split(&mut self, direction: SplitDirection, ctx: &mut ViewContext) { - ctx.emit(Event::Split(direction)); + pub fn split(&mut self, direction: SplitDirection, cx: &mut ViewContext) { + cx.emit(Event::Split(direction)); } - fn render_tabs(&self, ctx: &AppContext) -> ElementBox { + fn render_tabs(&self, cx: &AppContext) -> ElementBox { let settings = self.settings.borrow(); let border_color = ColorU::from_u32(0xdbdbdcff); - let line_height = ctx.font_cache().line_height( - ctx.font_cache().default_font(settings.ui_font_family), + let line_height = cx.font_cache().line_height( + cx.font_cache().default_font(settings.ui_font_family), settings.ui_font_size, ); @@ -201,8 +194,8 @@ impl Pane { row.add_child( Expanded::new( 1.0, - MouseEventHandler::new::(item.id(), ctx, |mouse_state| { - let title = item.title(ctx); + MouseEventHandler::new::(item.id(), cx, |mouse_state| { + let title = item.title(cx); let mut border = Border::new(1.0, border_color); border.left = ix > 0; @@ -227,9 +220,9 @@ impl Pane { item.id(), line_height - 2., mouse_state.hovered, - item.is_dirty(ctx), - item.has_conflict(ctx), - ctx, + item.is_dirty(cx), + item.has_conflict(cx), + cx, )) .right() .boxed(), @@ -250,8 +243,8 @@ impl Pane { ConstrainedBox::new( EventHandler::new(container.boxed()) - .on_mouse_down(move |ctx| { - ctx.dispatch_action("pane:activate_item", ix); + .on_mouse_down(move |cx| { + cx.dispatch_action("pane:activate_item", ix); true }) .boxed(), @@ -299,7 +292,7 @@ impl Pane { tab_hovered: bool, is_dirty: bool, has_conflict: bool, - ctx: &AppContext, + cx: &AppContext, ) -> ElementBox { enum TabCloseButton {} @@ -319,7 +312,7 @@ impl Pane { let icon = if tab_hovered { let mut icon = Svg::new("icons/x.svg"); - MouseEventHandler::new::(item_id, ctx, |mouse_state| { + MouseEventHandler::new::(item_id, cx, |mouse_state| { if mouse_state.hovered { Container::new(icon.with_color(ColorU::white()).boxed()) .with_background_color(if mouse_state.clicked { @@ -336,15 +329,15 @@ impl Pane { icon.boxed() } }) - .on_click(move |ctx| ctx.dispatch_action("pane:close_item", item_id)) + .on_click(move |cx| cx.dispatch_action("pane:close_item", item_id)) .named("close-tab-icon") } else { let diameter = 8.; ConstrainedBox::new( - Canvas::new(move |bounds, ctx| { + Canvas::new(move |bounds, cx| { if let Some(current_color) = current_color { let square = RectF::new(bounds.origin(), vec2f(diameter, diameter)); - ctx.scene.push_quad(Quad { + cx.scene.push_quad(Quad { bounds: square, background: Some(current_color), border: Default::default(), @@ -374,10 +367,10 @@ impl View for Pane { "Pane" } - fn render<'a>(&self, app: &AppContext) -> ElementBox { + fn render<'a>(&self, cx: &AppContext) -> ElementBox { if let Some(active_item) = self.active_item() { Flex::column() - .with_child(self.render_tabs(app)) + .with_child(self.render_tabs(cx)) .with_child(Expanded::new(1.0, ChildView::new(active_item.id()).boxed()).boxed()) .named("pane") } else { @@ -385,21 +378,7 @@ impl View for Pane { } } - fn on_focus(&mut self, ctx: &mut ViewContext) { - self.focus_active_item(ctx); + fn on_focus(&mut self, cx: &mut ViewContext) { + self.focus_active_item(cx); } - - // fn state(&self, app: &AppContext) -> Self::State { - // State { - // tabs: self - // .items - // .iter() - // .enumerate() - // .map(|(idx, item)| TabState { - // title: item.title(app), - // active: idx == self.active_item, - // }) - // .collect(), - // } - // } } From f6e2754494b6636445e773d5402d8c28907a2f1c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:10:39 -0700 Subject: [PATCH 14/16] Rename context parameters to `cx` in main.rs --- zed/src/main.rs | 14 +++++++------- zed/src/test.rs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/zed/src/main.rs b/zed/src/main.rs index 8df011e7d2bba5f6d9222d64f29ad88a947aa3d4..5340cedc616203f2ebc378633ac74181632e72ff 100644 --- a/zed/src/main.rs +++ b/zed/src/main.rs @@ -24,19 +24,19 @@ fn main() { settings, }; - app.run(move |ctx| { - ctx.set_menus(menus::menus(app_state.settings.clone())); - workspace::init(ctx); - editor::init(ctx); - file_finder::init(ctx); + app.run(move |cx| { + cx.set_menus(menus::menus(app_state.settings.clone())); + workspace::init(cx); + editor::init(cx); + file_finder::init(cx); if stdout_is_a_pty() { - ctx.platform().activate(true); + cx.platform().activate(true); } let paths = collect_path_args(); if !paths.is_empty() { - ctx.dispatch_global_action( + cx.dispatch_global_action( "workspace:open_paths", OpenParams { paths, diff --git a/zed/src/test.rs b/zed/src/test.rs index 5efb0f3e3573f3165596b299b02c6dd844e10a4d..90ef48e6c088d815f6cecbeeebb58db1826f40bf 100644 --- a/zed/src/test.rs +++ b/zed/src/test.rs @@ -144,8 +144,8 @@ fn write_tree(path: &Path, tree: serde_json::Value) { } } -pub fn build_app_state(ctx: &AppContext) -> AppState { - let settings = settings::channel(&ctx.font_cache()).unwrap().1; +pub fn build_app_state(cx: &AppContext) -> AppState { + let settings = settings::channel(&cx.font_cache()).unwrap().1; let language_registry = Arc::new(LanguageRegistry::new()); AppState { settings, From 173f99748dbf6a73c88ed4a5fbab2a0f2a037d8c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:24:33 -0700 Subject: [PATCH 15/16] Rename context parameters to `cx` in sum_tree --- zed/src/sum_tree.rs | 90 +++++++++++++++++++------------------- zed/src/sum_tree/cursor.rs | 55 +++++++++++------------ 2 files changed, 70 insertions(+), 75 deletions(-) diff --git a/zed/src/sum_tree.rs b/zed/src/sum_tree.rs index 90cffaebd68d34b51183b7eeeea008e02c3d4fae..8a2f9eb47594a6fdb81392468cb0210f7fa58d34 100644 --- a/zed/src/sum_tree.rs +++ b/zed/src/sum_tree.rs @@ -25,7 +25,7 @@ pub trait KeyedItem: Item { pub trait Summary: Default + Clone + fmt::Debug { type Context; - fn add_summary(&mut self, summary: &Self, ctx: &Self::Context); + fn add_summary(&mut self, summary: &Self, cx: &Self::Context); } pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default { @@ -37,7 +37,7 @@ impl<'a, T: Summary> Dimension<'a, T> for () { } pub trait SeekDimension<'a, T: Summary>: Dimension<'a, T> { - fn cmp(&self, other: &Self, ctx: &T::Context) -> Ordering; + fn cmp(&self, other: &Self, cx: &T::Context) -> Ordering; } impl<'a, S: Summary, T: Dimension<'a, S> + Ord> SeekDimension<'a, S> for T { @@ -64,9 +64,9 @@ impl SumTree { })) } - pub fn from_item(item: T, ctx: &::Context) -> Self { + pub fn from_item(item: T, cx: &::Context) -> Self { let mut tree = Self::new(); - tree.push(item, ctx); + tree.push(item, cx); tree } @@ -101,14 +101,14 @@ impl SumTree { self.rightmost_leaf().0.items().last() } - pub fn update_last(&mut self, f: impl FnOnce(&mut T), ctx: &::Context) { - self.update_last_recursive(f, ctx); + pub fn update_last(&mut self, f: impl FnOnce(&mut T), cx: &::Context) { + self.update_last_recursive(f, cx); } fn update_last_recursive( &mut self, f: impl FnOnce(&mut T), - ctx: &::Context, + cx: &::Context, ) -> Option { match Arc::make_mut(&mut self.0) { Node::Internal { @@ -119,8 +119,8 @@ impl SumTree { } => { let last_summary = child_summaries.last_mut().unwrap(); let last_child = child_trees.last_mut().unwrap(); - *last_summary = last_child.update_last_recursive(f, ctx).unwrap(); - *summary = sum(child_summaries.iter(), ctx); + *last_summary = last_child.update_last_recursive(f, cx).unwrap(); + *summary = sum(child_summaries.iter(), cx); Some(summary.clone()) } Node::Leaf { @@ -132,7 +132,7 @@ impl SumTree { { (f)(item); *item_summary = item.summary(); - *summary = sum(item_summaries.iter(), ctx); + *summary = sum(item_summaries.iter(), cx); Some(summary.clone()) } else { None @@ -165,7 +165,7 @@ impl SumTree { } } - pub fn extend(&mut self, iter: I, ctx: &::Context) + pub fn extend(&mut self, iter: I, cx: &::Context) where I: IntoIterator, { @@ -173,7 +173,7 @@ impl SumTree { for item in iter { if leaf.is_some() && leaf.as_ref().unwrap().items().len() == 2 * TREE_BASE { - self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx); + self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), cx); } if leaf.is_none() { @@ -191,7 +191,7 @@ impl SumTree { }) = leaf.as_mut() { let item_summary = item.summary(); - summary.add_summary(&item_summary, ctx); + summary.add_summary(&item_summary, cx); items.push(item); item_summaries.push(item_summary); } else { @@ -200,11 +200,11 @@ impl SumTree { } if leaf.is_some() { - self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx); + self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), cx); } } - pub fn push(&mut self, item: T, ctx: &::Context) { + pub fn push(&mut self, item: T, cx: &::Context) { let summary = item.summary(); self.push_tree( SumTree(Arc::new(Node::Leaf { @@ -212,18 +212,18 @@ impl SumTree { items: ArrayVec::from_iter(Some(item)), item_summaries: ArrayVec::from_iter(Some(summary)), })), - ctx, + cx, ); } - pub fn push_tree(&mut self, other: Self, ctx: &::Context) { + pub fn push_tree(&mut self, other: Self, cx: &::Context) { if !other.0.is_leaf() || other.0.items().len() > 0 { if self.0.height() < other.0.height() { for tree in other.0.child_trees() { - self.push_tree(tree.clone(), ctx); + self.push_tree(tree.clone(), cx); } - } else if let Some(split_tree) = self.push_tree_recursive(other, ctx) { - *self = Self::from_child_trees(self.clone(), split_tree, ctx); + } else if let Some(split_tree) = self.push_tree_recursive(other, cx) { + *self = Self::from_child_trees(self.clone(), split_tree, cx); } } } @@ -231,7 +231,7 @@ impl SumTree { fn push_tree_recursive( &mut self, other: SumTree, - ctx: &::Context, + cx: &::Context, ) -> Option> { match Arc::make_mut(&mut self.0) { Node::Internal { @@ -242,7 +242,7 @@ impl SumTree { .. } => { let other_node = other.0.clone(); - summary.add_summary(other_node.summary(), ctx); + summary.add_summary(other_node.summary(), cx); let height_delta = *height - other_node.height(); let mut summaries_to_append = ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new(); @@ -257,7 +257,7 @@ impl SumTree { let tree_to_append = child_trees .last_mut() .unwrap() - .push_tree_recursive(other, ctx); + .push_tree_recursive(other, cx); *child_summaries.last_mut().unwrap() = child_trees.last().unwrap().0.summary().clone(); @@ -287,13 +287,13 @@ impl SumTree { left_trees = all_trees.by_ref().take(midpoint).collect(); right_trees = all_trees.collect(); } - *summary = sum(left_summaries.iter(), ctx); + *summary = sum(left_summaries.iter(), cx); *child_summaries = left_summaries; *child_trees = left_trees; Some(SumTree(Arc::new(Node::Internal { height: *height, - summary: sum(right_summaries.iter(), ctx), + summary: sum(right_summaries.iter(), cx), child_summaries: right_summaries, child_trees: right_trees, }))) @@ -332,14 +332,14 @@ impl SumTree { } *items = left_items; *item_summaries = left_summaries; - *summary = sum(item_summaries.iter(), ctx); + *summary = sum(item_summaries.iter(), cx); Some(SumTree(Arc::new(Node::Leaf { items: right_items, - summary: sum(right_summaries.iter(), ctx), + summary: sum(right_summaries.iter(), cx), item_summaries: right_summaries, }))) } else { - summary.add_summary(other_node.summary(), ctx); + summary.add_summary(other_node.summary(), cx); items.extend(other_node.items().iter().cloned()); item_summaries.extend(other_node.child_summaries().iter().cloned()); None @@ -351,7 +351,7 @@ impl SumTree { fn from_child_trees( left: SumTree, right: SumTree, - ctx: &::Context, + cx: &::Context, ) -> Self { let height = left.0.height() + 1; let mut child_summaries = ArrayVec::new(); @@ -362,7 +362,7 @@ impl SumTree { child_trees.push(right); SumTree(Arc::new(Node::Internal { height, - summary: sum(child_summaries.iter(), ctx), + summary: sum(child_summaries.iter(), cx), child_summaries, child_trees, })) @@ -389,12 +389,12 @@ impl SumTree { impl SumTree { #[allow(unused)] - pub fn insert(&mut self, item: T, ctx: &::Context) { + pub fn insert(&mut self, item: T, cx: &::Context) { *self = { let mut cursor = self.cursor::(); - let mut new_tree = cursor.slice(&item.key(), SeekBias::Left, ctx); - new_tree.push(item, ctx); - new_tree.push_tree(cursor.suffix(ctx), ctx); + let mut new_tree = cursor.slice(&item.key(), SeekBias::Left, cx); + new_tree.push(item, cx); + new_tree.push_tree(cursor.suffix(cx), cx); new_tree }; } @@ -402,7 +402,7 @@ impl SumTree { pub fn edit( &mut self, mut edits: Vec>, - ctx: &::Context, + cx: &::Context, ) -> Vec { if edits.is_empty() { return Vec::new(); @@ -416,7 +416,7 @@ impl SumTree { let mut new_tree = SumTree::new(); let mut buffered_items = Vec::new(); - cursor.seek(&T::Key::default(), SeekBias::Left, ctx); + cursor.seek(&T::Key::default(), SeekBias::Left, cx); for edit in edits { let new_key = edit.key(); let mut old_item = cursor.item(); @@ -425,9 +425,9 @@ impl SumTree { .as_ref() .map_or(false, |old_item| old_item.key() < new_key) { - new_tree.extend(buffered_items.drain(..), ctx); - let slice = cursor.slice(&new_key, SeekBias::Left, ctx); - new_tree.push_tree(slice, ctx); + new_tree.extend(buffered_items.drain(..), cx); + let slice = cursor.slice(&new_key, SeekBias::Left, cx); + new_tree.push_tree(slice, cx); old_item = cursor.item(); } @@ -446,17 +446,17 @@ impl SumTree { } } - new_tree.extend(buffered_items, ctx); - new_tree.push_tree(cursor.suffix(ctx), ctx); + new_tree.extend(buffered_items, cx); + new_tree.push_tree(cursor.suffix(cx), cx); new_tree }; removed } - pub fn get(&self, key: &T::Key, ctx: &::Context) -> Option<&T> { + pub fn get(&self, key: &T::Key, cx: &::Context) -> Option<&T> { let mut cursor = self.cursor::(); - if cursor.seek(key, SeekBias::Left, ctx) { + if cursor.seek(key, SeekBias::Left, cx) { cursor.item() } else { None @@ -553,14 +553,14 @@ impl Edit { } } -fn sum<'a, T, I>(iter: I, ctx: &T::Context) -> T +fn sum<'a, T, I>(iter: I, cx: &T::Context) -> T where T: 'a + Summary, I: Iterator, { let mut sum = T::default(); for value in iter { - sum.add_summary(value, ctx); + sum.add_summary(value, cx); } sum } diff --git a/zed/src/sum_tree/cursor.rs b/zed/src/sum_tree/cursor.rs index 3d65d3f9c34d7940a6e0b2abd597fa97fce1a573..577b8eed36d353857535f717d11ae04f208d227e 100644 --- a/zed/src/sum_tree/cursor.rs +++ b/zed/src/sum_tree/cursor.rs @@ -342,33 +342,28 @@ where S: SeekDimension<'a, T::Summary>, U: Dimension<'a, T::Summary>, { - pub fn seek( - &mut self, - pos: &S, - bias: SeekBias, - ctx: &::Context, - ) -> bool { + pub fn seek(&mut self, pos: &S, bias: SeekBias, cx: &::Context) -> bool { self.reset(); - self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, ctx) + self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx) } pub fn seek_forward( &mut self, pos: &S, bias: SeekBias, - ctx: &::Context, + cx: &::Context, ) -> bool { - self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, ctx) + self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx) } pub fn slice( &mut self, end: &S, bias: SeekBias, - ctx: &::Context, + cx: &::Context, ) -> SumTree { let mut slice = SeekAggregate::Slice(SumTree::new()); - self.seek_internal::<()>(end, bias, &mut slice, ctx); + self.seek_internal::<()>(end, bias, &mut slice, cx); if let SeekAggregate::Slice(slice) = slice { slice } else { @@ -376,10 +371,10 @@ where } } - pub fn suffix(&mut self, ctx: &::Context) -> SumTree { + pub fn suffix(&mut self, cx: &::Context) -> SumTree { let extent = self.tree.extent::(); let mut slice = SeekAggregate::Slice(SumTree::new()); - self.seek_internal::<()>(&extent, SeekBias::Right, &mut slice, ctx); + self.seek_internal::<()>(&extent, SeekBias::Right, &mut slice, cx); if let SeekAggregate::Slice(slice) = slice { slice } else { @@ -391,13 +386,13 @@ where &mut self, end: &S, bias: SeekBias, - ctx: &::Context, + cx: &::Context, ) -> D where D: Dimension<'a, T::Summary>, { let mut summary = SeekAggregate::Summary(D::default()); - self.seek_internal(end, bias, &mut summary, ctx); + self.seek_internal(end, bias, &mut summary, cx); if let SeekAggregate::Summary(summary) = summary { summary } else { @@ -410,12 +405,12 @@ where target: &S, bias: SeekBias, aggregate: &mut SeekAggregate, - ctx: &::Context, + cx: &::Context, ) -> bool where D: Dimension<'a, T::Summary>, { - debug_assert!(target.cmp(&self.seek_dimension, ctx) >= Ordering::Equal); + debug_assert!(target.cmp(&self.seek_dimension, cx) >= Ordering::Equal); let mut containing_subtree = None; if self.did_seek { @@ -435,7 +430,7 @@ where let mut child_end = self.seek_dimension.clone(); child_end.add_summary(&child_summary); - let comparison = target.cmp(&child_end, ctx); + let comparison = target.cmp(&child_end, cx); if comparison == Ordering::Greater || (comparison == Ordering::Equal && bias == SeekBias::Right) { @@ -444,7 +439,7 @@ where match aggregate { SeekAggregate::None => {} SeekAggregate::Slice(slice) => { - slice.push_tree(child_tree.clone(), ctx); + slice.push_tree(child_tree.clone(), cx); } SeekAggregate::Summary(summary) => { summary.add_summary(child_summary); @@ -477,7 +472,7 @@ where let mut item_end = self.seek_dimension.clone(); item_end.add_summary(item_summary); - let comparison = target.cmp(&item_end, ctx); + let comparison = target.cmp(&item_end, cx); if comparison == Ordering::Greater || (comparison == Ordering::Equal && bias == SeekBias::Right) { @@ -491,7 +486,7 @@ where slice_items_summary .as_mut() .unwrap() - .add_summary(item_summary, ctx); + .add_summary(item_summary, cx); } SeekAggregate::Summary(summary) => { summary.add_summary(item_summary); @@ -506,7 +501,7 @@ where items: slice_items, item_summaries: slice_item_summaries, })), - ctx, + cx, ); } break 'outer; @@ -521,7 +516,7 @@ where items: slice_items, item_summaries: slice_item_summaries, })), - ctx, + cx, ); } } @@ -551,7 +546,7 @@ where let mut child_end = self.seek_dimension.clone(); child_end.add_summary(child_summary); - let comparison = target.cmp(&child_end, ctx); + let comparison = target.cmp(&child_end, cx); if comparison == Ordering::Greater || (comparison == Ordering::Equal && bias == SeekBias::Right) { @@ -560,7 +555,7 @@ where match aggregate { SeekAggregate::None => {} SeekAggregate::Slice(slice) => { - slice.push_tree(child_trees[index].clone(), ctx); + slice.push_tree(child_trees[index].clone(), cx); } SeekAggregate::Summary(summary) => { summary.add_summary(child_summary); @@ -597,7 +592,7 @@ where let mut child_end = self.seek_dimension.clone(); child_end.add_summary(item_summary); - let comparison = target.cmp(&child_end, ctx); + let comparison = target.cmp(&child_end, cx); if comparison == Ordering::Greater || (comparison == Ordering::Equal && bias == SeekBias::Right) { @@ -610,7 +605,7 @@ where slice_items_summary .as_mut() .unwrap() - .add_summary(item_summary, ctx); + .add_summary(item_summary, cx); slice_item_summaries.push(item_summary.clone()); } SeekAggregate::Summary(summary) => { @@ -636,7 +631,7 @@ where items: slice_items, item_summaries: slice_item_summaries, })), - ctx, + cx, ); } } @@ -658,9 +653,9 @@ where if let Some(summary) = self.item_summary() { end.add_summary(summary); } - target.cmp(&end, ctx) == Ordering::Equal + target.cmp(&end, cx) == Ordering::Equal } else { - target.cmp(&self.seek_dimension, ctx) == Ordering::Equal + target.cmp(&self.seek_dimension, cx) == Ordering::Equal } } } From 6ef447866ac571feca4710450fe5fba4954d1a7b Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 15:25:15 -0700 Subject: [PATCH 16/16] Rename context parameters to `cx` in gpui --- gpui/examples/text.rs | 20 +- gpui/src/app.rs | 846 ++++++++++------------- gpui/src/elements.rs | 58 +- gpui/src/elements/align.rs | 20 +- gpui/src/elements/canvas.rs | 4 +- gpui/src/elements/constrained_box.rs | 20 +- gpui/src/elements/container.rs | 24 +- gpui/src/elements/event_handler.rs | 22 +- gpui/src/elements/flex.rs | 42 +- gpui/src/elements/label.rs | 28 +- gpui/src/elements/line_box.rs | 30 +- gpui/src/elements/mouse_event_handler.rs | 36 +- gpui/src/elements/stack.rs | 24 +- gpui/src/elements/svg.rs | 8 +- gpui/src/elements/uniform_list.rs | 36 +- gpui/src/keymap.rs | 36 +- gpui/src/platform/mac/fonts.rs | 12 +- gpui/src/presenter.rs | 96 +-- gpui/src/text_layout.rs | 6 +- gpui_macros/src/lib.rs | 8 +- 20 files changed, 643 insertions(+), 733 deletions(-) diff --git a/gpui/examples/text.rs b/gpui/examples/text.rs index 7c59336672f0db03fbd26b284be4fa4ea00329df..11c327e2bb75488e1a9c33d8065af4aa920ffb37 100644 --- a/gpui/examples/text.rs +++ b/gpui/examples/text.rs @@ -10,9 +10,9 @@ use simplelog::SimpleLogger; fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); - gpui::App::new(()).unwrap().run(|ctx| { - ctx.platform().activate(true); - ctx.add_window(|_| TextView); + gpui::App::new(()).unwrap().run(|cx| { + cx.platform().activate(true); + cx.add_window(|_| TextView); }); } @@ -58,15 +58,15 @@ impl gpui::Element for TextElement { &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut gpui::PaintContext, + cx: &mut gpui::PaintContext, ) -> Self::PaintState { let font_size = 12.; - let family = ctx.font_cache.load_family(&["SF Pro Display"]).unwrap(); - let normal = ctx + let family = cx.font_cache.load_family(&["SF Pro Display"]).unwrap(); + let normal = cx .font_cache .select_font(family, &Default::default()) .unwrap(); - let bold = ctx + let bold = cx .font_cache .select_font( family, @@ -78,7 +78,7 @@ impl gpui::Element for TextElement { .unwrap(); let text = "Hello world!"; - let line = ctx.text_layout_cache.layout_str( + let line = cx.text_layout_cache.layout_str( text, font_size, &[ @@ -90,12 +90,12 @@ impl gpui::Element for TextElement { ], ); - ctx.scene.push_quad(Quad { + cx.scene.push_quad(Quad { bounds: bounds, background: Some(ColorU::white()), ..Default::default() }); - line.paint(bounds.origin(), bounds, ctx); + line.paint(bounds.origin(), bounds, cx); } fn dispatch_event( diff --git a/gpui/src/app.rs b/gpui/src/app.rs index efaf410dbb4c59407c776cd5b92fdf6cd826c803..b11f5c63da91f9365f0e7aab957399458ece87c7 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -34,16 +34,16 @@ pub trait Entity: 'static + Send + Sync { pub trait View: Entity { fn ui_name() -> &'static str; - fn render<'a>(&self, app: &AppContext) -> ElementBox; - fn on_focus(&mut self, _ctx: &mut ViewContext) {} - fn on_blur(&mut self, _ctx: &mut ViewContext) {} + fn render<'a>(&self, cx: &AppContext) -> ElementBox; + fn on_focus(&mut self, _: &mut ViewContext) {} + fn on_blur(&mut self, _: &mut ViewContext) {} fn keymap_context(&self, _: &AppContext) -> keymap::Context { Self::default_keymap_context() } fn default_keymap_context() -> keymap::Context { - let mut ctx = keymap::Context::default(); - ctx.set.insert(Self::ui_name().into()); - ctx + let mut cx = keymap::Context::default(); + cx.set.insert(Self::ui_name().into()); + cx } } @@ -114,14 +114,14 @@ impl App { ) -> T { let platform = platform::test::platform(); let foreground = Rc::new(executor::Foreground::test()); - let ctx = Rc::new(RefCell::new(MutableAppContext::new( + let cx = Rc::new(RefCell::new(MutableAppContext::new( foreground, Rc::new(platform), asset_source, ))); - ctx.borrow_mut().weak_self = Some(Rc::downgrade(&ctx)); - let mut ctx = ctx.borrow_mut(); - f(&mut *ctx) + cx.borrow_mut().weak_self = Some(Rc::downgrade(&cx)); + let mut cx = cx.borrow_mut(); + f(&mut *cx) } pub fn test_async(asset_source: A, f: Fn) -> T @@ -131,7 +131,7 @@ impl App { { let platform = Rc::new(platform::test::platform()); let foreground = Rc::new(executor::Foreground::test()); - let ctx = TestAppContext( + let cx = TestAppContext( Rc::new(RefCell::new(MutableAppContext::new( foreground.clone(), platform.clone(), @@ -139,9 +139,9 @@ impl App { ))), platform, ); - ctx.0.borrow_mut().weak_self = Some(Rc::downgrade(&ctx.0)); + cx.0.borrow_mut().weak_self = Some(Rc::downgrade(&cx.0)); - let future = f(ctx); + let future = f(cx); smol::block_on(foreground.run(future)) } @@ -154,21 +154,20 @@ impl App { asset_source, )))); - let ctx = app.0.clone(); + let cx = app.0.clone(); platform.on_menu_command(Box::new(move |command, arg| { - let mut ctx = ctx.borrow_mut(); - if let Some(key_window_id) = ctx.platform.key_window_id() { - if let Some((presenter, _)) = - ctx.presenters_and_platform_windows.get(&key_window_id) + let mut cx = cx.borrow_mut(); + if let Some(key_window_id) = cx.platform.key_window_id() { + if let Some((presenter, _)) = cx.presenters_and_platform_windows.get(&key_window_id) { let presenter = presenter.clone(); - let path = presenter.borrow().dispatch_path(ctx.as_ref()); - ctx.dispatch_action_any(key_window_id, &path, command, arg.unwrap_or(&())); + let path = presenter.borrow().dispatch_path(cx.as_ref()); + cx.dispatch_action_any(key_window_id, &path, command, arg.unwrap_or(&())); } else { - ctx.dispatch_global_action_any(command, arg.unwrap_or(&())); + cx.dispatch_global_action_any(command, arg.unwrap_or(&())); } } else { - ctx.dispatch_global_action_any(command, arg.unwrap_or(&())); + cx.dispatch_global_action_any(command, arg.unwrap_or(&())); } })); @@ -180,11 +179,11 @@ impl App { where F: 'static + FnMut(&mut MutableAppContext), { - let ctx = self.0.clone(); + let cx = self.0.clone(); self.0 .borrow() .platform - .on_become_active(Box::new(move || callback(&mut *ctx.borrow_mut()))); + .on_become_active(Box::new(move || callback(&mut *cx.borrow_mut()))); self } @@ -192,11 +191,11 @@ impl App { where F: 'static + FnMut(&mut MutableAppContext), { - let ctx = self.0.clone(); + let cx = self.0.clone(); self.0 .borrow() .platform - .on_resign_active(Box::new(move || callback(&mut *ctx.borrow_mut()))); + .on_resign_active(Box::new(move || callback(&mut *cx.borrow_mut()))); self } @@ -204,9 +203,9 @@ impl App { where F: 'static + FnMut(Event, &mut MutableAppContext) -> bool, { - let ctx = self.0.clone(); + let cx = self.0.clone(); self.0.borrow().platform.on_event(Box::new(move |event| { - callback(event, &mut *ctx.borrow_mut()) + callback(event, &mut *cx.borrow_mut()) })); self } @@ -215,12 +214,12 @@ impl App { where F: 'static + FnMut(Vec, &mut MutableAppContext), { - let ctx = self.0.clone(); + let cx = self.0.clone(); self.0 .borrow() .platform .on_open_files(Box::new(move |paths| { - callback(paths, &mut *ctx.borrow_mut()) + callback(paths, &mut *cx.borrow_mut()) })); self } @@ -231,13 +230,13 @@ impl App { { let platform = self.0.borrow().platform.clone(); platform.run(Box::new(move || { - let mut ctx = self.0.borrow_mut(); - on_finish_launching(&mut *ctx); + let mut cx = self.0.borrow_mut(); + on_finish_launching(&mut *cx); })) } pub fn font_cache(&self) -> Arc { - self.0.borrow().ctx.font_cache.clone() + self.0.borrow().cx.font_cache.clone() } fn update T>(&mut self, callback: F) -> T { @@ -347,7 +346,7 @@ impl TestAppContext { } pub fn font_cache(&self) -> Arc { - self.0.borrow().ctx.font_cache.clone() + self.0.borrow().cx.font_cache.clone() } pub fn platform(&self) -> Rc { @@ -398,11 +397,11 @@ impl AsyncAppContext { T: Entity, F: FnOnce(&mut ModelContext) -> T, { - self.update(|ctx| ctx.add_model(build_model)) + self.update(|cx| cx.add_model(build_model)) } pub fn background_executor(&self) -> Arc { - self.0.borrow().ctx.background.clone() + self.0.borrow().cx.background.clone() } } @@ -426,9 +425,9 @@ impl ReadModelWith for AsyncAppContext { handle: &ModelHandle, read: F, ) -> T { - let ctx = self.0.borrow(); - let ctx = ctx.as_ref(); - read(handle.read(ctx), ctx) + let cx = self.0.borrow(); + let cx = cx.as_ref(); + read(handle.read(cx), cx) } } @@ -452,9 +451,9 @@ impl ReadViewWith for AsyncAppContext { V: View, F: FnOnce(&V, &AppContext) -> T, { - let ctx = self.0.borrow(); - let ctx = ctx.as_ref(); - read(handle.read(ctx), ctx) + let cx = self.0.borrow(); + let cx = cx.as_ref(); + read(handle.read(cx), cx) } } @@ -478,9 +477,9 @@ impl ReadModelWith for TestAppContext { handle: &ModelHandle, read: F, ) -> T { - let ctx = self.0.borrow(); - let ctx = ctx.as_ref(); - read(handle.read(ctx), ctx) + let cx = self.0.borrow(); + let cx = cx.as_ref(); + read(handle.read(cx), cx) } } @@ -504,9 +503,9 @@ impl ReadViewWith for TestAppContext { V: View, F: FnOnce(&V, &AppContext) -> T, { - let ctx = self.0.borrow(); - let ctx = ctx.as_ref(); - read(handle.read(ctx), ctx) + let cx = self.0.borrow(); + let cx = cx.as_ref(); + read(handle.read(cx), cx) } } @@ -519,7 +518,7 @@ pub struct MutableAppContext { weak_self: Option>>, platform: Rc, assets: Arc, - ctx: AppContext, + cx: AppContext, actions: HashMap>>>, global_actions: HashMap>>, keystroke_matcher: keymap::Matcher, @@ -548,7 +547,7 @@ impl MutableAppContext { weak_self: None, platform, assets: Arc::new(AssetCache::new(asset_source)), - ctx: AppContext { + cx: AppContext { models: Default::default(), views: Default::default(), windows: Default::default(), @@ -584,7 +583,7 @@ impl MutableAppContext { } pub fn font_cache(&self) -> &Arc { - &self.ctx.font_cache + &self.cx.font_cache } pub fn foreground_executor(&self) -> &Rc { @@ -592,7 +591,7 @@ impl MutableAppContext { } pub fn background_executor(&self) -> &Arc { - &self.ctx.background + &self.cx.background } pub fn on_debug_elements(&mut self, window_id: usize, callback: F) @@ -606,7 +605,7 @@ impl MutableAppContext { pub fn debug_elements(&self, window_id: usize) -> Option { self.debug_elements_callbacks .get(&window_id) - .map(|debug_elements| debug_elements(&self.ctx)) + .map(|debug_elements| debug_elements(&self.cx)) } pub fn add_action(&mut self, name: S, mut handler: F) @@ -621,20 +620,20 @@ impl MutableAppContext { let handler = Box::new( move |view: &mut dyn AnyView, arg: &dyn Any, - app: &mut MutableAppContext, + cx: &mut MutableAppContext, window_id: usize, view_id: usize| { match arg.downcast_ref() { Some(arg) => { - let mut ctx = ViewContext::new(app, window_id, view_id); + let mut cx = ViewContext::new(cx, window_id, view_id); handler( view.as_any_mut() .downcast_mut() .expect("downcast is type safe"), arg, - &mut ctx, + &mut cx, ); - ctx.halt_action_dispatch + cx.halt_action_dispatch } None => { log::error!("Could not downcast argument for action {}", name_clone); @@ -660,9 +659,9 @@ impl MutableAppContext { { let name = name.into(); let name_clone = name.clone(); - let handler = Box::new(move |arg: &dyn Any, app: &mut MutableAppContext| { + let handler = Box::new(move |arg: &dyn Any, cx: &mut MutableAppContext| { if let Some(arg) = arg.downcast_ref() { - handler(arg, app); + handler(arg, cx); } else { log::error!("Could not downcast argument for action {}", name_clone); } @@ -672,30 +671,30 @@ impl MutableAppContext { } pub fn window_ids(&self) -> impl Iterator + '_ { - self.ctx.windows.keys().cloned() + self.cx.windows.keys().cloned() } pub fn root_view(&self, window_id: usize) -> Option> { - self.ctx + self.cx .windows .get(&window_id) .and_then(|window| window.root_view.clone().downcast::()) } pub fn root_view_id(&self, window_id: usize) -> Option { - self.ctx.root_view_id(window_id) + self.cx.root_view_id(window_id) } pub fn focused_view_id(&self, window_id: usize) -> Option { - self.ctx.focused_view_id(window_id) + self.cx.focused_view_id(window_id) } pub fn render_view(&self, window_id: usize, view_id: usize) -> Result { - self.ctx.render_view(window_id, view_id) + self.cx.render_view(window_id, view_id) } pub fn render_views(&self, window_id: usize) -> HashMap { - self.ctx.render_views(window_id) + self.cx.render_views(window_id) } pub fn update T>(&mut self, callback: F) -> T { @@ -792,7 +791,7 @@ impl MutableAppContext { let mut halted_dispatch = false; for view_id in path.iter().rev() { - if let Some(mut view) = self.ctx.views.remove(&(window_id, *view_id)) { + if let Some(mut view) = self.cx.views.remove(&(window_id, *view_id)) { let type_id = view.as_any().type_id(); if let Some((name, mut handlers)) = self @@ -813,7 +812,7 @@ impl MutableAppContext { .insert(name, handlers); } - self.ctx.views.insert((window_id, *view_id), view); + self.cx.views.insert((window_id, *view_id), view); if halted_dispatch { break; @@ -857,7 +856,7 @@ impl MutableAppContext { let mut context_chain = Vec::new(); let mut context = keymap::Context::default(); for view_id in &responder_chain { - if let Some(view) = self.ctx.views.get(&(window_id, *view_id)) { + if let Some(view) = self.cx.views.get(&(window_id, *view_id)) { context.extend(view.keymap_context(self.as_ref())); context_chain.push(context.clone()); } else { @@ -869,10 +868,10 @@ impl MutableAppContext { } let mut pending = false; - for (i, ctx) in context_chain.iter().enumerate().rev() { + for (i, cx) in context_chain.iter().enumerate().rev() { match self .keystroke_matcher - .push_keystroke(keystroke.clone(), responder_chain[i], ctx) + .push_keystroke(keystroke.clone(), responder_chain[i], cx) { MatchResult::None => {} MatchResult::Pending => pending = true, @@ -899,10 +898,10 @@ impl MutableAppContext { { self.pending_flushes += 1; let model_id = post_inc(&mut self.next_entity_id); - let handle = ModelHandle::new(model_id, &self.ctx.ref_counts); - let mut ctx = ModelContext::new(self, model_id); - let model = build_model(&mut ctx); - self.ctx.models.insert(model_id, Box::new(model)); + let handle = ModelHandle::new(model_id, &self.cx.ref_counts); + let mut cx = ModelContext::new(self, model_id); + let model = build_model(&mut cx); + self.cx.models.insert(model_id, Box::new(model)); self.flush_effects(); handle } @@ -916,7 +915,7 @@ impl MutableAppContext { let window_id = post_inc(&mut self.next_window_id); let root_view = self.add_view(window_id, build_root_view); - self.ctx.windows.insert( + self.cx.windows.insert( window_id, Window { root_view: root_view.clone().into(), @@ -925,14 +924,14 @@ impl MutableAppContext { }, ); self.open_platform_window(window_id); - root_view.update(self, |view, ctx| view.on_focus(ctx)); + root_view.update(self, |view, cx| view.on_focus(cx)); self.flush_effects(); (window_id, root_view) } pub fn remove_window(&mut self, window_id: usize) { - self.ctx.windows.remove(&window_id); + self.cx.windows.remove(&window_id); self.presenters_and_platform_windows.remove(&window_id); self.remove_dropped_entities(); } @@ -949,7 +948,7 @@ impl MutableAppContext { let text_layout_cache = TextLayoutCache::new(self.platform.fonts()); let presenter = Rc::new(RefCell::new(Presenter::new( window_id, - self.ctx.font_cache.clone(), + self.cx.font_cache.clone(), text_layout_cache, self.assets.clone(), self, @@ -959,12 +958,12 @@ impl MutableAppContext { let mut app = self.upgrade(); let presenter = presenter.clone(); window.on_event(Box::new(move |event| { - app.update(|ctx| { + app.update(|cx| { if let Event::KeyDown { keystroke, .. } = &event { - if ctx + if cx .dispatch_keystroke( window_id, - presenter.borrow().dispatch_path(ctx.as_ref()), + presenter.borrow().dispatch_path(cx.as_ref()), keystroke, ) .unwrap() @@ -973,7 +972,7 @@ impl MutableAppContext { } } - presenter.borrow_mut().dispatch_event(event, ctx); + presenter.borrow_mut().dispatch_event(event, cx); }) })); } @@ -982,11 +981,11 @@ impl MutableAppContext { let mut app = self.upgrade(); let presenter = presenter.clone(); window.on_resize(Box::new(move |window| { - app.update(|ctx| { + app.update(|cx| { let scene = presenter.borrow_mut().build_scene( window.size(), window.scale_factor(), - ctx, + cx, ); window.present_scene(scene); }) @@ -996,15 +995,15 @@ impl MutableAppContext { { let mut app = self.upgrade(); window.on_close(Box::new(move || { - app.update(|ctx| ctx.remove_window(window_id)); + app.update(|cx| cx.remove_window(window_id)); })); } self.presenters_and_platform_windows .insert(window_id, (presenter.clone(), window)); - self.on_debug_elements(window_id, move |ctx| { - presenter.borrow().debug_elements(ctx).unwrap() + self.on_debug_elements(window_id, move |cx| { + presenter.borrow().debug_elements(cx).unwrap() }); } @@ -1013,7 +1012,7 @@ impl MutableAppContext { T: View, F: FnOnce(&mut ViewContext) -> T, { - self.add_option_view(window_id, |ctx| Some(build_view(ctx))) + self.add_option_view(window_id, |cx| Some(build_view(cx))) .unwrap() } @@ -1028,11 +1027,11 @@ impl MutableAppContext { { let view_id = post_inc(&mut self.next_entity_id); self.pending_flushes += 1; - let handle = ViewHandle::new(window_id, view_id, &self.ctx.ref_counts); - let mut ctx = ViewContext::new(self, window_id, view_id); - let handle = if let Some(view) = build_view(&mut ctx) { - self.ctx.views.insert((window_id, view_id), Box::new(view)); - if let Some(window) = self.ctx.windows.get_mut(&window_id) { + let handle = ViewHandle::new(window_id, view_id, &self.cx.ref_counts); + let mut cx = ViewContext::new(self, window_id, view_id); + let handle = if let Some(view) = build_view(&mut cx) { + self.cx.views.insert((window_id, view_id), Box::new(view)); + if let Some(window) = self.cx.windows.get_mut(&window_id) { window .invalidation .get_or_insert_with(Default::default) @@ -1050,13 +1049,13 @@ impl MutableAppContext { fn remove_dropped_entities(&mut self) { loop { let (dropped_models, dropped_views, dropped_values) = - self.ctx.ref_counts.lock().take_dropped(); + self.cx.ref_counts.lock().take_dropped(); if dropped_models.is_empty() && dropped_views.is_empty() && dropped_values.is_empty() { break; } for model_id in dropped_models { - self.ctx.models.remove(&model_id); + self.cx.models.remove(&model_id); self.subscriptions.remove(&model_id); self.model_observations.remove(&model_id); } @@ -1064,8 +1063,8 @@ impl MutableAppContext { for (window_id, view_id) in dropped_views { self.subscriptions.remove(&view_id); self.model_observations.remove(&view_id); - self.ctx.views.remove(&(window_id, view_id)); - let change_focus_to = self.ctx.windows.get_mut(&window_id).and_then(|window| { + self.cx.views.remove(&(window_id, view_id)); + let change_focus_to = self.cx.windows.get_mut(&window_id).and_then(|window| { window .invalidation .get_or_insert_with(Default::default) @@ -1083,7 +1082,7 @@ impl MutableAppContext { } } - let mut values = self.ctx.values.write(); + let mut values = self.cx.values.write(); for key in dropped_values { values.remove(&key); } @@ -1126,7 +1125,7 @@ impl MutableAppContext { fn update_windows(&mut self) { let mut invalidations = HashMap::new(); - for (window_id, window) in &mut self.ctx.windows { + for (window_id, window) in &mut self.cx.windows { if let Some(invalidation) = window.invalidation.take() { invalidations.insert(*window_id, invalidation); } @@ -1153,9 +1152,9 @@ impl MutableAppContext { for mut subscription in subscriptions { let alive = match &mut subscription { Subscription::FromModel { model_id, callback } => { - if let Some(mut model) = self.ctx.models.remove(model_id) { + if let Some(mut model) = self.cx.models.remove(model_id) { callback(model.as_any_mut(), payload.as_ref(), self, *model_id); - self.ctx.models.insert(*model_id, model); + self.cx.models.insert(*model_id, model); true } else { false @@ -1166,7 +1165,7 @@ impl MutableAppContext { view_id, callback, } => { - if let Some(mut view) = self.ctx.views.remove(&(*window_id, *view_id)) { + if let Some(mut view) = self.cx.views.remove(&(*window_id, *view_id)) { callback( view.as_any_mut(), payload.as_ref(), @@ -1174,7 +1173,7 @@ impl MutableAppContext { *window_id, *view_id, ); - self.ctx.views.insert((*window_id, *view_id), view); + self.cx.views.insert((*window_id, *view_id), view); true } else { false @@ -1194,13 +1193,13 @@ impl MutableAppContext { fn notify_model_observers(&mut self, observed_id: usize) { if let Some(observations) = self.model_observations.remove(&observed_id) { - if self.ctx.models.contains_key(&observed_id) { + if self.cx.models.contains_key(&observed_id) { for mut observation in observations { let alive = match &mut observation { ModelObservation::FromModel { model_id, callback } => { - if let Some(mut model) = self.ctx.models.remove(model_id) { + if let Some(mut model) = self.cx.models.remove(model_id) { callback(model.as_any_mut(), observed_id, self, *model_id); - self.ctx.models.insert(*model_id, model); + self.cx.models.insert(*model_id, model); true } else { false @@ -1211,7 +1210,7 @@ impl MutableAppContext { view_id, callback, } => { - if let Some(mut view) = self.ctx.views.remove(&(*window_id, *view_id)) { + if let Some(mut view) = self.cx.views.remove(&(*window_id, *view_id)) { callback( view.as_any_mut(), observed_id, @@ -1219,7 +1218,7 @@ impl MutableAppContext { *window_id, *view_id, ); - self.ctx.views.insert((*window_id, *view_id), view); + self.cx.views.insert((*window_id, *view_id), view); true } else { false @@ -1239,7 +1238,7 @@ impl MutableAppContext { } fn notify_view_observers(&mut self, window_id: usize, view_id: usize) { - if let Some(window) = self.ctx.windows.get_mut(&window_id) { + if let Some(window) = self.cx.windows.get_mut(&window_id) { window .invalidation .get_or_insert_with(Default::default) @@ -1248,10 +1247,10 @@ impl MutableAppContext { } if let Some(observations) = self.view_observations.remove(&view_id) { - if self.ctx.views.contains_key(&(window_id, view_id)) { + if self.cx.views.contains_key(&(window_id, view_id)) { for mut observation in observations { let alive = if let Some(mut view) = self - .ctx + .cx .views .remove(&(observation.window_id, observation.view_id)) { @@ -1263,7 +1262,7 @@ impl MutableAppContext { observation.window_id, observation.view_id, ); - self.ctx + self.cx .views .insert((observation.window_id, observation.view_id), view); true @@ -1284,7 +1283,7 @@ impl MutableAppContext { fn focus(&mut self, window_id: usize, focused_id: usize) { if self - .ctx + .cx .windows .get(&window_id) .map(|w| w.focused_view_id) @@ -1295,22 +1294,22 @@ impl MutableAppContext { self.pending_flushes += 1; - let blurred_id = self.ctx.windows.get_mut(&window_id).map(|window| { + let blurred_id = self.cx.windows.get_mut(&window_id).map(|window| { let blurred_id = window.focused_view_id; window.focused_view_id = focused_id; blurred_id }); if let Some(blurred_id) = blurred_id { - if let Some(mut blurred_view) = self.ctx.views.remove(&(window_id, blurred_id)) { + if let Some(mut blurred_view) = self.cx.views.remove(&(window_id, blurred_id)) { blurred_view.on_blur(self, window_id, blurred_id); - self.ctx.views.insert((window_id, blurred_id), blurred_view); + self.cx.views.insert((window_id, blurred_id), blurred_view); } } - if let Some(mut focused_view) = self.ctx.views.remove(&(window_id, focused_id)) { + if let Some(mut focused_view) = self.cx.views.remove(&(window_id, focused_id)) { focused_view.on_focus(self, window_id, focused_id); - self.ctx.views.insert((window_id, focused_id), focused_view); + self.cx.views.insert((window_id, focused_id), focused_view); } self.flush_effects(); @@ -1322,8 +1321,8 @@ impl MutableAppContext { Fut: 'static + Future, T: 'static, { - let ctx = AsyncAppContext(self.weak_self.as_ref().unwrap().upgrade().unwrap()); - self.foreground.spawn(f(ctx)) + let cx = AsyncAppContext(self.weak_self.as_ref().unwrap().upgrade().unwrap()); + self.foreground.spawn(f(cx)) } pub fn write_to_clipboard(&self, item: ClipboardItem) { @@ -1337,7 +1336,7 @@ impl MutableAppContext { impl ReadModel for MutableAppContext { fn read_model(&self, handle: &ModelHandle) -> &T { - if let Some(model) = self.ctx.models.get(&handle.model_id) { + if let Some(model) = self.cx.models.get(&handle.model_id) { model .as_any() .downcast_ref() @@ -1354,17 +1353,17 @@ impl UpdateModel for MutableAppContext { T: Entity, F: FnOnce(&mut T, &mut ModelContext) -> S, { - if let Some(mut model) = self.ctx.models.remove(&handle.model_id) { + if let Some(mut model) = self.cx.models.remove(&handle.model_id) { self.pending_flushes += 1; - let mut ctx = ModelContext::new(self, handle.model_id); + let mut cx = ModelContext::new(self, handle.model_id); let result = update( model .as_any_mut() .downcast_mut() .expect("downcast is type safe"), - &mut ctx, + &mut cx, ); - self.ctx.models.insert(handle.model_id, model); + self.cx.models.insert(handle.model_id, model); self.flush_effects(); result } else { @@ -1375,7 +1374,7 @@ impl UpdateModel for MutableAppContext { impl ReadView for MutableAppContext { fn read_view(&self, handle: &ViewHandle) -> &T { - if let Some(view) = self.ctx.views.get(&(handle.window_id, handle.view_id)) { + if let Some(view) = self.cx.views.get(&(handle.window_id, handle.view_id)) { view.as_any().downcast_ref().expect("downcast is type safe") } else { panic!("circular view reference"); @@ -1391,19 +1390,19 @@ impl UpdateView for MutableAppContext { { self.pending_flushes += 1; let mut view = self - .ctx + .cx .views .remove(&(handle.window_id, handle.view_id)) .expect("circular view update"); - let mut ctx = ViewContext::new(self, handle.window_id, handle.view_id); + let mut cx = ViewContext::new(self, handle.window_id, handle.view_id); let result = update( view.as_any_mut() .downcast_mut() .expect("downcast is type safe"), - &mut ctx, + &mut cx, ); - self.ctx + self.cx .views .insert((handle.window_id, handle.view_id), view); self.flush_effects(); @@ -1413,7 +1412,7 @@ impl UpdateView for MutableAppContext { impl AsRef for MutableAppContext { fn as_ref(&self) -> &AppContext { - &self.ctx + &self.cx } } @@ -1558,10 +1557,10 @@ pub trait AnyView: Send + Sync { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; fn ui_name(&self) -> &'static str; - fn render<'a>(&self, app: &AppContext) -> ElementBox; - fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize); - fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize); - fn keymap_context(&self, app: &AppContext) -> keymap::Context; + fn render<'a>(&self, cx: &AppContext) -> ElementBox; + fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize); + fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize); + fn keymap_context(&self, cx: &AppContext) -> keymap::Context; } impl AnyView for T @@ -1580,22 +1579,22 @@ where T::ui_name() } - fn render<'a>(&self, app: &AppContext) -> ElementBox { - View::render(self, app) + fn render<'a>(&self, cx: &AppContext) -> ElementBox { + View::render(self, cx) } - fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) { - let mut ctx = ViewContext::new(app, window_id, view_id); - View::on_focus(self, &mut ctx); + fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) { + let mut cx = ViewContext::new(cx, window_id, view_id); + View::on_focus(self, &mut cx); } - fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) { - let mut ctx = ViewContext::new(app, window_id, view_id); - View::on_blur(self, &mut ctx); + fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) { + let mut cx = ViewContext::new(cx, window_id, view_id); + View::on_blur(self, &mut cx); } - fn keymap_context(&self, app: &AppContext) -> keymap::Context { - View::keymap_context(self, app) + fn keymap_context(&self, cx: &AppContext) -> keymap::Context { + View::keymap_context(self, cx) } } @@ -1617,11 +1616,11 @@ impl<'a, T: Entity> ModelContext<'a, T> { } pub fn background_executor(&self) -> &Arc { - &self.app.ctx.background + &self.app.cx.background } pub fn thread_pool(&self) -> &scoped_pool::Pool { - &self.app.ctx.thread_pool + &self.app.cx.thread_pool } pub fn halt_stream(&mut self) { @@ -1654,8 +1653,8 @@ impl<'a, T: Entity> ModelContext<'a, T> { callback: Box::new(move |model, payload, app, model_id| { let model = model.downcast_mut().expect("downcast is type safe"); let payload = payload.downcast_ref().expect("downcast is type safe"); - let mut ctx = ModelContext::new(app, model_id); - callback(model, payload, &mut ctx); + let mut cx = ModelContext::new(app, model_id); + callback(model, payload, &mut cx); }), }); } @@ -1680,9 +1679,9 @@ impl<'a, T: Entity> ModelContext<'a, T> { model_id: self.model_id, callback: Box::new(move |model, observed_id, app, model_id| { let model = model.downcast_mut().expect("downcast is type safe"); - let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts); - let mut ctx = ModelContext::new(app, model_id); - callback(model, observed, &mut ctx); + let observed = ModelHandle::new(observed_id, &app.cx.ref_counts); + let mut cx = ModelContext::new(app, model_id); + callback(model, observed, &mut cx); }), }); } @@ -1696,7 +1695,7 @@ impl<'a, T: Entity> ModelContext<'a, T> { } pub fn handle(&self) -> ModelHandle { - ModelHandle::new(self.model_id, &self.app.ctx.ref_counts) + ModelHandle::new(self.model_id, &self.app.cx.ref_counts) } pub fn spawn(&self, f: F) -> Task @@ -1706,13 +1705,13 @@ impl<'a, T: Entity> ModelContext<'a, T> { S: 'static, { let handle = self.handle(); - self.app.spawn(|ctx| f(handle, ctx)) + self.app.spawn(|cx| f(handle, cx)) } } impl AsRef for ModelContext<'_, M> { fn as_ref(&self) -> &AppContext { - &self.app.ctx + &self.app.cx } } @@ -1758,7 +1757,7 @@ impl<'a, T: View> ViewContext<'a, T> { } pub fn handle(&self) -> ViewHandle { - ViewHandle::new(self.window_id, self.view_id, &self.app.ctx.ref_counts) + ViewHandle::new(self.window_id, self.view_id, &self.app.cx.ref_counts) } pub fn window_id(&self) -> usize { @@ -1774,7 +1773,7 @@ impl<'a, T: View> ViewContext<'a, T> { } pub fn background_executor(&self) -> &Arc { - &self.app.ctx.background + &self.app.cx.background } pub fn prompt(&self, level: PromptLevel, msg: &str, answers: &[&str], done_fn: F) @@ -1852,9 +1851,9 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, ModelHandle, &E::Event, &mut ViewContext), { let emitter_handle = handle.downgrade(); - self.subscribe(handle, move |model, payload, ctx| { - if let Some(emitter_handle) = emitter_handle.upgrade(ctx.as_ref()) { - callback(model, emitter_handle, payload, ctx); + self.subscribe(handle, move |model, payload, cx| { + if let Some(emitter_handle) = emitter_handle.upgrade(cx.as_ref()) { + callback(model, emitter_handle, payload, cx); } }); } @@ -1866,9 +1865,9 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, ViewHandle, &V::Event, &mut ViewContext), { let emitter_handle = handle.downgrade(); - self.subscribe(handle, move |view, payload, ctx| { - if let Some(emitter_handle) = emitter_handle.upgrade(ctx.as_ref()) { - callback(view, emitter_handle, payload, ctx); + self.subscribe(handle, move |view, payload, cx| { + if let Some(emitter_handle) = emitter_handle.upgrade(cx.as_ref()) { + callback(view, emitter_handle, payload, cx); } }); } @@ -1889,8 +1888,8 @@ impl<'a, T: View> ViewContext<'a, T> { callback: Box::new(move |entity, payload, app, window_id, view_id| { let entity = entity.downcast_mut().expect("downcast is type safe"); let payload = payload.downcast_ref().expect("downcast is type safe"); - let mut ctx = ViewContext::new(app, window_id, view_id); - callback(entity, payload, &mut ctx); + let mut cx = ViewContext::new(app, window_id, view_id); + callback(entity, payload, &mut cx); }), }); } @@ -1916,9 +1915,9 @@ impl<'a, T: View> ViewContext<'a, T> { view_id: self.view_id, callback: Box::new(move |view, observed_id, app, window_id, view_id| { let view = view.downcast_mut().expect("downcast is type safe"); - let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts); - let mut ctx = ViewContext::new(app, window_id, view_id); - callback(view, observed, &mut ctx); + let observed = ModelHandle::new(observed_id, &app.cx.ref_counts); + let mut cx = ViewContext::new(app, window_id, view_id); + callback(view, observed, &mut cx); }), }); } @@ -1946,10 +1945,10 @@ impl<'a, T: View> ViewContext<'a, T> { let observed_handle = ViewHandle::new( observed_view_id, observed_window_id, - &app.ctx.ref_counts, + &app.cx.ref_counts, ); - let mut ctx = ViewContext::new(app, observing_window_id, observing_view_id); - callback(view, observed_handle, &mut ctx); + let mut cx = ViewContext::new(app, observing_window_id, observing_view_id); + callback(view, observed_handle, &mut cx); }, ), }); @@ -1970,7 +1969,7 @@ impl<'a, T: View> ViewContext<'a, T> { S: 'static, { let handle = self.handle(); - self.app.spawn(|ctx| f(handle, ctx)) + self.app.spawn(|cx| f(handle, cx)) } } @@ -1982,7 +1981,7 @@ impl AsRef for &AppContext { impl AsRef for ViewContext<'_, M> { fn as_ref(&self) -> &AppContext { - &self.app.ctx + &self.app.cx } } @@ -2059,42 +2058,42 @@ impl ModelHandle { self.model_id } - pub fn read<'a, A: ReadModel>(&self, app: &'a A) -> &'a T { - app.read_model(self) + pub fn read<'a, C: ReadModel>(&self, cx: &'a C) -> &'a T { + cx.read_model(self) } - pub fn read_with<'a, A, F, S>(&self, ctx: &A, read: F) -> S + pub fn read_with<'a, C, F, S>(&self, cx: &C, read: F) -> S where - A: ReadModelWith, + C: ReadModelWith, F: FnOnce(&T, &AppContext) -> S, { - ctx.read_model_with(self, read) + cx.read_model_with(self, read) } - pub fn update(&self, app: &mut A, update: F) -> S + pub fn update(&self, cx: &mut C, update: F) -> S where - A: UpdateModel, + C: UpdateModel, F: FnOnce(&mut T, &mut ModelContext) -> S, { - app.update_model(self, update) + cx.update_model(self, update) } pub fn condition( &self, - ctx: &TestAppContext, + cx: &TestAppContext, mut predicate: impl FnMut(&T, &AppContext) -> bool, ) -> impl Future { let (tx, mut rx) = mpsc::channel(1024); - let mut ctx = ctx.0.borrow_mut(); - self.update(&mut *ctx, |_, ctx| { - ctx.observe(self, { + let mut cx = cx.0.borrow_mut(); + self.update(&mut *cx, |_, cx| { + cx.observe(self, { let mut tx = tx.clone(); move |_, _, _| { tx.blocking_send(()).ok(); } }); - ctx.subscribe(self, { + cx.subscribe(self, { let mut tx = tx.clone(); move |_, _, _| { tx.blocking_send(()).ok(); @@ -2102,7 +2101,7 @@ impl ModelHandle { }) }); - let ctx = ctx.weak_self.as_ref().unwrap().upgrade().unwrap(); + let cx = cx.weak_self.as_ref().unwrap().upgrade().unwrap(); let handle = self.downgrade(); let duration = if std::env::var("CI").is_ok() { Duration::from_secs(2) @@ -2114,14 +2113,14 @@ impl ModelHandle { timeout(duration, async move { loop { { - let ctx = ctx.borrow(); - let ctx = ctx.as_ref(); + let cx = cx.borrow(); + let cx = cx.as_ref(); if predicate( handle - .upgrade(ctx) + .upgrade(cx) .expect("model dropped with pending condition") - .read(ctx), - ctx, + .read(cx), + cx, ) { break; } @@ -2209,10 +2208,10 @@ impl WeakModelHandle { } } - pub fn upgrade(&self, ctx: impl AsRef) -> Option> { - let ctx = ctx.as_ref(); - if ctx.models.contains_key(&self.model_id) { - Some(ModelHandle::new(self.model_id, &ctx.ref_counts)) + pub fn upgrade(&self, cx: impl AsRef) -> Option> { + let cx = cx.as_ref(); + if cx.models.contains_key(&self.model_id) { + Some(ModelHandle::new(self.model_id, &cx.ref_counts)) } else { None } @@ -2258,48 +2257,48 @@ impl ViewHandle { self.view_id } - pub fn read<'a, A: ReadView>(&self, app: &'a A) -> &'a T { - app.read_view(self) + pub fn read<'a, C: ReadView>(&self, cx: &'a C) -> &'a T { + cx.read_view(self) } - pub fn read_with(&self, ctx: &A, read: F) -> S + pub fn read_with(&self, cx: &C, read: F) -> S where - A: ReadViewWith, + C: ReadViewWith, F: FnOnce(&T, &AppContext) -> S, { - ctx.read_view_with(self, read) + cx.read_view_with(self, read) } - pub fn update(&self, app: &mut A, update: F) -> S + pub fn update(&self, cx: &mut C, update: F) -> S where - A: UpdateView, + C: UpdateView, F: FnOnce(&mut T, &mut ViewContext) -> S, { - app.update_view(self, update) + cx.update_view(self, update) } - pub fn is_focused(&self, app: &AppContext) -> bool { - app.focused_view_id(self.window_id) + pub fn is_focused(&self, cx: &AppContext) -> bool { + cx.focused_view_id(self.window_id) .map_or(false, |focused_id| focused_id == self.view_id) } pub fn condition( &self, - ctx: &TestAppContext, + cx: &TestAppContext, mut predicate: impl FnMut(&T, &AppContext) -> bool, ) -> impl Future { let (tx, mut rx) = mpsc::channel(1024); - let mut ctx = ctx.0.borrow_mut(); - self.update(&mut *ctx, |_, ctx| { - ctx.observe_view(self, { + let mut cx = cx.0.borrow_mut(); + self.update(&mut *cx, |_, cx| { + cx.observe_view(self, { let mut tx = tx.clone(); move |_, _, _| { tx.blocking_send(()).ok(); } }); - ctx.subscribe(self, { + cx.subscribe(self, { let mut tx = tx.clone(); move |_, _, _| { tx.blocking_send(()).ok(); @@ -2307,7 +2306,7 @@ impl ViewHandle { }) }); - let ctx = ctx.weak_self.as_ref().unwrap().upgrade().unwrap(); + let cx = cx.weak_self.as_ref().unwrap().upgrade().unwrap(); let handle = self.downgrade(); let duration = if std::env::var("CI").is_ok() { Duration::from_secs(2) @@ -2319,14 +2318,14 @@ impl ViewHandle { timeout(duration, async move { loop { { - let ctx = ctx.borrow(); - let ctx = ctx.as_ref(); + let cx = cx.borrow(); + let cx = cx.as_ref(); if predicate( handle - .upgrade(ctx) + .upgrade(cx) .expect("view dropped with pending condition") - .read(ctx), - ctx, + .read(cx), + cx, ) { break; } @@ -2515,13 +2514,13 @@ impl WeakViewHandle { } } - pub fn upgrade(&self, ctx: impl AsRef) -> Option> { - let ctx = ctx.as_ref(); - if ctx.ref_counts.lock().is_entity_alive(self.view_id) { + pub fn upgrade(&self, cx: impl AsRef) -> Option> { + let cx = cx.as_ref(); + if cx.ref_counts.lock().is_entity_alive(self.view_id) { Some(ViewHandle::new( self.window_id, self.view_id, - &ctx.ref_counts, + &cx.ref_counts, )) } else { None @@ -2557,9 +2556,8 @@ impl ValueHandle { } } - pub fn read(&self, ctx: &AppContext, f: impl FnOnce(&T) -> R) -> R { - f(ctx - .values + pub fn read(&self, cx: &AppContext, f: impl FnOnce(&T) -> R) -> R { + f(cx.values .read() .get(&(self.tag_type_id, self.id)) .unwrap() @@ -2567,9 +2565,8 @@ impl ValueHandle { .unwrap()) } - pub fn update(&self, ctx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R { - f(ctx - .values + pub fn update(&self, cx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R { + f(cx.values .write() .get_mut(&(self.tag_type_id, self.id)) .unwrap() @@ -2706,7 +2703,7 @@ mod tests { use smol::future::poll_once; #[crate::test(self)] - fn test_model_handles(app: &mut MutableAppContext) { + fn test_model_handles(cx: &mut MutableAppContext) { struct Model { other: Option>, events: Vec, @@ -2717,12 +2714,12 @@ mod tests { } impl Model { - fn new(other: Option>, ctx: &mut ModelContext) -> Self { + fn new(other: Option>, cx: &mut ModelContext) -> Self { if let Some(other) = other.as_ref() { - ctx.observe(other, |me, _, _| { + cx.observe(other, |me, _, _| { me.events.push("notified".into()); }); - ctx.subscribe(other, |me, event, _| { + cx.subscribe(other, |me, event, _| { me.events.push(format!("observed event {}", event)); }); } @@ -2734,19 +2731,19 @@ mod tests { } } - let handle_1 = app.add_model(|ctx| Model::new(None, ctx)); - let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx)); - assert_eq!(app.ctx.models.len(), 2); + let handle_1 = cx.add_model(|cx| Model::new(None, cx)); + let handle_2 = cx.add_model(|cx| Model::new(Some(handle_1.clone()), cx)); + assert_eq!(cx.cx.models.len(), 2); - handle_1.update(app, |model, ctx| { + handle_1.update(cx, |model, cx| { model.events.push("updated".into()); - ctx.emit(1); - ctx.notify(); - ctx.emit(2); + cx.emit(1); + cx.notify(); + cx.emit(2); }); - assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]); + assert_eq!(handle_1.read(cx).events, vec!["updated".to_string()]); assert_eq!( - handle_2.read(app).events, + handle_2.read(cx).events, vec![ "observed event 1".to_string(), "notified".to_string(), @@ -2754,18 +2751,18 @@ mod tests { ] ); - handle_2.update(app, |model, _| { + handle_2.update(cx, |model, _| { drop(handle_1); model.other.take(); }); - assert_eq!(app.ctx.models.len(), 1); - assert!(app.subscriptions.is_empty()); - assert!(app.model_observations.is_empty()); + assert_eq!(cx.cx.models.len(), 1); + assert!(cx.subscriptions.is_empty()); + assert!(cx.model_observations.is_empty()); } #[crate::test(self)] - fn test_subscribe_and_emit_from_model(app: &mut MutableAppContext) { + fn test_subscribe_and_emit_from_model(cx: &mut MutableAppContext) { #[derive(Default)] struct Model { events: Vec, @@ -2775,11 +2772,11 @@ mod tests { type Event = usize; } - let handle_1 = app.add_model(|_| Model::default()); - let handle_2 = app.add_model(|_| Model::default()); + let handle_1 = cx.add_model(|_| Model::default()); + let handle_2 = cx.add_model(|_| Model::default()); let handle_2b = handle_2.clone(); - handle_1.update(app, |_, c| { + handle_1.update(cx, |_, c| { c.subscribe(&handle_2, move |model: &mut Model, event, c| { model.events.push(*event); @@ -2789,15 +2786,15 @@ mod tests { }); }); - handle_2.update(app, |_, c| c.emit(7)); - assert_eq!(handle_1.read(app).events, vec![7]); + handle_2.update(cx, |_, c| c.emit(7)); + assert_eq!(handle_1.read(cx).events, vec![7]); - handle_2.update(app, |_, c| c.emit(5)); - assert_eq!(handle_1.read(app).events, vec![7, 10, 5]); + handle_2.update(cx, |_, c| c.emit(5)); + assert_eq!(handle_1.read(cx).events, vec![7, 10, 5]); } #[crate::test(self)] - fn test_observe_and_notify_from_model(app: &mut MutableAppContext) { + fn test_observe_and_notify_from_model(cx: &mut MutableAppContext) { #[derive(Default)] struct Model { count: usize, @@ -2808,11 +2805,11 @@ mod tests { type Event = (); } - let handle_1 = app.add_model(|_| Model::default()); - let handle_2 = app.add_model(|_| Model::default()); + let handle_1 = cx.add_model(|_| Model::default()); + let handle_2 = cx.add_model(|_| Model::default()); let handle_2b = handle_2.clone(); - handle_1.update(app, |_, c| { + handle_1.update(cx, |_, c| { c.observe(&handle_2, move |model, observed, c| { model.events.push(observed.read(c).count); c.observe(&handle_2b, |model, observed, c| { @@ -2821,21 +2818,21 @@ mod tests { }); }); - handle_2.update(app, |model, c| { + handle_2.update(cx, |model, c| { model.count = 7; c.notify() }); - assert_eq!(handle_1.read(app).events, vec![7]); + assert_eq!(handle_1.read(cx).events, vec![7]); - handle_2.update(app, |model, c| { + handle_2.update(cx, |model, c| { model.count = 5; c.notify() }); - assert_eq!(handle_1.read(app).events, vec![7, 10, 5]) + assert_eq!(handle_1.read(cx).events, vec![7, 10, 5]) } #[crate::test(self)] - fn test_view_handles(app: &mut MutableAppContext) { + fn test_view_handles(cx: &mut MutableAppContext) { struct View { other: Option>, events: Vec, @@ -2856,9 +2853,9 @@ mod tests { } impl View { - fn new(other: Option>, ctx: &mut ViewContext) -> Self { + fn new(other: Option>, cx: &mut ViewContext) -> Self { if let Some(other) = other.as_ref() { - ctx.subscribe_to_view(other, |me, _, event, _| { + cx.subscribe_to_view(other, |me, _, event, _| { me.events.push(format!("observed event {}", event)); }); } @@ -2869,37 +2866,37 @@ mod tests { } } - let (window_id, _) = app.add_window(|ctx| View::new(None, ctx)); - let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx)); - let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx)); - assert_eq!(app.ctx.views.len(), 3); + let (window_id, _) = cx.add_window(|cx| View::new(None, cx)); + let handle_1 = cx.add_view(window_id, |cx| View::new(None, cx)); + let handle_2 = cx.add_view(window_id, |cx| View::new(Some(handle_1.clone()), cx)); + assert_eq!(cx.cx.views.len(), 3); - handle_1.update(app, |view, ctx| { + handle_1.update(cx, |view, cx| { view.events.push("updated".into()); - ctx.emit(1); - ctx.emit(2); + cx.emit(1); + cx.emit(2); }); - assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]); + assert_eq!(handle_1.read(cx).events, vec!["updated".to_string()]); assert_eq!( - handle_2.read(app).events, + handle_2.read(cx).events, vec![ "observed event 1".to_string(), "observed event 2".to_string(), ] ); - handle_2.update(app, |view, _| { + handle_2.update(cx, |view, _| { drop(handle_1); view.other.take(); }); - assert_eq!(app.ctx.views.len(), 2); - assert!(app.subscriptions.is_empty()); - assert!(app.model_observations.is_empty()); + assert_eq!(cx.cx.views.len(), 2); + assert!(cx.subscriptions.is_empty()); + assert!(cx.model_observations.is_empty()); } #[crate::test(self)] - fn test_subscribe_and_emit_from_view(app: &mut MutableAppContext) { + fn test_subscribe_and_emit_from_view(cx: &mut MutableAppContext) { #[derive(Default)] struct View { events: Vec, @@ -2925,12 +2922,12 @@ mod tests { type Event = usize; } - let (window_id, handle_1) = app.add_window(|_| View::default()); - let handle_2 = app.add_view(window_id, |_| View::default()); + let (window_id, handle_1) = cx.add_window(|_| View::default()); + let handle_2 = cx.add_view(window_id, |_| View::default()); let handle_2b = handle_2.clone(); - let handle_3 = app.add_model(|_| Model); + let handle_3 = cx.add_model(|_| Model); - handle_1.update(app, |_, c| { + handle_1.update(cx, |_, c| { c.subscribe_to_view(&handle_2, move |me, _, event, c| { me.events.push(*event); @@ -2944,18 +2941,18 @@ mod tests { }) }); - handle_2.update(app, |_, c| c.emit(7)); - assert_eq!(handle_1.read(app).events, vec![7]); + handle_2.update(cx, |_, c| c.emit(7)); + assert_eq!(handle_1.read(cx).events, vec![7]); - handle_2.update(app, |_, c| c.emit(5)); - assert_eq!(handle_1.read(app).events, vec![7, 10, 5]); + handle_2.update(cx, |_, c| c.emit(5)); + assert_eq!(handle_1.read(cx).events, vec![7, 10, 5]); - handle_3.update(app, |_, c| c.emit(9)); - assert_eq!(handle_1.read(app).events, vec![7, 10, 5, 9]); + handle_3.update(cx, |_, c| c.emit(9)); + assert_eq!(handle_1.read(cx).events, vec![7, 10, 5, 9]); } #[crate::test(self)] - fn test_dropping_subscribers(app: &mut MutableAppContext) { + fn test_dropping_subscribers(cx: &mut MutableAppContext) { struct View; impl Entity for View { @@ -2978,31 +2975,31 @@ mod tests { type Event = (); } - let (window_id, _) = app.add_window(|_| View); - let observing_view = app.add_view(window_id, |_| View); - let emitting_view = app.add_view(window_id, |_| View); - let observing_model = app.add_model(|_| Model); - let observed_model = app.add_model(|_| Model); + let (window_id, _) = cx.add_window(|_| View); + let observing_view = cx.add_view(window_id, |_| View); + let emitting_view = cx.add_view(window_id, |_| View); + let observing_model = cx.add_model(|_| Model); + let observed_model = cx.add_model(|_| Model); - observing_view.update(app, |_, ctx| { - ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {}); - ctx.subscribe_to_model(&observed_model, |_, _, _, _| {}); + observing_view.update(cx, |_, cx| { + cx.subscribe_to_view(&emitting_view, |_, _, _, _| {}); + cx.subscribe_to_model(&observed_model, |_, _, _, _| {}); }); - observing_model.update(app, |_, ctx| { - ctx.subscribe(&observed_model, |_, _, _| {}); + observing_model.update(cx, |_, cx| { + cx.subscribe(&observed_model, |_, _, _| {}); }); - app.update(|| { + cx.update(|| { drop(observing_view); drop(observing_model); }); - emitting_view.update(app, |_, ctx| ctx.emit(())); - observed_model.update(app, |_, ctx| ctx.emit(())); + emitting_view.update(cx, |_, cx| cx.emit(())); + observed_model.update(cx, |_, cx| cx.emit(())); } #[crate::test(self)] - fn test_observe_and_notify_from_view(app: &mut MutableAppContext) { + fn test_observe_and_notify_from_view(cx: &mut MutableAppContext) { #[derive(Default)] struct View { events: Vec, @@ -3031,24 +3028,24 @@ mod tests { type Event = (); } - let (_, view) = app.add_window(|_| View::default()); - let model = app.add_model(|_| Model::default()); + let (_, view) = cx.add_window(|_| View::default()); + let model = cx.add_model(|_| Model::default()); - view.update(app, |_, c| { + view.update(cx, |_, c| { c.observe_model(&model, |me, observed, c| { me.events.push(observed.read(c).count) }); }); - model.update(app, |model, c| { + model.update(cx, |model, c| { model.count = 11; c.notify(); }); - assert_eq!(view.read(app).events, vec![11]); + assert_eq!(view.read(cx).events, vec![11]); } #[crate::test(self)] - fn test_dropping_observers(app: &mut MutableAppContext) { + fn test_dropping_observers(cx: &mut MutableAppContext) { struct View; impl Entity for View { @@ -3071,28 +3068,28 @@ mod tests { type Event = (); } - let (window_id, _) = app.add_window(|_| View); - let observing_view = app.add_view(window_id, |_| View); - let observing_model = app.add_model(|_| Model); - let observed_model = app.add_model(|_| Model); + let (window_id, _) = cx.add_window(|_| View); + let observing_view = cx.add_view(window_id, |_| View); + let observing_model = cx.add_model(|_| Model); + let observed_model = cx.add_model(|_| Model); - observing_view.update(app, |_, ctx| { - ctx.observe_model(&observed_model, |_, _, _| {}); + observing_view.update(cx, |_, cx| { + cx.observe_model(&observed_model, |_, _, _| {}); }); - observing_model.update(app, |_, ctx| { - ctx.observe(&observed_model, |_, _, _| {}); + observing_model.update(cx, |_, cx| { + cx.observe(&observed_model, |_, _, _| {}); }); - app.update(|| { + cx.update(|| { drop(observing_view); drop(observing_model); }); - observed_model.update(app, |_, ctx| ctx.notify()); + observed_model.update(cx, |_, cx| cx.notify()); } #[crate::test(self)] - fn test_focus(app: &mut MutableAppContext) { + fn test_focus(cx: &mut MutableAppContext) { struct View { name: String, events: Arc>>, @@ -3121,19 +3118,19 @@ mod tests { } let events: Arc>> = Default::default(); - let (window_id, view_1) = app.add_window(|_| View { + let (window_id, view_1) = cx.add_window(|_| View { events: events.clone(), name: "view 1".to_string(), }); - let view_2 = app.add_view(window_id, |_| View { + let view_2 = cx.add_view(window_id, |_| View { events: events.clone(), name: "view 2".to_string(), }); - view_1.update(app, |_, ctx| ctx.focus(&view_2)); - view_1.update(app, |_, ctx| ctx.focus(&view_1)); - view_1.update(app, |_, ctx| ctx.focus(&view_2)); - view_1.update(app, |_, _| drop(view_2)); + view_1.update(cx, |_, cx| cx.focus(&view_2)); + view_1.update(cx, |_, cx| cx.focus(&view_1)); + view_1.update(cx, |_, cx| cx.focus(&view_2)); + view_1.update(cx, |_, _| drop(view_2)); assert_eq!( *events.lock(), @@ -3151,7 +3148,7 @@ mod tests { } #[crate::test(self)] - fn test_dispatch_action(app: &mut MutableAppContext) { + fn test_dispatch_action(cx: &mut MutableAppContext) { struct ViewA { id: usize, } @@ -3195,48 +3192,48 @@ mod tests { let actions = Rc::new(RefCell::new(Vec::new())); let actions_clone = actions.clone(); - app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| { + cx.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| { actions_clone.borrow_mut().push("global a".to_string()); }); let actions_clone = actions.clone(); - app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| { + cx.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| { actions_clone.borrow_mut().push("global b".to_string()); }); let actions_clone = actions.clone(); - app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| { + cx.add_action("action", move |view: &mut ViewA, arg: &ActionArg, cx| { assert_eq!(arg.foo, "bar"); - ctx.propagate_action(); + cx.propagate_action(); actions_clone.borrow_mut().push(format!("{} a", view.id)); }); let actions_clone = actions.clone(); - app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| { + cx.add_action("action", move |view: &mut ViewA, _: &ActionArg, cx| { if view.id != 1 { - ctx.propagate_action(); + cx.propagate_action(); } actions_clone.borrow_mut().push(format!("{} b", view.id)); }); let actions_clone = actions.clone(); - app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| { - ctx.propagate_action(); + cx.add_action("action", move |view: &mut ViewB, _: &ActionArg, cx| { + cx.propagate_action(); actions_clone.borrow_mut().push(format!("{} c", view.id)); }); let actions_clone = actions.clone(); - app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| { - ctx.propagate_action(); + cx.add_action("action", move |view: &mut ViewB, _: &ActionArg, cx| { + cx.propagate_action(); actions_clone.borrow_mut().push(format!("{} d", view.id)); }); - let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 }); - let view_2 = app.add_view(window_id, |_| ViewB { id: 2 }); - let view_3 = app.add_view(window_id, |_| ViewA { id: 3 }); - let view_4 = app.add_view(window_id, |_| ViewB { id: 4 }); + let (window_id, view_1) = cx.add_window(|_| ViewA { id: 1 }); + let view_2 = cx.add_view(window_id, |_| ViewB { id: 2 }); + let view_3 = cx.add_view(window_id, |_| ViewA { id: 3 }); + let view_4 = cx.add_view(window_id, |_| ViewB { id: 4 }); - app.dispatch_action( + cx.dispatch_action( window_id, vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()], "action", @@ -3250,7 +3247,7 @@ mod tests { // Remove view_1, which doesn't propagate the action actions.borrow_mut().clear(); - app.dispatch_action( + cx.dispatch_action( window_id, vec![view_2.id(), view_3.id(), view_4.id()], "action", @@ -3264,7 +3261,7 @@ mod tests { } #[crate::test(self)] - fn test_dispatch_keystroke(app: &mut MutableAppContext) { + fn test_dispatch_keystroke(cx: &mut MutableAppContext) { use std::cell::Cell; #[derive(Clone)] @@ -3311,25 +3308,25 @@ mod tests { view_2.keymap_context.set.insert("b".into()); view_3.keymap_context.set.insert("c".into()); - let (window_id, view_1) = app.add_window(|_| view_1); - let view_2 = app.add_view(window_id, |_| view_2); - let view_3 = app.add_view(window_id, |_| view_3); + let (window_id, view_1) = cx.add_window(|_| view_1); + let view_2 = cx.add_view(window_id, |_| view_2); + let view_3 = cx.add_view(window_id, |_| view_3); // This keymap's only binding dispatches an action on view 2 because that view will have // "a" and "b" in its context, but not "c". let binding = keymap::Binding::new("a", "action", Some("a && b && !c")) .with_arg(ActionArg { key: "a".into() }); - app.add_bindings(vec![binding]); + cx.add_bindings(vec![binding]); let handled_action = Rc::new(Cell::new(false)); let handled_action_clone = handled_action.clone(); - app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| { + cx.add_action("action", move |view: &mut View, arg: &ActionArg, _| { handled_action_clone.set(true); assert_eq!(view.id, 2); assert_eq!(arg.key, "a"); }); - app.dispatch_keystroke( + cx.dispatch_keystroke( window_id, vec![view_1.id(), view_2.id(), view_3.id()], &Keystroke::parse("a").unwrap(), @@ -3340,7 +3337,7 @@ mod tests { } #[crate::test(self)] - async fn test_model_condition(mut app: TestAppContext) { + async fn test_model_condition(mut cx: TestAppContext) { struct Counter(usize); impl super::Entity for Counter { @@ -3348,62 +3345,62 @@ mod tests { } impl Counter { - fn inc(&mut self, ctx: &mut ModelContext) { + fn inc(&mut self, cx: &mut ModelContext) { self.0 += 1; - ctx.notify(); + cx.notify(); } } - let model = app.add_model(|_| Counter(0)); + let model = cx.add_model(|_| Counter(0)); - let condition1 = model.condition(&app, |model, _| model.0 == 2); - let condition2 = model.condition(&app, |model, _| model.0 == 3); + let condition1 = model.condition(&cx, |model, _| model.0 == 2); + let condition2 = model.condition(&cx, |model, _| model.0 == 3); smol::pin!(condition1, condition2); - model.update(&mut app, |model, ctx| model.inc(ctx)); + model.update(&mut cx, |model, cx| model.inc(cx)); assert_eq!(poll_once(&mut condition1).await, None); assert_eq!(poll_once(&mut condition2).await, None); - model.update(&mut app, |model, ctx| model.inc(ctx)); + model.update(&mut cx, |model, cx| model.inc(cx)); assert_eq!(poll_once(&mut condition1).await, Some(())); assert_eq!(poll_once(&mut condition2).await, None); - model.update(&mut app, |model, ctx| model.inc(ctx)); + model.update(&mut cx, |model, cx| model.inc(cx)); assert_eq!(poll_once(&mut condition2).await, Some(())); - model.update(&mut app, |_, ctx| ctx.notify()); + model.update(&mut cx, |_, cx| cx.notify()); } #[crate::test(self)] #[should_panic] - async fn test_model_condition_timeout(mut app: TestAppContext) { + async fn test_model_condition_timeout(mut cx: TestAppContext) { struct Model; impl super::Entity for Model { type Event = (); } - let model = app.add_model(|_| Model); - model.condition(&app, |_, _| false).await; + let model = cx.add_model(|_| Model); + model.condition(&cx, |_, _| false).await; } #[crate::test(self)] #[should_panic(expected = "model dropped with pending condition")] - async fn test_model_condition_panic_on_drop(mut app: TestAppContext) { + async fn test_model_condition_panic_on_drop(mut cx: TestAppContext) { struct Model; impl super::Entity for Model { type Event = (); } - let model = app.add_model(|_| Model); - let condition = model.condition(&app, |_, _| false); - app.update(|_| drop(model)); + let model = cx.add_model(|_| Model); + let condition = model.condition(&cx, |_, _| false); + cx.update(|_| drop(model)); condition.await; } #[crate::test(self)] - async fn test_view_condition(mut app: TestAppContext) { + async fn test_view_condition(mut cx: TestAppContext) { struct Counter(usize); impl super::Entity for Counter { @@ -3421,34 +3418,34 @@ mod tests { } impl Counter { - fn inc(&mut self, ctx: &mut ViewContext) { + fn inc(&mut self, cx: &mut ViewContext) { self.0 += 1; - ctx.notify(); + cx.notify(); } } - let (_, view) = app.add_window(|_| Counter(0)); + let (_, view) = cx.add_window(|_| Counter(0)); - let condition1 = view.condition(&app, |view, _| view.0 == 2); - let condition2 = view.condition(&app, |view, _| view.0 == 3); + let condition1 = view.condition(&cx, |view, _| view.0 == 2); + let condition2 = view.condition(&cx, |view, _| view.0 == 3); smol::pin!(condition1, condition2); - view.update(&mut app, |view, ctx| view.inc(ctx)); + view.update(&mut cx, |view, cx| view.inc(cx)); assert_eq!(poll_once(&mut condition1).await, None); assert_eq!(poll_once(&mut condition2).await, None); - view.update(&mut app, |view, ctx| view.inc(ctx)); + view.update(&mut cx, |view, cx| view.inc(cx)); assert_eq!(poll_once(&mut condition1).await, Some(())); assert_eq!(poll_once(&mut condition2).await, None); - view.update(&mut app, |view, ctx| view.inc(ctx)); + view.update(&mut cx, |view, cx| view.inc(cx)); assert_eq!(poll_once(&mut condition2).await, Some(())); - view.update(&mut app, |_, ctx| ctx.notify()); + view.update(&mut cx, |_, cx| cx.notify()); } #[crate::test(self)] #[should_panic] - async fn test_view_condition_timeout(mut app: TestAppContext) { + async fn test_view_condition_timeout(mut cx: TestAppContext) { struct View; impl super::Entity for View { @@ -3465,13 +3462,13 @@ mod tests { } } - let (_, view) = app.add_window(|_| View); - view.condition(&app, |_, _| false).await; + let (_, view) = cx.add_window(|_| View); + view.condition(&cx, |_, _| false).await; } #[crate::test(self)] #[should_panic(expected = "view dropped with pending condition")] - async fn test_view_condition_panic_on_drop(mut app: TestAppContext) { + async fn test_view_condition_panic_on_drop(mut cx: TestAppContext) { struct View; impl super::Entity for View { @@ -3488,92 +3485,11 @@ mod tests { } } - let window_id = app.add_window(|_| View).0; - let view = app.add_view(window_id, |_| View); + let window_id = cx.add_window(|_| View).0; + let view = cx.add_view(window_id, |_| View); - let condition = view.condition(&app, |_, _| false); - app.update(|_| drop(view)); + let condition = view.condition(&cx, |_, _| false); + cx.update(|_| drop(view)); condition.await; } - - // #[crate::test(self)] - // fn test_ui_and_window_updates() { - // struct View { - // count: usize, - // } - - // impl Entity for View { - // type Event = (); - // } - - // impl super::View for View { - // fn render<'a>(&self, _: &AppContext) -> ElementBox { - // Empty::new().boxed() - // } - - // fn ui_name() -> &'static str { - // "View" - // } - // } - - // App::test(|app| async move { - // let (window_id, _) = app.add_window(|_| View { count: 3 }); - // let view_1 = app.add_view(window_id, |_| View { count: 1 }); - // let view_2 = app.add_view(window_id, |_| View { count: 2 }); - - // // Ensure that registering for UI updates after mutating the app still gives us all the - // // updates. - // let ui_updates = Rc::new(RefCell::new(Vec::new())); - // let ui_updates_ = ui_updates.clone(); - // app.on_ui_update(move |update, _| ui_updates_.borrow_mut().push(update)); - - // assert_eq!( - // ui_updates.borrow_mut().drain(..).collect::>(), - // vec![UiUpdate::OpenWindow { - // window_id, - // width: 1024.0, - // height: 768.0, - // }] - // ); - - // let window_invalidations = Rc::new(RefCell::new(Vec::new())); - // let window_invalidations_ = window_invalidations.clone(); - // app.on_window_invalidated(window_id, move |update, _| { - // window_invalidations_.borrow_mut().push(update) - // }); - - // let view_2_id = view_2.id(); - // view_1.update(app, |view, ctx| { - // view.count = 7; - // ctx.notify(); - // drop(view_2); - // }); - - // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap(); - // assert_eq!(invalidation.updated.len(), 1); - // assert!(invalidation.updated.contains(&view_1.id())); - // assert_eq!(invalidation.removed, vec![view_2_id]); - - // let view_3 = view_1.update(app, |_, ctx| ctx.add_view(|_| View { count: 8 })); - - // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap(); - // assert_eq!(invalidation.updated.len(), 1); - // assert!(invalidation.updated.contains(&view_3.id())); - // assert!(invalidation.removed.is_empty()); - - // view_3 - // .update(app, |_, ctx| { - // ctx.spawn_local(async { 9 }, |me, output, ctx| { - // me.count = output; - // ctx.notify(); - // }) - // }) - // .await; - - // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap(); - // assert_eq!(invalidation.updated.len(), 1); - // assert!(invalidation.updated.contains(&view_3.id())); - // assert!(invalidation.removed.is_empty()); - // }); - // } } diff --git a/gpui/src/elements.rs b/gpui/src/elements.rs index f78a3f999d34e6af9b056d934f5d1bbc6a25d028..a37ee7fea5801e9864ec75194f1d7dbf3359d45a 100644 --- a/gpui/src/elements.rs +++ b/gpui/src/elements.rs @@ -38,11 +38,11 @@ use replace_with::replace_with_or_abort; use std::{any::Any, borrow::Cow}; trait AnyElement { - fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F; + fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F; fn after_layout(&mut self, _: &mut AfterLayoutContext) {} - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext); - fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool; - fn debug(&self, ctx: &DebugContext) -> serde_json::Value; + fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext); + fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool; + fn debug(&self, cx: &DebugContext) -> serde_json::Value; fn size(&self) -> Vector2F; fn metadata(&self) -> Option<&dyn Any>; @@ -55,21 +55,21 @@ pub trait Element { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState); fn after_layout( &mut self, size: Vector2F, layout: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ); fn paint( &mut self, bounds: RectF, layout: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState; fn dispatch_event( @@ -78,7 +78,7 @@ pub trait Element { bounds: RectF, layout: &mut Self::LayoutState, paint: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool; fn metadata(&self) -> Option<&dyn Any> { @@ -90,7 +90,7 @@ pub trait Element { bounds: RectF, layout: &Self::LayoutState, paint: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> serde_json::Value; fn boxed(self) -> ElementBox @@ -138,13 +138,13 @@ pub struct ElementBox { } impl AnyElement for Lifecycle { - fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F { + fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F { let mut result = None; replace_with_or_abort(self, |me| match me { Lifecycle::Init { mut element } | Lifecycle::PostLayout { mut element, .. } | Lifecycle::PostPaint { mut element, .. } => { - let (size, layout) = element.layout(constraint, ctx); + let (size, layout) = element.layout(constraint, cx); debug_assert!(size.x().is_finite()); debug_assert!(size.y().is_finite()); @@ -160,7 +160,7 @@ impl AnyElement for Lifecycle { result.unwrap() } - fn after_layout(&mut self, ctx: &mut AfterLayoutContext) { + fn after_layout(&mut self, cx: &mut AfterLayoutContext) { if let Lifecycle::PostLayout { element, size, @@ -168,13 +168,13 @@ impl AnyElement for Lifecycle { .. } = self { - element.after_layout(*size, layout, ctx); + element.after_layout(*size, layout, cx); } else { panic!("invalid element lifecycle state"); } } - fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) { + fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) { replace_with_or_abort(self, |me| { if let Lifecycle::PostLayout { mut element, @@ -184,7 +184,7 @@ impl AnyElement for Lifecycle { } = me { let bounds = RectF::new(origin, size); - let paint = element.paint(bounds, &mut layout, ctx); + let paint = element.paint(bounds, &mut layout, cx); Lifecycle::PostPaint { element, constraint, @@ -198,7 +198,7 @@ impl AnyElement for Lifecycle { }); } - fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool { + fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool { if let Lifecycle::PostPaint { element, bounds, @@ -207,7 +207,7 @@ impl AnyElement for Lifecycle { .. } = self { - element.dispatch_event(event, *bounds, layout, paint, ctx) + element.dispatch_event(event, *bounds, layout, paint, cx) } else { panic!("invalid element lifecycle state"); } @@ -229,7 +229,7 @@ impl AnyElement for Lifecycle { } } - fn debug(&self, ctx: &DebugContext) -> serde_json::Value { + fn debug(&self, cx: &DebugContext) -> serde_json::Value { match self { Lifecycle::PostPaint { element, @@ -238,7 +238,7 @@ impl AnyElement for Lifecycle { layout, paint, } => { - let mut value = element.debug(*bounds, layout, paint, ctx); + let mut value = element.debug(*bounds, layout, paint, cx); if let json::Value::Object(map) = &mut value { let mut new_map: crate::json::Map = Default::default(); @@ -258,20 +258,20 @@ impl AnyElement for Lifecycle { } impl ElementBox { - pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F { - self.element.layout(constraint, ctx) + pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F { + self.element.layout(constraint, cx) } - pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) { - self.element.after_layout(ctx); + pub fn after_layout(&mut self, cx: &mut AfterLayoutContext) { + self.element.after_layout(cx); } - pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) { - self.element.paint(origin, ctx); + pub fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) { + self.element.paint(origin, cx); } - pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool { - self.element.dispatch_event(event, ctx) + pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool { + self.element.dispatch_event(event, cx) } pub fn size(&self) -> Vector2F { @@ -282,8 +282,8 @@ impl ElementBox { self.element.metadata() } - pub fn debug(&self, ctx: &DebugContext) -> json::Value { - let mut value = self.element.debug(ctx); + pub fn debug(&self, cx: &DebugContext) -> json::Value { + let mut value = self.element.debug(cx); if let Some(name) = &self.name { if let json::Value::Object(map) = &mut value { diff --git a/gpui/src/elements/align.rs b/gpui/src/elements/align.rs index 8bb59169e2ea42ba0634bb9daf53d670b9e18de8..5b3fd5d0b51f62c7ca36ab85afe2900d783efb60 100644 --- a/gpui/src/elements/align.rs +++ b/gpui/src/elements/align.rs @@ -37,11 +37,11 @@ impl Element for Align { fn layout( &mut self, mut constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.max; constraint.min = Vector2F::zero(); - let child_size = self.child.layout(constraint, ctx); + let child_size = self.child.layout(constraint, cx); if size.x().is_infinite() { size.set_x(child_size.x()); } @@ -55,16 +55,16 @@ impl Element for Align { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - self.child.after_layout(ctx); + self.child.after_layout(cx); } fn paint( &mut self, bounds: pathfinder_geometry::rect::RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { let my_center = bounds.size() / 2.; let my_target = my_center + my_center * self.alignment; @@ -73,7 +73,7 @@ impl Element for Align { let child_target = child_center + child_center * self.alignment; self.child - .paint(bounds.origin() - (child_target - my_target), ctx); + .paint(bounds.origin() - (child_target - my_target), cx); } fn dispatch_event( @@ -82,9 +82,9 @@ impl Element for Align { _: pathfinder_geometry::rect::RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - self.child.dispatch_event(event, ctx) + self.child.dispatch_event(event, cx) } fn debug( @@ -92,13 +92,13 @@ impl Element for Align { bounds: pathfinder_geometry::rect::RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> json::Value { json!({ "type": "Align", "bounds": bounds.to_json(), "alignment": self.alignment.to_json(), - "child": self.child.debug(ctx), + "child": self.child.debug(cx), }) } } diff --git a/gpui/src/elements/canvas.rs b/gpui/src/elements/canvas.rs index a82ef50c900c1270e631ef89793b88f41f371e1d..e90c377be13c1285e5ff508e042089b6984efb46 100644 --- a/gpui/src/elements/canvas.rs +++ b/gpui/src/elements/canvas.rs @@ -51,9 +51,9 @@ where &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { - self.0(bounds, ctx) + self.0(bounds, cx) } fn after_layout( diff --git a/gpui/src/elements/constrained_box.rs b/gpui/src/elements/constrained_box.rs index a705be3612a5519d9deeba2b26f271b479f50810..3d50b70a57fb8a74c25a8b68f001acb7aa7ddf55 100644 --- a/gpui/src/elements/constrained_box.rs +++ b/gpui/src/elements/constrained_box.rs @@ -58,12 +58,12 @@ impl Element for ConstrainedBox { fn layout( &mut self, mut constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { constraint.min = constraint.min.max(self.constraint.min); constraint.max = constraint.max.min(self.constraint.max); constraint.max = constraint.max.max(constraint.min); - let size = self.child.layout(constraint, ctx); + let size = self.child.layout(constraint, cx); (size, ()) } @@ -71,18 +71,18 @@ impl Element for ConstrainedBox { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - self.child.after_layout(ctx); + self.child.after_layout(cx); } fn paint( &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { - self.child.paint(bounds.origin(), ctx); + self.child.paint(bounds.origin(), cx); } fn dispatch_event( @@ -91,9 +91,9 @@ impl Element for ConstrainedBox { _: RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - self.child.dispatch_event(event, ctx) + self.child.dispatch_event(event, cx) } fn debug( @@ -101,8 +101,8 @@ impl Element for ConstrainedBox { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> json::Value { - json!({"type": "ConstrainedBox", "set_constraint": self.constraint.to_json(), "child": self.child.debug(ctx)}) + json!({"type": "ConstrainedBox", "set_constraint": self.constraint.to_json(), "child": self.child.debug(cx)}) } } diff --git a/gpui/src/elements/container.rs b/gpui/src/elements/container.rs index d228c54d077009e0f578939299ace7f8014842bb..c0b829fbe6f881b0cf24e8c80d2bf92a16cabcb2 100644 --- a/gpui/src/elements/container.rs +++ b/gpui/src/elements/container.rs @@ -141,14 +141,14 @@ impl Element for Container { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let size_buffer = self.margin_size() + self.padding_size() + self.border_size(); let child_constraint = SizeConstraint { min: (constraint.min - size_buffer).max(Vector2F::zero()), max: (constraint.max - size_buffer).max(Vector2F::zero()), }; - let child_size = self.child.layout(child_constraint, ctx); + let child_size = self.child.layout(child_constraint, cx); (child_size + size_buffer, ()) } @@ -156,16 +156,16 @@ impl Element for Container { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - self.child.after_layout(ctx); + self.child.after_layout(cx); } fn paint( &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { let quad_bounds = RectF::from_points( bounds.origin() + vec2f(self.margin.left, self.margin.top), @@ -173,14 +173,14 @@ impl Element for Container { ); if let Some(shadow) = self.shadow.as_ref() { - ctx.scene.push_shadow(scene::Shadow { + cx.scene.push_shadow(scene::Shadow { bounds: quad_bounds + shadow.offset, corner_radius: self.corner_radius, sigma: shadow.blur, color: shadow.color, }); } - ctx.scene.push_quad(Quad { + cx.scene.push_quad(Quad { bounds: quad_bounds, background: self.background_color, border: self.border, @@ -190,7 +190,7 @@ impl Element for Container { let child_origin = quad_bounds.origin() + vec2f(self.padding.left, self.padding.top) + vec2f(self.border.left_width(), self.border.top_width()); - self.child.paint(child_origin, ctx); + self.child.paint(child_origin, cx); } fn dispatch_event( @@ -199,9 +199,9 @@ impl Element for Container { _: RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - self.child.dispatch_event(event, ctx) + self.child.dispatch_event(event, cx) } fn debug( @@ -209,7 +209,7 @@ impl Element for Container { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &crate::DebugContext, + cx: &crate::DebugContext, ) -> serde_json::Value { json!({ "type": "Container", @@ -222,7 +222,7 @@ impl Element for Container { "corner_radius": self.corner_radius, "shadow": self.shadow.to_json(), }, - "child": self.child.debug(ctx), + "child": self.child.debug(cx), }) } } diff --git a/gpui/src/elements/event_handler.rs b/gpui/src/elements/event_handler.rs index 717d7db1f673afd6cf7b5f979bf91f46c477bba7..a66778f8b7c91d979ee13eb4fd1de804702f4eb0 100644 --- a/gpui/src/elements/event_handler.rs +++ b/gpui/src/elements/event_handler.rs @@ -35,9 +35,9 @@ impl Element for EventHandler { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, ctx); + let size = self.child.layout(constraint, cx); (size, ()) } @@ -45,18 +45,18 @@ impl Element for EventHandler { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - self.child.after_layout(ctx); + self.child.after_layout(cx); } fn paint( &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { - self.child.paint(bounds.origin(), ctx); + self.child.paint(bounds.origin(), cx); } fn dispatch_event( @@ -65,16 +65,16 @@ impl Element for EventHandler { bounds: RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - if self.child.dispatch_event(event, ctx) { + if self.child.dispatch_event(event, cx) { true } else { match event { Event::LeftMouseDown { position, .. } => { if let Some(callback) = self.mouse_down.as_mut() { if bounds.contains_point(*position) { - return callback(ctx); + return callback(cx); } } false @@ -89,11 +89,11 @@ impl Element for EventHandler { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> serde_json::Value { json!({ "type": "EventHandler", - "child": self.child.debug(ctx), + "child": self.child.debug(cx), }) } } diff --git a/gpui/src/elements/flex.rs b/gpui/src/elements/flex.rs index cbce89ed2fdadb9df3eeeb8e309632d264b42a65..1ed9204de4796fc45056acaf16f550de7a181287 100644 --- a/gpui/src/elements/flex.rs +++ b/gpui/src/elements/flex.rs @@ -53,7 +53,7 @@ impl Element for Flex { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut total_flex = 0.0; let mut fixed_space = 0.0; @@ -74,7 +74,7 @@ impl Element for Flex { vec2f(constraint.max.x(), INFINITY), ), }; - let size = child.layout(child_constraint, ctx); + let size = child.layout(child_constraint, cx); fixed_space += size.along(self.axis); cross_axis_max = cross_axis_max.max(size.along(cross_axis)); } @@ -105,7 +105,7 @@ impl Element for Flex { vec2f(constraint.max.x(), child_max), ), }; - let child_size = child.layout(child_constraint, ctx); + let child_size = child.layout(child_constraint, cx); remaining_space -= child_size.along(self.axis); remaining_flex -= flex; cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); @@ -138,10 +138,10 @@ impl Element for Flex { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { for child in &mut self.children { - child.after_layout(ctx); + child.after_layout(cx); } } @@ -149,11 +149,11 @@ impl Element for Flex { &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { let mut child_origin = bounds.origin(); for child in &mut self.children { - child.paint(child_origin, ctx); + child.paint(child_origin, cx); match self.axis { Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), @@ -167,11 +167,11 @@ impl Element for Flex { _: RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { let mut handled = false; for child in &mut self.children { - handled = child.dispatch_event(event, ctx) || handled; + handled = child.dispatch_event(event, cx) || handled; } handled } @@ -181,13 +181,13 @@ impl Element for Flex { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> json::Value { json!({ "type": "Flex", "bounds": bounds.to_json(), "axis": self.axis.to_json(), - "children": self.children.iter().map(|child| child.debug(ctx)).collect::>() + "children": self.children.iter().map(|child| child.debug(cx)).collect::>() }) } } @@ -217,9 +217,9 @@ impl Element for Expanded { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, ctx); + let size = self.child.layout(constraint, cx); (size, ()) } @@ -227,18 +227,18 @@ impl Element for Expanded { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - self.child.after_layout(ctx); + self.child.after_layout(cx); } fn paint( &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { - self.child.paint(bounds.origin(), ctx) + self.child.paint(bounds.origin(), cx) } fn dispatch_event( @@ -247,9 +247,9 @@ impl Element for Expanded { _: RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - self.child.dispatch_event(event, ctx) + self.child.dispatch_event(event, cx) } fn metadata(&self) -> Option<&dyn Any> { @@ -261,12 +261,12 @@ impl Element for Expanded { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> Value { json!({ "type": "Expanded", "flex": self.metadata.flex, - "child": self.child.debug(ctx) + "child": self.child.debug(cx) }) } } diff --git a/gpui/src/elements/label.rs b/gpui/src/elements/label.rs index 02d89200dda6ac2c9e78e3db2f2679de187bc954..9a473606913b4f796698e508f8c343b970430943 100644 --- a/gpui/src/elements/label.rs +++ b/gpui/src/elements/label.rs @@ -109,20 +109,20 @@ impl Element for Label { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - let font_id = ctx + let font_id = cx .font_cache .select_font(self.family_id, &self.font_properties) .unwrap(); - let runs = self.compute_runs(&ctx.font_cache, font_id); + let runs = self.compute_runs(&cx.font_cache, font_id); let line = - ctx.text_layout_cache + cx.text_layout_cache .layout_str(self.text.as_str(), self.font_size, runs.as_slice()); let size = vec2f( line.width().max(constraint.min.x()).min(constraint.max.x()), - ctx.font_cache.line_height(font_id, self.font_size).ceil(), + cx.font_cache.line_height(font_id, self.font_size).ceil(), ); (size, line) @@ -135,12 +135,12 @@ impl Element for Label { &mut self, bounds: RectF, line: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { line.paint( bounds.origin(), RectF::new(vec2f(0., 0.), bounds.size()), - ctx, + cx, ) } @@ -160,12 +160,12 @@ impl Element for Label { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> Value { json!({ "type": "Label", "bounds": bounds.to_json(), - "font_family": ctx.font_cache.family_name(self.family_id).unwrap(), + "font_family": cx.font_cache.family_name(self.family_id).unwrap(), "font_size": self.font_size, "font_properties": self.font_properties.to_json(), "text": &self.text, @@ -191,13 +191,13 @@ mod tests { use super::*; #[crate::test(self)] - fn test_layout_label_with_highlights(app: &mut crate::MutableAppContext) { - let menlo = app.font_cache().load_family(&["Menlo"]).unwrap(); - let menlo_regular = app + fn test_layout_label_with_highlights(cx: &mut crate::MutableAppContext) { + let menlo = cx.font_cache().load_family(&["Menlo"]).unwrap(); + let menlo_regular = cx .font_cache() .select_font(menlo, &Properties::new()) .unwrap(); - let menlo_bold = app + let menlo_bold = cx .font_cache() .select_font(menlo, Properties::new().weight(Weight::BOLD)) .unwrap(); @@ -216,7 +216,7 @@ mod tests { ], ); - let runs = label.compute_runs(app.font_cache().as_ref(), menlo_regular); + let runs = label.compute_runs(cx.font_cache().as_ref(), menlo_regular); assert_eq!( runs.as_slice(), &[ diff --git a/gpui/src/elements/line_box.rs b/gpui/src/elements/line_box.rs index 83f58feea59e679b63bec5e8b16be56c5559a059..16baf6e00ba5d483891a41088248bf32fd4b1270 100644 --- a/gpui/src/elements/line_box.rs +++ b/gpui/src/elements/line_box.rs @@ -35,20 +35,20 @@ impl Element for LineBox { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - match ctx + match cx .font_cache .select_font(self.family_id, &self.font_properties) { Ok(font_id) => { - let line_height = ctx.font_cache.line_height(font_id, self.font_size); - let character_height = ctx.font_cache.ascent(font_id, self.font_size) - + ctx.font_cache.descent(font_id, self.font_size); + let line_height = cx.font_cache.line_height(font_id, self.font_size); + let character_height = cx.font_cache.ascent(font_id, self.font_size) + + cx.font_cache.descent(font_id, self.font_size); let child_max = vec2f(constraint.max.x(), character_height); let child_size = self.child.layout( SizeConstraint::new(constraint.min.min(child_max), child_max), - ctx, + cx, ); let size = vec2f(child_size.x(), line_height); (size, (line_height - character_height) / 2.) @@ -64,19 +64,19 @@ impl Element for LineBox { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - self.child.after_layout(ctx); + self.child.after_layout(cx); } fn paint( &mut self, bounds: pathfinder_geometry::rect::RectF, padding_top: &mut f32, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { self.child - .paint(bounds.origin() + vec2f(0., *padding_top), ctx); + .paint(bounds.origin() + vec2f(0., *padding_top), cx); } fn dispatch_event( @@ -85,9 +85,9 @@ impl Element for LineBox { _: pathfinder_geometry::rect::RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - self.child.dispatch_event(event, ctx) + self.child.dispatch_event(event, cx) } fn debug( @@ -95,14 +95,14 @@ impl Element for LineBox { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> serde_json::Value { json!({ "bounds": bounds.to_json(), - "font_family": ctx.font_cache.family_name(self.family_id).unwrap(), + "font_family": cx.font_cache.family_name(self.family_id).unwrap(), "font_size": self.font_size, "font_properties": self.font_properties.to_json(), - "child": self.child.debug(ctx), + "child": self.child.debug(cx), }) } } diff --git a/gpui/src/elements/mouse_event_handler.rs b/gpui/src/elements/mouse_event_handler.rs index aed9779f81a21b2e7794ba93ac51612f0ade865c..98de1f6a0f4d0a0b47f8876452c7d2a067967ced 100644 --- a/gpui/src/elements/mouse_event_handler.rs +++ b/gpui/src/elements/mouse_event_handler.rs @@ -18,13 +18,13 @@ pub struct MouseState { } impl MouseEventHandler { - pub fn new(id: usize, ctx: &AppContext, render_child: F) -> Self + pub fn new(id: usize, cx: &AppContext, render_child: F) -> Self where Tag: 'static, F: FnOnce(MouseState) -> ElementBox, { - let state_handle = ctx.value::(id); - let state = state_handle.read(ctx, |state| *state); + let state_handle = cx.value::(id); + let state = state_handle.read(cx, |state| *state); let child = render_child(state); Self { state: state_handle, @@ -46,27 +46,27 @@ impl Element for MouseEventHandler { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - (self.child.layout(constraint, ctx), ()) + (self.child.layout(constraint, cx), ()) } fn after_layout( &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - self.child.after_layout(ctx); + self.child.after_layout(cx); } fn paint( &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { - self.child.paint(bounds.origin(), ctx); + self.child.paint(bounds.origin(), cx); } fn dispatch_event( @@ -75,18 +75,18 @@ impl Element for MouseEventHandler { bounds: RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { let click_handler = self.click_handler.as_mut(); - let handled_in_child = self.child.dispatch_event(event, ctx); + let handled_in_child = self.child.dispatch_event(event, cx); - self.state.update(ctx.app, |state| match event { + self.state.update(cx.app, |state| match event { Event::MouseMoved { position } => { let mouse_in = bounds.contains_point(*position); if state.hovered != mouse_in { state.hovered = mouse_in; - ctx.notify(); + cx.notify(); true } else { handled_in_child @@ -95,7 +95,7 @@ impl Element for MouseEventHandler { Event::LeftMouseDown { position, .. } => { if !handled_in_child && bounds.contains_point(*position) { state.clicked = true; - ctx.notify(); + cx.notify(); true } else { handled_in_child @@ -104,10 +104,10 @@ impl Element for MouseEventHandler { Event::LeftMouseUp { position, .. } => { if !handled_in_child && state.clicked { state.clicked = false; - ctx.notify(); + cx.notify(); if let Some(handler) = click_handler { if bounds.contains_point(*position) { - handler(ctx); + handler(cx); } } true @@ -124,11 +124,11 @@ impl Element for MouseEventHandler { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> serde_json::Value { json!({ "type": "MouseEventHandler", - "child": self.child.debug(ctx), + "child": self.child.debug(cx), }) } } diff --git a/gpui/src/elements/stack.rs b/gpui/src/elements/stack.rs index 6fdae680108b8fc7bcc6d5d9d7ba9babbad2c40f..cfc4d9cc6cfc486a55d26f9c4df333bfe47b346b 100644 --- a/gpui/src/elements/stack.rs +++ b/gpui/src/elements/stack.rs @@ -24,11 +24,11 @@ impl Element for Stack { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.min; for child in &mut self.children { - size = size.max(child.layout(constraint, ctx)); + size = size.max(child.layout(constraint, cx)); } (size, ()) } @@ -37,10 +37,10 @@ impl Element for Stack { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { for child in &mut self.children { - child.after_layout(ctx); + child.after_layout(cx); } } @@ -48,12 +48,12 @@ impl Element for Stack { &mut self, bounds: RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { for child in &mut self.children { - ctx.scene.push_layer(None); - child.paint(bounds.origin(), ctx); - ctx.scene.pop_layer(); + cx.scene.push_layer(None); + child.paint(bounds.origin(), cx); + cx.scene.pop_layer(); } } @@ -63,10 +63,10 @@ impl Element for Stack { _: RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { for child in self.children.iter_mut().rev() { - if child.dispatch_event(event, ctx) { + if child.dispatch_event(event, cx) { return true; } } @@ -78,12 +78,12 @@ impl Element for Stack { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> json::Value { json!({ "type": "Stack", "bounds": bounds.to_json(), - "children": self.children.iter().map(|child| child.debug(ctx)).collect::>() + "children": self.children.iter().map(|child| child.debug(cx)).collect::>() }) } } diff --git a/gpui/src/elements/svg.rs b/gpui/src/elements/svg.rs index b52112f65c664234e81db93bdce647f8291d5769..855d30b1a3b619f902b06a354100dcebaac5276e 100644 --- a/gpui/src/elements/svg.rs +++ b/gpui/src/elements/svg.rs @@ -38,9 +38,9 @@ impl Element for Svg { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - match ctx.asset_cache.svg(&self.path) { + match cx.asset_cache.svg(&self.path) { Ok(tree) => { let size = if constraint.max.x().is_infinite() && constraint.max.y().is_infinite() { let rect = from_usvg_rect(tree.svg_node().view_box.rect); @@ -69,9 +69,9 @@ impl Element for Svg { fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) { } - fn paint(&mut self, bounds: RectF, svg: &mut Self::LayoutState, ctx: &mut PaintContext) { + fn paint(&mut self, bounds: RectF, svg: &mut Self::LayoutState, cx: &mut PaintContext) { if let Some(svg) = svg.clone() { - ctx.scene.push_icon(scene::Icon { + cx.scene.push_icon(scene::Icon { bounds, svg, path: self.path.clone(), diff --git a/gpui/src/elements/uniform_list.rs b/gpui/src/elements/uniform_list.rs index 0b1d51d9aca28a31732ebbd056945f12a5785fe7..69cc55217bbcc83896257614e4b20e1650909e0a 100644 --- a/gpui/src/elements/uniform_list.rs +++ b/gpui/src/elements/uniform_list.rs @@ -72,7 +72,7 @@ where delta: Vector2F, precise: bool, scroll_max: f32, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { if !precise { todo!("still need to handle non-precise scroll events from a mouse wheel"); @@ -80,7 +80,7 @@ where let mut state = self.state.0.lock(); state.scroll_top = (state.scroll_top - delta.y()).max(0.0).min(scroll_max); - ctx.dispatch_action("uniform_list:scroll", state.scroll_top); + cx.dispatch_action("uniform_list:scroll", state.scroll_top); true } @@ -119,7 +119,7 @@ where fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { if constraint.max.y().is_infinite() { unimplemented!( @@ -133,9 +133,9 @@ where let mut scroll_max = 0.; let mut items = Vec::new(); - (self.append_items)(0..1, &mut items, ctx.app); + (self.append_items)(0..1, &mut items, cx.app); if let Some(first_item) = items.first_mut() { - let mut item_size = first_item.layout(item_constraint, ctx); + let mut item_size = first_item.layout(item_constraint, cx); item_size.set_x(size.x()); item_constraint.min = item_size; item_constraint.max = item_size; @@ -155,9 +155,9 @@ where self.item_count, start + (size.y() / item_height).ceil() as usize + 1, ); - (self.append_items)(start..end, &mut items, ctx.app); + (self.append_items)(start..end, &mut items, cx.app); for item in &mut items { - item.layout(item_constraint, ctx); + item.layout(item_constraint, cx); } } @@ -175,10 +175,10 @@ where &mut self, _: Vector2F, layout: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { for item in &mut layout.items { - item.after_layout(ctx); + item.after_layout(cx); } } @@ -186,19 +186,19 @@ where &mut self, bounds: RectF, layout: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { - ctx.scene.push_layer(Some(bounds)); + cx.scene.push_layer(Some(bounds)); let mut item_origin = bounds.origin() - vec2f(0.0, self.state.scroll_top() % layout.item_height); for item in &mut layout.items { - item.paint(item_origin, ctx); + item.paint(item_origin, cx); item_origin += vec2f(0.0, layout.item_height); } - ctx.scene.pop_layer(); + cx.scene.pop_layer(); } fn dispatch_event( @@ -207,11 +207,11 @@ where bounds: RectF, layout: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { let mut handled = false; for item in &mut layout.items { - handled = item.dispatch_event(event, ctx) || handled; + handled = item.dispatch_event(event, cx) || handled; } match event { @@ -221,7 +221,7 @@ where precise, } => { if bounds.contains_point(*position) { - if self.scroll(*position, *delta, *precise, layout.scroll_max, ctx) { + if self.scroll(*position, *delta, *precise, layout.scroll_max, cx) { handled = true; } } @@ -237,14 +237,14 @@ where bounds: RectF, layout: &Self::LayoutState, _: &Self::PaintState, - ctx: &crate::DebugContext, + cx: &crate::DebugContext, ) -> json::Value { json!({ "type": "UniformList", "bounds": bounds.to_json(), "scroll_max": layout.scroll_max, "item_height": layout.item_height, - "items": layout.items.iter().map(|item| item.debug(ctx)).collect::>() + "items": layout.items.iter().map(|item| item.debug(cx)).collect::>() }) } diff --git a/gpui/src/keymap.rs b/gpui/src/keymap.rs index e38beade8c657a15d9f56f230c55b19df5547679..a3a2cbf58c1078d9e20a9b2975f4bf7cdc8c9a25 100644 --- a/gpui/src/keymap.rs +++ b/gpui/src/keymap.rs @@ -98,12 +98,12 @@ impl Matcher { &mut self, keystroke: Keystroke, view_id: usize, - ctx: &Context, + cx: &Context, ) -> MatchResult { let pending = self.pending.entry(view_id).or_default(); if let Some(pending_ctx) = pending.context.as_ref() { - if pending_ctx != ctx { + if pending_ctx != cx { pending.keystrokes.clear(); } } @@ -113,11 +113,7 @@ impl Matcher { let mut retain_pending = false; for binding in self.keymap.0.iter().rev() { if binding.keystrokes.starts_with(&pending.keystrokes) - && binding - .context - .as_ref() - .map(|c| c.eval(ctx)) - .unwrap_or(true) + && binding.context.as_ref().map(|c| c.eval(cx)).unwrap_or(true) { if binding.keystrokes.len() == pending.keystrokes.len() { self.pending.remove(&view_id); @@ -127,7 +123,7 @@ impl Matcher { }; } else { retain_pending = true; - pending.context = Some(ctx.clone()); + pending.context = Some(cx.clone()); } } } @@ -312,22 +308,20 @@ impl ContextPredicate { } } - fn eval(&self, ctx: &Context) -> bool { + fn eval(&self, cx: &Context) -> bool { match self { - Self::Identifier(name) => ctx.set.contains(name.as_str()), - Self::Equal(left, right) => ctx + Self::Identifier(name) => cx.set.contains(name.as_str()), + Self::Equal(left, right) => cx .map .get(left) .map(|value| value == right) .unwrap_or(false), - Self::NotEqual(left, right) => ctx - .map - .get(left) - .map(|value| value != right) - .unwrap_or(true), - Self::Not(pred) => !pred.eval(ctx), - Self::And(left, right) => left.eval(ctx) && right.eval(ctx), - Self::Or(left, right) => left.eval(ctx) || right.eval(ctx), + Self::NotEqual(left, right) => { + cx.map.get(left).map(|value| value != right).unwrap_or(true) + } + Self::Not(pred) => !pred.eval(cx), + Self::And(left, right) => left.eval(cx) && right.eval(cx), + Self::Or(left, right) => left.eval(cx) || right.eval(cx), } } } @@ -488,10 +482,10 @@ mod tests { &mut self, keystroke: &str, view_id: usize, - ctx: &Context, + cx: &Context, ) -> Option<(String, Option)> { if let MatchResult::Action { name, arg } = - self.push_keystroke(Keystroke::parse(keystroke).unwrap(), view_id, ctx) + self.push_keystroke(Keystroke::parse(keystroke).unwrap(), view_id, cx) { Some((name, arg.and_then(|arg| arg.downcast_ref::().cloned()))) } else { diff --git a/gpui/src/platform/mac/fonts.rs b/gpui/src/platform/mac/fonts.rs index ac455b93b997a3086c466d905cc229930e6de800..b1605c8b0bad6328fca5c991d127396c7ee5a030 100644 --- a/gpui/src/platform/mac/fonts.rs +++ b/gpui/src/platform/mac/fonts.rs @@ -145,7 +145,7 @@ impl FontSystemState { // Make room for subpixel variants. let bounds = RectI::new(bounds.origin(), bounds.size() + vec2i(1, 1)); let mut pixels = vec![0; bounds.width() as usize * bounds.height() as usize]; - let ctx = CGContext::create_bitmap_context( + let cx = CGContext::create_bitmap_context( Some(pixels.as_mut_ptr() as *mut _), bounds.width() as usize, bounds.height() as usize, @@ -157,9 +157,9 @@ impl FontSystemState { // Move the origin to bottom left and account for scaling, this // makes drawing text consistent with the font-kit's raster_bounds. - ctx.translate(0.0, bounds.height() as CGFloat); + cx.translate(0.0, bounds.height() as CGFloat); let transform = scale.translate(-bounds.origin().to_f32()); - ctx.set_text_matrix(&CGAffineTransform { + cx.set_text_matrix(&CGAffineTransform { a: transform.matrix.m11() as CGFloat, b: -transform.matrix.m21() as CGFloat, c: -transform.matrix.m12() as CGFloat, @@ -168,9 +168,9 @@ impl FontSystemState { ty: -transform.vector.y() as CGFloat, }); - ctx.set_font(&font.native_font().copy_to_CGFont()); - ctx.set_font_size(font_size as CGFloat); - ctx.show_glyphs_at_positions( + cx.set_font(&font.native_font().copy_to_CGFont()); + cx.set_font_size(font_size as CGFloat); + cx.show_glyphs_at_positions( &[glyph_id as CGGlyph], &[CGPoint::new( (subpixel_shift.x() / scale_factor) as CGFloat, diff --git a/gpui/src/presenter.rs b/gpui/src/presenter.rs index 8fdf94de005bf133e015a8947c60e8ea5fa5245a..a6e37097c08229f0363071823e5a2af93134a06d 100644 --- a/gpui/src/presenter.rs +++ b/gpui/src/presenter.rs @@ -31,11 +31,11 @@ impl Presenter { font_cache: Arc, text_layout_cache: TextLayoutCache, asset_cache: Arc, - app: &MutableAppContext, + cx: &MutableAppContext, ) -> Self { Self { window_id, - rendered_views: app.render_views(window_id), + rendered_views: cx.render_views(window_id), parents: HashMap::new(), font_cache, text_layout_cache, @@ -55,7 +55,7 @@ impl Presenter { path } - pub fn invalidate(&mut self, mut invalidation: WindowInvalidation, app: &AppContext) { + pub fn invalidate(&mut self, mut invalidation: WindowInvalidation, cx: &AppContext) { for view_id in invalidation.removed { invalidation.updated.remove(&view_id); self.rendered_views.remove(&view_id); @@ -63,7 +63,7 @@ impl Presenter { } for view_id in invalidation.updated { self.rendered_views - .insert(view_id, app.render_view(self.window_id, view_id).unwrap()); + .insert(view_id, cx.render_view(self.window_id, view_id).unwrap()); } } @@ -71,25 +71,25 @@ impl Presenter { &mut self, window_size: Vector2F, scale_factor: f32, - app: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Scene { let mut scene = Scene::new(scale_factor); - if let Some(root_view_id) = app.root_view_id(self.window_id) { - self.layout(window_size, app.as_ref()); - self.after_layout(app); - let mut ctx = PaintContext { + if let Some(root_view_id) = cx.root_view_id(self.window_id) { + self.layout(window_size, cx.as_ref()); + self.after_layout(cx); + let mut paint_cx = PaintContext { scene: &mut scene, font_cache: &self.font_cache, text_layout_cache: &self.text_layout_cache, rendered_views: &mut self.rendered_views, - app: app.as_ref(), + app: cx.as_ref(), }; - ctx.paint(root_view_id, Vector2F::zero()); + paint_cx.paint(root_view_id, Vector2F::zero()); self.text_layout_cache.finish_frame(); if let Some(event) = self.last_mouse_moved_event.clone() { - self.dispatch_event(event, app) + self.dispatch_event(event, cx) } } else { log::error!("could not find root_view_id for window {}", self.window_id); @@ -98,8 +98,8 @@ impl Presenter { scene } - fn layout(&mut self, size: Vector2F, app: &AppContext) { - if let Some(root_view_id) = app.root_view_id(self.window_id) { + fn layout(&mut self, size: Vector2F, cx: &AppContext) { + if let Some(root_view_id) = cx.root_view_id(self.window_id) { let mut layout_ctx = LayoutContext { rendered_views: &mut self.rendered_views, parents: &mut self.parents, @@ -107,49 +107,49 @@ impl Presenter { text_layout_cache: &self.text_layout_cache, asset_cache: &self.asset_cache, view_stack: Vec::new(), - app, + app: cx, }; layout_ctx.layout(root_view_id, SizeConstraint::strict(size)); } } - fn after_layout(&mut self, app: &mut MutableAppContext) { - if let Some(root_view_id) = app.root_view_id(self.window_id) { - let mut ctx = AfterLayoutContext { + fn after_layout(&mut self, cx: &mut MutableAppContext) { + if let Some(root_view_id) = cx.root_view_id(self.window_id) { + let mut layout_cx = AfterLayoutContext { rendered_views: &mut self.rendered_views, font_cache: &self.font_cache, text_layout_cache: &self.text_layout_cache, - app, + app: cx, }; - ctx.after_layout(root_view_id); + layout_cx.after_layout(root_view_id); } } - pub fn dispatch_event(&mut self, event: Event, app: &mut MutableAppContext) { - if let Some(root_view_id) = app.root_view_id(self.window_id) { + pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) { + if let Some(root_view_id) = cx.root_view_id(self.window_id) { if matches!(event, Event::MouseMoved { .. }) { self.last_mouse_moved_event = Some(event.clone()); } - let mut ctx = EventContext { + let mut event_cx = EventContext { rendered_views: &mut self.rendered_views, actions: Default::default(), font_cache: &self.font_cache, text_layout_cache: &self.text_layout_cache, view_stack: Default::default(), invalidated_views: Default::default(), - app: app.as_ref(), + app: cx.as_ref(), }; - ctx.dispatch_event(root_view_id, &event); + event_cx.dispatch_event(root_view_id, &event); - let invalidated_views = ctx.invalidated_views; - let actions = ctx.actions; + let invalidated_views = event_cx.invalidated_views; + let actions = event_cx.actions; for view_id in invalidated_views { - app.notify_view(self.window_id, view_id); + cx.notify_view(self.window_id, view_id); } for action in actions { - app.dispatch_action_any( + cx.dispatch_action_any( self.window_id, &action.path, action.name, @@ -159,14 +159,14 @@ impl Presenter { } } - pub fn debug_elements(&self, ctx: &AppContext) -> Option { - ctx.root_view_id(self.window_id) + pub fn debug_elements(&self, cx: &AppContext) -> Option { + cx.root_view_id(self.window_id) .and_then(|root_view_id| self.rendered_views.get(&root_view_id)) .map(|root_element| { root_element.debug(&DebugContext { rendered_views: &self.rendered_views, font_cache: &self.font_cache, - app: ctx, + app: cx, }) }) } @@ -380,9 +380,9 @@ impl Element for ChildView { fn layout( &mut self, constraint: SizeConstraint, - ctx: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { - let size = ctx.layout(self.view_id, constraint); + let size = cx.layout(self.view_id, constraint); (size, ()) } @@ -390,18 +390,18 @@ impl Element for ChildView { &mut self, _: Vector2F, _: &mut Self::LayoutState, - ctx: &mut AfterLayoutContext, + cx: &mut AfterLayoutContext, ) { - ctx.after_layout(self.view_id); + cx.after_layout(self.view_id); } fn paint( &mut self, bounds: pathfinder_geometry::rect::RectF, _: &mut Self::LayoutState, - ctx: &mut PaintContext, + cx: &mut PaintContext, ) -> Self::PaintState { - ctx.paint(self.view_id, bounds.origin()); + cx.paint(self.view_id, bounds.origin()); } fn dispatch_event( @@ -410,9 +410,9 @@ impl Element for ChildView { _: pathfinder_geometry::rect::RectF, _: &mut Self::LayoutState, _: &mut Self::PaintState, - ctx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - ctx.dispatch_event(self.view_id, event) + cx.dispatch_event(self.view_id, event) } fn debug( @@ -420,14 +420,14 @@ impl Element for ChildView { bounds: pathfinder_geometry::rect::RectF, _: &Self::LayoutState, _: &Self::PaintState, - ctx: &DebugContext, + cx: &DebugContext, ) -> serde_json::Value { json!({ "type": "ChildView", "view_id": self.view_id, "bounds": bounds.to_json(), - "child": if let Some(view) = ctx.rendered_views.get(&self.view_id) { - view.debug(ctx) + "child": if let Some(view) = cx.rendered_views.get(&self.view_id) { + view.debug(cx) } else { json!(null) } @@ -441,9 +441,9 @@ mod tests { // fn test_responder_chain() { // let settings = settings_rx(None); // let mut app = App::new().unwrap(); - // let workspace = app.add_model(|ctx| Workspace::new(Vec::new(), ctx)); + // let workspace = app.add_model(|cx| Workspace::new(Vec::new(), cx)); // let (window_id, workspace_view) = - // app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx)); + // app.add_window(|cx| WorkspaceView::new(workspace.clone(), settings, cx)); // let invalidations = Rc::new(RefCell::new(Vec::new())); // let invalidations_ = invalidations.clone(); @@ -451,8 +451,8 @@ mod tests { // invalidations_.borrow_mut().push(invalidation) // }); - // let active_pane_id = workspace_view.update(&mut app, |view, ctx| { - // ctx.focus(view.active_pane()); + // let active_pane_id = workspace_view.update(&mut app, |view, cx| { + // cx.focus(view.active_pane()); // view.active_pane().id() // }); @@ -468,7 +468,7 @@ mod tests { // } // assert_eq!( - // presenter.responder_chain(app.ctx()).unwrap(), + // presenter.responder_chain(app.cx()).unwrap(), // vec![workspace_view.id(), active_pane_id] // ); // }); diff --git a/gpui/src/text_layout.rs b/gpui/src/text_layout.rs index af30630fb24b8020bc313b2b3526205334ad2f0d..dfba1810233fb4874210029eea1c2d52b441a750 100644 --- a/gpui/src/text_layout.rs +++ b/gpui/src/text_layout.rs @@ -200,7 +200,7 @@ impl Line { } } - pub fn paint(&self, origin: Vector2F, visible_bounds: RectF, ctx: &mut PaintContext) { + pub fn paint(&self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) { let padding_top = (visible_bounds.height() - self.layout.ascent - self.layout.descent) / 2.; let baseline_origin = vec2f(0., padding_top + self.layout.ascent); @@ -209,7 +209,7 @@ impl Line { let mut color = ColorU::black(); for run in &self.layout.runs { - let max_glyph_width = ctx + let max_glyph_width = cx .font_cache .bounding_box(run.font_id, self.layout.font_size) .x(); @@ -234,7 +234,7 @@ impl Line { } } - ctx.scene.push_glyph(scene::Glyph { + cx.scene.push_glyph(scene::Glyph { font_id: run.font_id, font_size: self.layout.font_size, id: glyph.id, diff --git a/gpui_macros/src/lib.rs b/gpui_macros/src/lib.rs index cdd4cacb803107baca67fe83359571736d547bf0..c7218387dffe627a1f40084a670f8702628beccc 100644 --- a/gpui_macros/src/lib.rs +++ b/gpui_macros/src/lib.rs @@ -34,8 +34,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { fn #outer_fn_name() { #inner_fn - #namespace::App::test_async((), move |ctx| async { - #inner_fn_name(ctx).await; + #namespace::App::test_async((), move |cx| async { + #inner_fn_name(cx).await; }); } } @@ -45,8 +45,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { fn #outer_fn_name() { #inner_fn - #namespace::App::test((), |ctx| { - #inner_fn_name(ctx); + #namespace::App::test((), |cx| { + #inner_fn_name(cx); }); } }