Detailed changes
@@ -23,7 +23,7 @@ use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
marker::PhantomData,
- ops::Deref,
+ ops::{Deref, DerefMut},
path::{Path, PathBuf},
rc::{self, Rc},
sync::{Arc, Weak},
@@ -2110,6 +2110,12 @@ impl<M> Deref for ViewContext<'_, M> {
}
}
+impl<M> DerefMut for ViewContext<'_, M> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.app
+ }
+}
+
impl<M> AsMut<MutableAppContext> for ViewContext<'_, M> {
fn as_mut(&mut self) -> &mut MutableAppContext {
self.app
@@ -4,7 +4,7 @@ mod element;
pub mod movement;
use crate::{
- settings::{Settings, StyleId},
+ settings::{Settings, StyleId, Theme},
util::{post_inc, Bias},
workspace,
worktree::{File, Worktree},
@@ -15,10 +15,10 @@ 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,
+ color::ColorU, font_cache::FamilyId, 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::{prelude::Stream, watch};
@@ -384,6 +384,15 @@ pub struct Editor {
single_line: bool,
}
+struct Snapshot {
+ display_snapshot: DisplayMapSnapshot,
+ gutter_visible: bool,
+ scroll_position: Vector2F,
+ theme: Arc<Theme>,
+ font_family: FamilyId,
+ font_size: f32,
+}
+
struct AddSelectionsState {
above: bool,
stack: Vec<usize>,
@@ -410,8 +419,7 @@ impl Editor {
) -> Self {
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().clone(), None, cx.as_ref());
+ let display_map = DisplayMap::new(buffer.clone(), settings.borrow().clone(), None, cx);
let mut notifications = display_map.notifications();
cx.spawn(|this, mut cx| async move {
@@ -458,8 +466,17 @@ impl Editor {
&self.buffer
}
- pub fn is_gutter_visible(&self) -> bool {
- !self.single_line
+ pub fn snapshot(&mut self, cx: &mut MutableAppContext) -> Snapshot {
+ let settings = self.settings.borrow();
+
+ Snapshot {
+ display_snapshot: self.display_map.snapshot(cx),
+ gutter_visible: !self.single_line,
+ scroll_position: *self.scroll_position.lock(),
+ theme: settings.theme.clone(),
+ font_family: settings.buffer_font_family,
+ font_size: settings.buffer_font_size,
+ }
}
fn scroll(&mut self, scroll_position: &Vector2F, cx: &mut ViewContext<Self>) {
@@ -481,7 +498,7 @@ impl Editor {
&self,
viewport_height: f32,
line_height: f32,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> bool {
let display_map = self.display_map.snapshot(cx);
let mut scroll_position = self.scroll_position.lock();
@@ -541,7 +558,7 @@ impl Editor {
scroll_width: f32,
max_glyph_width: f32,
layouts: &[text_layout::Line],
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) {
let display_map = self.display_map.snapshot(cx);
let mut target_left = std::f32::INFINITY;
@@ -591,7 +608,7 @@ impl Editor {
cx.emit(Event::Activate);
}
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let cursor = display_map.anchor_before(position, Bias::Left);
let selection = Selection {
id: post_inc(&mut self.next_selection_id),
@@ -616,7 +633,7 @@ impl Editor {
cx: &mut ViewContext<Self>,
) {
let buffer = self.buffer.read(cx);
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let cursor = display_map.anchor_before(position, Bias::Left);
if let Some(selection) = self.pending_selection.as_mut() {
selection.set_head(buffer, cursor);
@@ -694,7 +711,7 @@ impl Editor {
T: IntoIterator<Item = &'a Range<DisplayPoint>>,
{
let mut selections = Vec::new();
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
for range in ranges {
let mut start = range.start;
let mut end = range.end;
@@ -769,7 +786,7 @@ impl Editor {
pub fn backspace(&mut self, _: &(), cx: &mut ViewContext<Self>) {
self.start_transaction(cx);
let mut selections = self.selections(cx.as_ref()).to_vec();
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
{
let buffer = self.buffer.read(cx);
for selection in &mut selections {
@@ -791,7 +808,7 @@ impl Editor {
pub fn delete(&mut self, _: &(), cx: &mut ViewContext<Self>) {
self.start_transaction(cx);
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut selections = self.selections(cx.as_ref()).to_vec();
{
let buffer = self.buffer.read(cx);
@@ -821,7 +838,7 @@ impl Editor {
let mut new_cursors = Vec::new();
let mut edit_ranges = Vec::new();
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut selections = self.selections(app).iter().peekable();
while let Some(selection) = selections.next() {
let (mut rows, _) = selection.buffer_rows_for_display_rows(false, &display_map);
@@ -902,7 +919,7 @@ impl Editor {
self.update_selections(selections.clone(), false, cx);
let buffer = self.buffer.read(cx);
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut edits = Vec::new();
let mut selections_iter = selections.iter_mut().peekable();
@@ -952,7 +969,7 @@ impl Editor {
let app = cx.as_ref();
let buffer = self.buffer.read(cx);
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut edits = Vec::new();
let mut new_selection_ranges = Vec::new();
@@ -1037,7 +1054,7 @@ impl Editor {
let app = cx.as_ref();
let buffer = self.buffer.read(cx);
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut edits = Vec::new();
let mut new_selection_ranges = Vec::new();
@@ -1250,8 +1267,8 @@ impl Editor {
}
pub fn move_left(&mut self, _: &(), cx: &mut ViewContext<Self>) {
+ let display_map = self.display_map.snapshot(cx);
let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
let mut selections = self.selections(app).to_vec();
{
for selection in &mut selections {
@@ -1274,7 +1291,7 @@ impl Editor {
}
pub fn select_left(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut selections = self.selections(cx.as_ref()).to_vec();
{
let buffer = self.buffer.read(cx);
@@ -1290,7 +1307,7 @@ impl Editor {
}
pub fn move_right(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut selections = self.selections(cx.as_ref()).to_vec();
{
for selection in &mut selections {
@@ -1313,7 +1330,7 @@ impl Editor {
}
pub fn select_right(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut selections = self.selections(cx.as_ref()).to_vec();
{
let app = cx.as_ref();
@@ -1330,7 +1347,7 @@ impl Editor {
}
pub fn move_up(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
if self.single_line {
cx.propagate_action();
} else {
@@ -1356,7 +1373,7 @@ impl Editor {
}
pub fn select_up(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut selections = self.selections(cx.as_ref()).to_vec();
{
let app = cx.as_ref();
@@ -1375,7 +1392,7 @@ impl Editor {
if self.single_line {
cx.propagate_action();
} else {
- let display_map = self.display_map.snapshot(cx.as_ref());
+ let display_map = self.display_map.snapshot(cx);
let mut selections = self.selections(cx.as_ref()).to_vec();
{
for selection in &mut selections {
@@ -1398,8 +1415,8 @@ impl Editor {
}
pub fn select_down(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let display_map = self.display_map.snapshot(cx.as_ref());
- let mut selections = self.selections(cx.as_ref()).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
let app = cx.as_ref();
let buffer = self.buffer.read(app);
@@ -1414,9 +1431,8 @@ impl Editor {
}
pub fn move_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
for selection in &mut selections {
let head = selection.head().to_display_point(&display_map);
@@ -1432,9 +1448,8 @@ impl Editor {
}
pub fn select_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
let buffer = self.buffer.read(cx);
for selection in &mut selections {
@@ -1456,9 +1471,8 @@ impl Editor {
}
pub fn move_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
for selection in &mut selections {
let head = selection.head().to_display_point(&display_map);
@@ -1474,9 +1488,8 @@ impl Editor {
}
pub fn select_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
let buffer = self.buffer.read(cx);
for selection in &mut selections {
@@ -1498,9 +1511,8 @@ impl Editor {
}
pub fn move_to_beginning_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
for selection in &mut selections {
let head = selection.head().to_display_point(&display_map);
@@ -1520,9 +1532,8 @@ impl Editor {
toggle_indent: &bool,
cx: &mut ViewContext<Self>,
) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
let buffer = self.buffer.read(cx);
for selection in &mut selections {
@@ -1545,9 +1556,8 @@ impl Editor {
}
pub fn move_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
for selection in &mut selections {
let head = selection.head().to_display_point(&display_map);
@@ -1563,9 +1573,8 @@ impl Editor {
}
pub fn select_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).to_vec();
{
let buffer = self.buffer.read(cx);
for selection in &mut selections {
@@ -1643,10 +1652,9 @@ impl Editor {
}
pub fn select_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let buffer = self.buffer.read(app);
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let buffer = self.buffer.read(cx);
+ let mut selections = self.selections(cx).to_vec();
let max_point = buffer.max_point();
for selection in &mut selections {
let (rows, _) = selection.buffer_rows_for_display_rows(true, &display_map);
@@ -1706,9 +1714,8 @@ impl Editor {
}
fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- let mut selections = self.selections(app).to_vec();
+ let display_map = self.display_map.snapshot(cx);
+ let mut selections = self.selections(cx).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(&display_map).sorted();
@@ -1800,13 +1807,12 @@ impl Editor {
}
pub fn select_larger_syntax_node(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let buffer = self.buffer.read(app);
- let display_map = self.display_map.snapshot(app);
+ let display_map = self.display_map.snapshot(cx);
+ let buffer = self.buffer.read(cx);
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 old_selections = self.selections(cx).to_vec();
let mut new_selection_ranges = Vec::new();
for selection in &old_selections {
let old_range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
@@ -1916,10 +1922,10 @@ impl Editor {
&'a self,
set_id: SelectionSetId,
range: Range<DisplayPoint>,
- cx: &'a AppContext,
+ cx: &'a mut MutableAppContext,
) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
- let buffer = self.buffer.read(cx);
let display_map = self.display_map.snapshot(cx);
+ let buffer = self.buffer.read(cx);
let selections = &buffer.selection_set(set_id).unwrap().selections;
let start = display_map.anchor_before(range.start, Bias::Left);
let start_index = self.selection_insertion_index(selections, &start, cx);
@@ -2042,9 +2048,8 @@ impl Editor {
pub fn fold(&mut self, _: &(), cx: &mut ViewContext<Self>) {
let mut fold_ranges = Vec::new();
- let app = cx.as_ref();
- let display_map = self.display_map.snapshot(app);
- for selection in self.selections(app) {
+ let display_map = self.display_map.snapshot(cx);
+ for selection in self.selections(cx) {
let range = selection.display_range(&display_map).sorted();
let buffer_start_row = range.start.to_buffer_point(&display_map, Bias::Left).row;
@@ -2065,11 +2070,10 @@ impl Editor {
}
pub fn unfold(&mut self, _: &(), cx: &mut ViewContext<Self>) {
- let app = cx.as_ref();
- let buffer = self.buffer.read(app);
- let display_map = self.display_map.snapshot(app);
+ let display_map = self.display_map.snapshot(cx);
+ let buffer = self.buffer.read(cx);
let ranges = self
- .selections(app)
+ .selections(cx)
.iter()
.map(|s| {
let range = s.display_range(&display_map).sorted();
@@ -2138,7 +2142,7 @@ impl Editor {
fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
if !ranges.is_empty() {
- self.display_map.fold(ranges, cx.as_ref());
+ self.display_map.fold(ranges, cx);
*self.autoscroll_requested.lock() = true;
cx.notify();
}
@@ -2146,25 +2150,25 @@ impl Editor {
fn unfold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
if !ranges.is_empty() {
- self.display_map.unfold(ranges, cx.as_ref());
+ self.display_map.unfold(ranges, cx);
*self.autoscroll_requested.lock() = true;
cx.notify();
}
}
- pub fn line_len(&self, display_row: u32, cx: &AppContext) -> u32 {
+ pub fn line_len(&self, display_row: u32, cx: &mut MutableAppContext) -> u32 {
self.display_map.snapshot(cx).line_len(display_row)
}
- pub fn longest_row(&self, cx: &AppContext) -> u32 {
+ pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
self.display_map.snapshot(cx).longest_row()
}
- pub fn max_point(&self, cx: &AppContext) -> DisplayPoint {
+ pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
self.display_map.snapshot(cx).max_point()
}
- pub fn text(&self, cx: &AppContext) -> String {
+ pub fn text(&self, cx: &mut MutableAppContext) -> String {
self.display_map.snapshot(cx).text()
}
@@ -2172,34 +2176,104 @@ impl Editor {
self.settings.borrow().buffer_font_size
}
+ pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) {
+ self.display_map.set_wrap_width(Some(width), cx);
+ }
+
+ fn next_blink_epoch(&mut self) -> usize {
+ self.blink_epoch += 1;
+ self.blink_epoch
+ }
+
+ fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
+ self.cursors_visible = true;
+ cx.notify();
+
+ let epoch = self.next_blink_epoch();
+ cx.spawn(|this, mut cx| {
+ let this = this.downgrade();
+ async move {
+ Timer::after(CURSOR_BLINK_INTERVAL).await;
+ if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
+ this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
+ }
+ }
+ })
+ .detach();
+ }
+
+ fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
+ if epoch == self.blink_epoch {
+ self.blinking_paused = false;
+ self.blink_cursors(epoch, cx);
+ }
+ }
+
+ fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
+ if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
+ self.cursors_visible = !self.cursors_visible;
+ cx.notify();
+
+ let epoch = self.next_blink_epoch();
+ cx.spawn(|this, mut cx| {
+ let this = this.downgrade();
+ async move {
+ Timer::after(CURSOR_BLINK_INTERVAL).await;
+ if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
+ this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
+ }
+ }
+ })
+ .detach();
+ }
+ }
+
+ pub fn cursors_visible(&self) -> bool {
+ self.cursors_visible
+ }
+
+ fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
+ cx.notify();
+ }
+
+ fn on_buffer_event(
+ &mut self,
+ _: ModelHandle<Buffer>,
+ event: &buffer::Event,
+ cx: &mut ViewContext<Self>,
+ ) {
+ match event {
+ 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 => {}
+ }
+ }
+}
+
+impl Snapshot {
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 font_id = font_cache.default_font(self.font_family);
let ascent = font_cache.metric(font_id, |m| m.ascent);
- font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
+ font_cache.scale_metric(ascent, font_id, self.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)
+ let font_id = font_cache.default_font(self.font_family);
+ let descent = font_cache.metric(font_id, |m| m.descent);
+ font_cache.scale_metric(descent, font_id, self.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)
+ let font_id = font_cache.default_font(self.font_family);
+ font_cache.line_height(font_id, self.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)
- }
-
- pub fn set_wrap_width(&self, width: f32, cx: &AppContext) {
- self.display_map.set_wrap_width(Some(width), cx);
+ let font_id = font_cache.default_font(self.font_family);
+ font_cache.em_width(font_id, self.font_size)
}
// TODO: Can we make this not return a result?
@@ -2209,11 +2283,12 @@ impl Editor {
layout_cache: &TextLayoutCache,
cx: &AppContext,
) -> Result<f32> {
- 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(cx).row_count() as f32).log10().floor() as usize + 1;
+ let font_size = self.font_size;
+ let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
+ let digit_count = (self.display_snapshot.buffer_row_count() as f32)
+ .log10()
+ .floor() as usize
+ + 1;
Ok(layout_cache
.layout_str(
@@ -2229,16 +2304,13 @@ impl Editor {
viewport_height: f32,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Result<Vec<text_layout::Line>> {
- 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 font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
- let start_row = self.scroll_position().y() as usize;
+ let start_row = self.scroll_position.y() as usize;
let end_row = cmp::min(
- self.max_point(cx).row() as usize,
+ self.display_snapshot.max_point().row() as usize,
start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
);
let line_count = end_row - start_row + 1;
@@ -2246,8 +2318,7 @@ impl Editor {
let mut layouts = Vec::with_capacity(line_count);
let mut line_number = String::new();
for buffer_row in self
- .display_map
- .snapshot(cx)
+ .display_snapshot
.buffer_rows(start_row as u32)
.take(line_count)
{
@@ -2255,7 +2326,7 @@ impl Editor {
write!(&mut line_number, "{}", buffer_row + 1).unwrap();
layouts.push(layout_cache.layout_str(
&line_number,
- font_size,
+ self.font_size,
&[(line_number.len(), font_id, ColorU::black())],
));
}
@@ -2268,17 +2339,13 @@ impl Editor {
mut rows: Range<u32>,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Result<Vec<text_layout::Line>> {
- let mut display_map = self.display_map.snapshot(cx);
- rows.end = cmp::min(rows.end, display_map.max_point().row() + 1);
+ rows.end = cmp::min(rows.end, self.display_snapshot.max_point().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)
@@ -2288,13 +2355,14 @@ impl Editor {
let mut line = String::new();
let mut styles = Vec::new();
let mut row = rows.start;
- let chunks = display_map.highlighted_chunks_for_rows(rows.clone());
- let theme = settings.theme.clone();
+ let chunks = self
+ .display_snapshot
+ .highlighted_chunks_for_rows(rows.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));
+ layouts.push(layout_cache.layout_str(&line, self.font_size, &styles));
line.clear();
styles.clear();
row += 1;
@@ -2304,12 +2372,12 @@ impl Editor {
}
if !line_chunk.is_empty() {
- let (color, font_properties) = theme.syntax_style(style_ix);
+ let (color, font_properties) = self.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)?
+ font_cache.select_font(self.font_family, &font_properties)?
};
line.push_str(line_chunk);
styles.push((line_chunk.len(), font_id, color));
@@ -2327,93 +2395,22 @@ impl Editor {
row: u32,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Result<text_layout::Line> {
- let settings = self.settings.borrow();
- let display_map = self.display_map.snapshot(cx);
- let font_id =
- font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
+ let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
- let line = display_map.line(row);
+ let line = self.display_snapshot.line(row);
Ok(layout_cache.layout_str(
&line,
- settings.buffer_font_size,
- &[(display_map.line_len(row) as usize, font_id, ColorU::black())],
+ self.font_size,
+ &[(
+ self.display_snapshot.line_len(row) 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, cx: &mut ViewContext<Self>) {
- self.cursors_visible = true;
- cx.notify();
-
- let epoch = self.next_blink_epoch();
- cx.spawn(|this, mut cx| {
- let this = this.downgrade();
- async move {
- Timer::after(CURSOR_BLINK_INTERVAL).await;
- if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
- this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
- }
- }
- })
- .detach();
- }
-
- fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
- if epoch == self.blink_epoch {
- self.blinking_paused = false;
- self.blink_cursors(epoch, cx);
- }
- }
-
- fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
- if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
- self.cursors_visible = !self.cursors_visible;
- cx.notify();
-
- let epoch = self.next_blink_epoch();
- cx.spawn(|this, mut cx| {
- let this = this.downgrade();
- async move {
- Timer::after(CURSOR_BLINK_INTERVAL).await;
- if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
- this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
- }
- }
- })
- .detach();
- }
- }
-
- pub fn cursors_visible(&self) -> bool {
- self.cursors_visible
- }
-
- fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
- cx.notify();
- }
-
- fn on_buffer_event(
- &mut self,
- _: ModelHandle<Buffer>,
- event: &buffer::Event,
- cx: &mut ViewContext<Self>,
- ) {
- match event {
- 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 => {}
- }
- }
}
pub enum Event {
@@ -2571,7 +2568,7 @@ mod tests {
let view = buffer_view.read(cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
[DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
);
@@ -2581,7 +2578,7 @@ mod tests {
let view = buffer_view.read(cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
[DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
);
@@ -2591,7 +2588,7 @@ mod tests {
let view = buffer_view.read(cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
[DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
);
@@ -2602,7 +2599,7 @@ mod tests {
let view = buffer_view.read(cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
[DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
);
@@ -2613,7 +2610,7 @@ mod tests {
let view = buffer_view.read(cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
[
DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
@@ -2626,7 +2623,7 @@ mod tests {
let view = buffer_view.read(cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
[DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
);
}
@@ -2641,7 +2638,7 @@ mod tests {
view.begin_selection(DisplayPoint::new(2, 2), false, cx);
});
assert_eq!(
- view.read(cx).selection_ranges(cx.as_ref()),
+ view.update(cx, |view, cx| view.selection_ranges(cx)),
[DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
);
@@ -2649,7 +2646,7 @@ mod tests {
view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
});
assert_eq!(
- view.read(cx).selection_ranges(cx.as_ref()),
+ view.update(cx, |view, cx| view.selection_ranges(cx)),
[DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
);
@@ -2658,7 +2655,7 @@ mod tests {
view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
});
assert_eq!(
- view.read(cx).selection_ranges(cx.as_ref()),
+ view.update(cx, |view, cx| view.selection_ranges(cx)),
[DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
);
}
@@ -2679,7 +2676,7 @@ mod tests {
view.end_selection(cx);
});
assert_eq!(
- view.read(cx).selection_ranges(cx.as_ref()),
+ view.update(cx, |view, cx| view.selection_ranges(cx)),
[
DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
@@ -2688,13 +2685,13 @@ mod tests {
view.update(cx, |view, cx| view.cancel(&(), cx));
assert_eq!(
- view.read(cx).selection_ranges(cx.as_ref()),
+ view.update(cx, |view, cx| view.selection_ranges(cx)),
[DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
);
view.update(cx, |view, cx| view.cancel(&(), cx));
assert_eq!(
- view.read(cx).selection_ranges(cx.as_ref()),
+ view.update(cx, |view, cx| view.selection_ranges(cx)),
[DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
);
}
@@ -2711,7 +2708,7 @@ mod tests {
let layouts = view
.read(cx)
- .layout_line_numbers(1000.0, &font_cache, &layout_cache, cx.as_ref())
+ .layout_line_numbers(1000.0, &font_cache, &layout_cache, cx)
.unwrap();
assert_eq!(layouts.len(), 6);
}
@@ -2750,7 +2747,7 @@ mod tests {
.unwrap();
view.fold(&(), cx);
assert_eq!(
- view.text(cx.as_ref()),
+ view.text(cx),
"
impl Foo {
// Hello!
@@ -2771,7 +2768,7 @@ mod tests {
view.fold(&(), cx);
assert_eq!(
- view.text(cx.as_ref()),
+ view.text(cx),
"
impl Foo {ā¦
}
@@ -2781,7 +2778,7 @@ mod tests {
view.unfold(&(), cx);
assert_eq!(
- view.text(cx.as_ref()),
+ view.text(cx),
"
impl Foo {
// Hello!
@@ -2801,7 +2798,7 @@ mod tests {
);
view.unfold(&(), cx);
- assert_eq!(view.text(cx.as_ref()), buffer.read(cx).text());
+ assert_eq!(view.text(cx), buffer.read(cx).text());
});
}
@@ -2824,43 +2821,43 @@ mod tests {
view.update(cx, |view, cx| {
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
);
view.move_down(&(), cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
);
view.move_right(&(), cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
);
view.move_left(&(), cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
);
view.move_up(&(), cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
);
view.move_to_end(&(), cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
&[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
);
view.move_to_beginning(&(), cx);
assert_eq!(
- view.selection_ranges(cx.as_ref()),
+ view.selection_ranges(cx),
&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
);
@@ -5,7 +5,7 @@ mod wrap_map;
use super::{buffer, Anchor, Bias, Buffer, Point, Settings, ToOffset, ToPoint};
use fold_map::FoldMap;
-use gpui::{AppContext, ModelHandle};
+use gpui::{ModelHandle, MutableAppContext};
use postage::prelude::Stream;
use std::ops::Range;
use tab_map::TabMap;
@@ -24,7 +24,7 @@ impl DisplayMap {
buffer: ModelHandle<Buffer>,
settings: Settings,
wrap_width: Option<f32>,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Self {
let (fold_map, snapshot) = FoldMap::new(buffer.clone(), cx);
let (tab_map, snapshot) = TabMap::new(snapshot, settings.tab_size);
@@ -37,7 +37,7 @@ impl DisplayMap {
}
}
- pub fn snapshot(&self, cx: &AppContext) -> DisplayMapSnapshot {
+ pub fn snapshot(&self, cx: &mut MutableAppContext) -> DisplayMapSnapshot {
let (folds_snapshot, edits) = self.fold_map.read(cx);
let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits);
let wraps_snapshot = self.wrap_map.sync(tabs_snapshot.clone(), edits, cx);
@@ -52,7 +52,7 @@ impl DisplayMap {
pub fn fold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) {
let (mut fold_map, snapshot, edits) = self.fold_map.write(cx);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
@@ -65,7 +65,7 @@ impl DisplayMap {
pub fn unfold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) {
let (mut fold_map, snapshot, edits) = self.fold_map.write(cx);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
@@ -75,7 +75,7 @@ impl DisplayMap {
self.wrap_map.sync(snapshot, edits, cx);
}
- pub fn set_wrap_width(&self, width: Option<f32>, cx: &AppContext) {
+ pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) {
self.wrap_map.set_wrap_width(width, cx);
}
@@ -96,6 +96,10 @@ impl DisplayMapSnapshot {
self.wraps_snapshot.buffer_rows(start_row)
}
+ pub fn buffer_row_count(&self) -> u32 {
+ self.buffer_snapshot.max_point().row + 1
+ }
+
pub fn max_point(&self) -> DisplayPoint {
DisplayPoint(self.wraps_snapshot.max_point())
}
@@ -317,11 +321,11 @@ mod tests {
Buffer::new(0, text, cx)
});
let wrap_width = Some(rng.gen_range(20.0..=100.0));
- let map = cx.read(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
+ let map = cx.update(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
for _op_ix in 0..operations {
buffer.update(&mut cx, |buffer, cx| buffer.randomly_mutate(&mut rng, cx));
- let snapshot = cx.read(|cx| map.snapshot(cx));
+ let snapshot = cx.update(|cx| map.snapshot(cx));
let expected_buffer_rows = (0..=snapshot.max_point().row())
.map(|display_row| {
DisplayPoint::new(display_row, 0)
@@ -362,9 +366,9 @@ mod tests {
let text = "one two three four five\nsix seven eight";
let buffer = cx.add_model(|cx| Buffer::new(0, text.to_string(), cx));
- let map = cx.read(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
+ let map = cx.update(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
- let snapshot = cx.read(|cx| map.snapshot(cx));
+ let snapshot = cx.update(|cx| map.snapshot(cx));
assert_eq!(
snapshot
.chunks_at(DisplayPoint::new(0, 3))
@@ -385,7 +389,7 @@ mod tests {
buffer.edit(vec![ix..ix], "and ", cx);
});
- let snapshot = cx.read(|cx| map.snapshot(cx));
+ let snapshot = cx.update(|cx| map.snapshot(cx));
assert_eq!(
snapshot
.chunks_at(DisplayPoint::new(1, 0))
@@ -402,7 +406,7 @@ mod tests {
buffer.clone(),
Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
None,
- cx.as_ref(),
+ cx,
);
buffer.update(cx, |buffer, cx| {
buffer.edit(
@@ -417,19 +421,19 @@ mod tests {
});
assert_eq!(
- &map.snapshot(cx.as_ref())
+ &map.snapshot(cx)
.chunks_at(DisplayPoint::new(1, 0))
.collect::<String>()[0..10],
" b bb"
);
assert_eq!(
- &map.snapshot(cx.as_ref())
+ &map.snapshot(cx)
.chunks_at(DisplayPoint::new(1, 2))
.collect::<String>()[0..10],
" b bbbb"
);
assert_eq!(
- &map.snapshot(cx.as_ref())
+ &map.snapshot(cx)
.chunks_at(DisplayPoint::new(1, 6))
.collect::<String>()[0..13],
" bbbbb\nc c"
@@ -480,7 +484,7 @@ mod tests {
});
buffer.condition(&cx, |buf, _| !buf.is_parsing()).await;
- let mut map = cx.read(|cx| {
+ let mut map = cx.update(|cx| {
DisplayMap::new(
buffer,
Settings::new(cx.font_cache()).unwrap().with_tab_size(2),
@@ -489,7 +493,7 @@ mod tests {
)
});
assert_eq!(
- cx.read(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
+ cx.update(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
vec![
("fn ".to_string(), None),
("outer".to_string(), Some("fn.name")),
@@ -500,7 +504,7 @@ mod tests {
]
);
assert_eq!(
- cx.read(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
+ cx.update(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
vec![
(" fn ".to_string(), Some("mod.body")),
("inner".to_string(), Some("fn.name")),
@@ -508,9 +512,9 @@ mod tests {
]
);
- cx.read(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
+ cx.update(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
assert_eq!(
- cx.read(|cx| highlighted_chunks(0..2, &map, &theme, cx)),
+ cx.update(|cx| highlighted_chunks(0..2, &map, &theme, cx)),
vec![
("fn ".to_string(), None),
("out".to_string(), Some("fn.name")),
@@ -575,9 +579,9 @@ mod tests {
buffer_font_size: 16.0,
..Settings::new(&font_cache).unwrap()
};
- let mut map = cx.read(|cx| DisplayMap::new(buffer, settings, Some(40.0), cx));
+ let mut map = cx.update(|cx| DisplayMap::new(buffer, settings, Some(40.0), cx));
assert_eq!(
- cx.read(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
+ cx.update(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
[
("fn \n".to_string(), None),
("oute\nr".to_string(), Some("fn.name")),
@@ -585,13 +589,13 @@ mod tests {
]
);
assert_eq!(
- cx.read(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
+ cx.update(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
[("{}\n\n".to_string(), None)]
);
- cx.read(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
+ cx.update(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
assert_eq!(
- cx.read(|cx| highlighted_chunks(1..4, &map, &theme, cx)),
+ cx.update(|cx| highlighted_chunks(1..4, &map, &theme, cx)),
[
("out".to_string(), Some("fn.name")),
("ā¦\n".to_string(), None),
@@ -607,7 +611,6 @@ mod tests {
let text = "\n'a', 'α',\t'ā',\t'ā', 'š'\n";
let display_text = "\n'a', 'α', 'ā', 'ā', 'š'\n";
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
- let cx = cx.as_ref();
let map = DisplayMap::new(
buffer.clone(),
Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
@@ -647,7 +650,6 @@ mod tests {
fn test_tabs_with_multibyte_chars(cx: &mut gpui::MutableAppContext) {
let text = "ā
\t\tα\nβ\t\nšĪ²\t\tγ";
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
- let cx = cx.as_ref();
let map = DisplayMap::new(
buffer.clone(),
Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
@@ -718,19 +720,16 @@ mod tests {
buffer.clone(),
Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
None,
- cx.as_ref(),
+ cx,
);
- assert_eq!(
- map.snapshot(cx.as_ref()).max_point(),
- DisplayPoint::new(1, 11)
- )
+ assert_eq!(map.snapshot(cx).max_point(), DisplayPoint::new(1, 11))
}
fn highlighted_chunks<'a>(
rows: Range<u32>,
map: &DisplayMap,
theme: &'a Theme,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Vec<(String, Option<&'a str>)> {
let mut chunks: Vec<(String, Option<&str>)> = Vec::new();
for (chunk, style_id) in map.snapshot(cx).highlighted_chunks_for_rows(rows) {
@@ -126,7 +126,7 @@ mod tests {
..Settings::new(&font_cache).unwrap()
};
- let mut wrapper = LineWrapper::new(font_system, font_cache, settings);
+ let wrapper = LineWrapper::new(font_system, font_cache, settings);
assert_eq!(
wrapper.wrap_line_with_shaping("aa bbb cccc ddddd eeee", 72.0),
@@ -12,7 +12,7 @@ use crate::{
util::Bias,
Settings,
};
-use gpui::{executor::Background, AppContext, Task};
+use gpui::{executor::Background, MutableAppContext, Task};
use parking_lot::Mutex;
use postage::{prelude::Stream, sink::Sink, watch};
use smol::future::yield_now;
@@ -80,7 +80,7 @@ impl WrapMap {
tab_snapshot: TabSnapshot,
settings: Settings,
wrap_width: Option<f32>,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Self {
let this = Self(Arc::new(Mutex::new(WrapMapState {
background_task: None,
@@ -116,14 +116,14 @@ impl WrapMap {
&self,
tab_snapshot: TabSnapshot,
edits: Vec<TabEdit>,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Snapshot {
self.0.lock().pending_edits.push_back((tab_snapshot, edits));
self.flush_edits(cx.background());
self.0.lock().snapshot.clone()
}
- pub fn set_wrap_width(&self, wrap_width: Option<f32>, cx: &AppContext) {
+ pub fn set_wrap_width(&self, wrap_width: Option<f32>, cx: &mut MutableAppContext) {
let mut state = self.0.lock();
if wrap_width == state.wrap_width {
return;
@@ -814,7 +814,7 @@ mod tests {
folds_snapshot.text()
);
log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text());
- let wrap_map = cx.read(|cx| {
+ let wrap_map = cx.update(|cx| {
WrapMap::new(
tabs_snapshot.clone(),
settings.clone(),
@@ -832,7 +832,7 @@ mod tests {
notifications.recv().await;
}
- let snapshot = cx.read(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
+ let snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
let actual_text = snapshot.text();
assert_eq!(
actual_text, expected_text,
@@ -856,12 +856,12 @@ mod tests {
let unwrapped_text = tabs_snapshot.text();
let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
- let mut snapshot = cx.read(|cx| wrap_map.sync(tabs_snapshot.clone(), edits, cx));
+ let mut snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot.clone(), edits, cx));
snapshot.check_invariants(&mut rng);
if wrap_map.is_rewrapping() {
notifications.recv().await;
- snapshot = cx.read(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
+ snapshot = cx.update(|cx| wrap_map.sync(tabs_snapshot, Vec::new(), cx));
}
snapshot.check_invariants(&mut rng);
@@ -1,3 +1,5 @@
+use crate::time::ReplicaId;
+
use super::{DisplayPoint, Editor, SelectAction};
use gpui::{
color::ColorU,
@@ -9,12 +11,15 @@ use gpui::{
json::{self, ToJson},
text_layout::{self, TextLayoutCache},
AfterLayoutContext, AppContext, Border, Element, Event, EventContext, FontCache, LayoutContext,
- PaintContext, Quad, Scene, SizeConstraint, WeakViewHandle,
+ MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
};
use json::json;
use smallvec::SmallVec;
-use std::cmp::Ordering;
-use std::cmp::{self};
+use std::{cmp::Ordering, ops::Range};
+use std::{
+ cmp::{self},
+ collections::HashMap,
+};
pub struct EditorElement {
view: WeakViewHandle<Editor>,
@@ -29,6 +34,13 @@ impl EditorElement {
self.view.upgrade(cx).unwrap().read(cx)
}
+ fn update_view<F, T>(&self, cx: &mut MutableAppContext, f: F) -> T
+ where
+ F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
+ {
+ self.view.upgrade(cx).unwrap().update(cx, f)
+ }
+
fn mouse_down(
&self,
position: Vector2F,
@@ -38,9 +50,10 @@ impl EditorElement {
cx: &mut EventContext,
) -> bool {
if paint.text_bounds.contains_point(position) {
- let view = self.view(cx.app.as_ref());
- let position =
- paint.point_for_position(view, layout, position, cx.font_cache, cx.app.as_ref());
+ let position = self.update_view(cx.app, |view, cx| {
+ let font_cache = cx.font_cache().clone();
+ paint.point_for_position(view, layout, position, &font_cache, cx)
+ });
cx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd });
true
} else {
@@ -94,19 +107,15 @@ impl EditorElement {
))
}
- let action = SelectAction::Update {
- position: paint.point_for_position(
- view,
- layout,
- position,
- cx.font_cache,
- cx.app.as_ref(),
- ),
+ let font_cache = cx.font_cache.clone();
+ let text_layout_cache = cx.text_layout_cache.clone();
+ let action = self.update_view(cx.app, |view, cx| SelectAction::Update {
+ position: paint.point_for_position(view, layout, position, &font_cache, cx),
scroll_position: (view.scroll_position() + scroll_delta).clamp(
Vector2F::zero(),
- layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app),
+ layout.scroll_max(view, &font_cache, &text_layout_cache, cx),
),
- };
+ });
cx.dispatch_action("buffer:select", action);
true
@@ -160,7 +169,9 @@ 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, cx.app),
+ self.update_view(cx.app, |view, cx| {
+ layout.scroll_max(view, font_cache, layout_cache, cx)
+ }),
);
cx.dispatch_action("buffer:scroll", scroll_position);
@@ -226,14 +237,11 @@ impl EditorElement {
let mut cursors = SmallVec::<[Cursor; 32]>::new();
let content_origin = bounds.origin() + layout.text_offset;
- for selection_set_id in view.active_selection_sets(cx.app) {
- let (selection_color, cursor_color) =
- colors[selection_set_id.replica_id as usize % colors.len()];
- for selection in view.selections_in_range(
- selection_set_id,
- DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
- cx.app,
- ) {
+
+ for (replica_id, selections) in &layout.selections {
+ let (selection_color, cursor_color) = colors[*replica_id as usize % colors.len()];
+
+ for selection in selections {
if selection.start != selection.end {
let range_start = cmp::min(selection.start, selection.end);
let range_end = cmp::max(selection.start, selection.end);
@@ -326,17 +334,12 @@ impl Element for EditorElement {
constraint: SizeConstraint,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
- let app = &mut 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(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 view = self.view(cx.app);
let font_cache = &cx.font_cache;
let layout_cache = &cx.text_layout_cache;
@@ -346,7 +349,7 @@ impl Element for EditorElement {
let gutter_width;
if view.is_gutter_visible() {
gutter_padding = view.em_width(cx.font_cache);
- match view.max_line_number_width(cx.font_cache, cx.text_layout_cache, app) {
+ match view.max_line_number_width(cx.font_cache, cx.text_layout_cache, cx.app) {
Err(error) => {
log::error!("error computing max line number width: {}", error);
return (size, None);
@@ -366,12 +369,18 @@ impl Element for EditorElement {
let wrap_width = text_size.x() - text_offset.x() - overscroll.x();
// TODO: Core text doesn't seem to be keeping our lines below the specified wrap width. Find out why.
let wrap_width = wrap_width - em_width;
- view.set_wrap_width(wrap_width, app);
+ self.update_view(cx.app, |view, cx| {
+ view.set_wrap_width(wrap_width, cx);
+ });
+
+ if size.y().is_infinite() {
+ size.set_y((view.max_point(cx.app).row() + 1) as f32 * view.line_height(cx.font_cache));
+ }
- let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, app);
+ let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx.app);
let line_number_layouts = if view.is_gutter_visible() {
- match view.layout_line_numbers(size.y(), cx.font_cache, cx.text_layout_cache, app) {
+ match view.layout_line_numbers(size.y(), cx.font_cache, cx.text_layout_cache, cx.app) {
Err(error) => {
log::error!("error laying out line numbers: {}", error);
return (size, None);
@@ -388,7 +397,7 @@ impl Element for EditorElement {
let mut max_visible_line_width = 0.0;
let line_layouts =
- match view.layout_lines(start_row..end_row, font_cache, layout_cache, app) {
+ match view.layout_lines(start_row..end_row, font_cache, layout_cache, cx.app) {
Err(error) => {
log::error!("error laying out lines: {}", error);
return (size, None);
@@ -404,21 +413,34 @@ impl Element for EditorElement {
}
};
- (
+ let mut selections = HashMap::new();
+ for selection_set_id in view.active_selection_sets(cx.app) {
+ selections.insert(
+ selection_set_id.replica_id,
+ view.selections_in_range(
+ selection_set_id,
+ DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
+ cx.app,
+ )
+ .collect(),
+ );
+ }
+
+ let layout_state = Some(LayoutState {
size,
- Some(LayoutState {
- size,
- gutter_size,
- gutter_padding,
- text_size,
- overscroll,
- text_offset,
- line_layouts,
- line_number_layouts,
- max_visible_line_width,
- autoscroll_horizontally,
- }),
- )
+ gutter_size,
+ gutter_padding,
+ text_size,
+ overscroll,
+ text_offset,
+ line_layouts,
+ line_number_layouts,
+ selections,
+ max_visible_line_width,
+ autoscroll_horizontally,
+ });
+
+ (size, layout_state)
}
fn after_layout(
@@ -428,12 +450,10 @@ impl Element for EditorElement {
cx: &mut AfterLayoutContext,
) {
if let Some(layout) = layout {
- let app = cx.app.as_ref();
-
- let view = self.view(app);
+ let view = self.view(cx.app);
view.clamp_scroll_left(
layout
- .scroll_max(view, cx.font_cache, cx.text_layout_cache, app)
+ .scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app)
.x(),
);
@@ -441,10 +461,10 @@ impl Element for EditorElement {
view.autoscroll_horizontally(
view.scroll_position().y() as u32,
layout.text_size.x(),
- layout.scroll_width(view, cx.font_cache, cx.text_layout_cache, app),
+ layout.scroll_width(view, cx.font_cache, cx.text_layout_cache, cx.app),
view.em_width(cx.font_cache),
&layout.line_layouts,
- app,
+ cx.app,
);
}
}
@@ -528,6 +548,7 @@ pub struct LayoutState {
text_size: Vector2F,
line_layouts: Vec<text_layout::Line>,
line_number_layouts: Vec<text_layout::Line>,
+ selections: HashMap<ReplicaId, Vec<Range<DisplayPoint>>>,
overscroll: Vector2F,
text_offset: Vector2F,
max_visible_line_width: f32,
@@ -540,7 +561,7 @@ impl LayoutState {
view: &Editor,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> f32 {
let row = view.longest_row(cx);
let longest_line_width = view
@@ -555,7 +576,7 @@ impl LayoutState {
view: &Editor,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> Vector2F {
vec2f(
((self.scroll_width(view, font_cache, layout_cache, cx) - self.text_size.x())
@@ -578,7 +599,7 @@ impl PaintState {
layout: &LayoutState,
position: Vector2F,
font_cache: &FontCache,
- cx: &AppContext,
+ cx: &mut MutableAppContext,
) -> DisplayPoint {
let scroll_position = view.scroll_position();
let position = position - self.text_bounds.origin();
@@ -311,7 +311,7 @@ impl FileFinder {
}
fn workspace_updated(&mut self, _: ViewHandle<Workspace>, cx: &mut ViewContext<Self>) {
- if let Some(task) = self.spawn_search(self.query_buffer.read(cx).text(cx.as_ref()), cx) {
+ if let Some(task) = self.spawn_search(self.query_buffer.read(cx).text(cx), cx) {
task.detach();
}
}
@@ -324,7 +324,7 @@ impl FileFinder {
) {
match event {
editor::Event::Edited => {
- let query = self.query_buffer.read(cx).text(cx.as_ref());
+ let query = self.query_buffer.update(cx, |buffer, cx| buffer.text(cx));
if query.is_empty() {
self.latest_search_id = util::post_inc(&mut self.search_count);
self.matches.clear();
@@ -1329,7 +1329,7 @@ mod tests {
.to_any()
.downcast::<Editor>()
.unwrap();
- assert!(editor.read(cx).text(cx.as_ref()).is_empty());
+ assert!(editor.update(cx, |editor, cx| editor.text(cx).is_empty()));
});
}