WIP
This commit is contained in:
+7
-1
@@ -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
|
||||
|
||||
+382
-463
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
+80
-59
@@ -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);
|
||||
});
|
||||
|
||||
let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, app);
|
||||
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, 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()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user