Remove unsafe code from App::test_async

I don't actually think it was correct to allow the future to borrow a mutable app reference. I went back to passing a wrapper around the refcell to async tests. They'll be a bit more annoying to write but also totally safe.
This commit is contained in:
Nathan Sobo
2021-04-10 00:05:09 -06:00
parent 448dace281
commit 97a8a8ed43
10 changed files with 317 additions and 315 deletions
+10 -10
View File
@@ -37,7 +37,7 @@ impl BufferElement {
ctx: &mut EventContext,
) -> bool {
if paint.text_bounds.contains_point(position) {
let view = self.view.as_ref(ctx.app);
let view = self.view.read(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 });
@@ -48,7 +48,7 @@ impl BufferElement {
}
fn mouse_up(&self, _position: Vector2F, ctx: &mut EventContext) -> bool {
if self.view.as_ref(ctx.app).is_selecting() {
if self.view.read(ctx.app).is_selecting() {
ctx.dispatch_action("buffer:select", SelectAction::End);
true
} else {
@@ -63,7 +63,7 @@ impl BufferElement {
paint: &mut PaintState,
ctx: &mut EventContext,
) -> bool {
let view = self.view.as_ref(ctx.app);
let view = self.view.read(ctx.app);
if view.is_selecting() {
let rect = paint.text_bounds;
@@ -145,7 +145,7 @@ impl BufferElement {
return false;
}
let view = self.view.as_ref(ctx.app);
let view = self.view.read(ctx.app);
let font_cache = &ctx.font_cache;
let layout_cache = &ctx.text_layout_cache;
let max_glyph_width = view.em_width(font_cache);
@@ -167,7 +167,7 @@ impl BufferElement {
}
fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, ctx: &mut PaintContext) {
let view = self.view.as_ref(ctx.app);
let view = self.view.read(ctx.app);
let line_height = view.line_height(ctx.font_cache);
let scroll_top = view.scroll_position().y() * line_height;
@@ -197,7 +197,7 @@ impl BufferElement {
}
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, ctx: &mut PaintContext) {
let view = self.view.as_ref(ctx.app);
let view = self.view.read(ctx.app);
let line_height = view.line_height(ctx.font_cache);
let descent = view.font_descent(ctx.font_cache);
let start_row = view.scroll_position().y() as u32;
@@ -313,14 +313,14 @@ impl Element for BufferElement {
let app = ctx.app;
let mut size = constraint.max;
if size.y().is_infinite() {
let view = self.view.as_ref(app);
let view = self.view.read(app);
size.set_y((view.max_point(app).row() + 1) as f32 * view.line_height(ctx.font_cache));
}
if size.x().is_infinite() {
unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
}
let view = self.view.as_ref(app);
let view = self.view.read(app);
let font_cache = &ctx.font_cache;
let layout_cache = &ctx.text_layout_cache;
let line_height = view.line_height(font_cache);
@@ -404,7 +404,7 @@ impl Element for BufferElement {
if let Some(layout) = layout {
let app = ctx.app.downgrade();
let view = self.view.as_ref(app);
let view = self.view.read(app);
view.clamp_scroll_left(
layout
.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app)
@@ -437,7 +437,7 @@ impl Element for BufferElement {
layout.text_size,
);
if self.view.as_ref(ctx.app).is_gutter_visible() {
if self.view.read(ctx.app).is_gutter_visible() {
self.paint_gutter(gutter_bounds, layout, ctx);
}
self.paint_text(text_bounds, layout, ctx);
+55 -55
View File
@@ -125,7 +125,7 @@ impl BufferView {
});
ctx.observe(&display_map, Self::on_display_map_changed);
let buffer_ref = buffer.as_ref(ctx);
let buffer_ref = buffer.read(ctx);
Self {
handle: ctx.handle().downgrade(),
buffer,
@@ -188,7 +188,7 @@ impl BufferView {
return false;
}
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
let visible_lines = viewport_height / line_height;
let first_cursor_top = self
.selections
@@ -238,7 +238,7 @@ impl BufferView {
layouts: &[Arc<text_layout::Line>],
app: &AppContext,
) {
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
let mut target_left = std::f32::INFINITY;
let mut target_right = 0.0_f32;
@@ -287,7 +287,7 @@ impl BufferView {
ctx.emit(Event::Activate);
}
let display_map = self.display_map.as_ref(ctx);
let display_map = self.display_map.read(ctx);
let cursor = display_map
.anchor_before(position, Bias::Left, ctx.app())
.unwrap();
@@ -312,8 +312,8 @@ impl BufferView {
scroll_position: Vector2F,
ctx: &mut ViewContext<Self>,
) {
let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let map = self.display_map.read(ctx);
let cursor = map.anchor_before(position, Bias::Left, ctx.app()).unwrap();
if let Some(selection) = self.pending_selection.as_mut() {
selection.set_head(buffer, cursor);
@@ -347,8 +347,8 @@ impl BufferView {
where
T: IntoIterator<Item = &'a Range<DisplayPoint>>,
{
let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let map = self.display_map.read(ctx);
let mut selections = Vec::new();
for range in ranges {
selections.push(Selection {
@@ -366,7 +366,7 @@ impl BufferView {
}
fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) {
let buffer = self.buffer.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let mut offset_ranges = SmallVec::<[Range<usize>; 32]>::new();
for selection in &self.selections {
let start = selection.start.to_offset(buffer).unwrap();
@@ -381,7 +381,7 @@ impl BufferView {
};
});
let buffer = self.buffer.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let char_count = text.chars().count() as isize;
let mut delta = 0_isize;
self.selections = offset_ranges
@@ -416,8 +416,8 @@ impl BufferView {
}
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let map = self.display_map.read(ctx);
for selection in &mut self.selections {
if selection.range(buffer).is_empty() {
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
@@ -439,7 +439,7 @@ impl BufferView {
pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
{
let app = ctx.app();
let map = self.display_map.as_ref(ctx);
let map = self.display_map.read(ctx);
for selection in &mut self.selections {
let start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.to_display_point(map, app).unwrap();
@@ -462,8 +462,8 @@ impl BufferView {
pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
{
let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let map = self.display_map.read(ctx);
for selection in &mut self.selections {
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
let cursor = map
@@ -483,7 +483,7 @@ impl BufferView {
pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
{
let app = ctx.app();
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
for selection in &mut self.selections {
let start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.to_display_point(map, app).unwrap();
@@ -506,9 +506,9 @@ impl BufferView {
pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
{
let buffer = self.buffer.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let app = ctx.app();
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
for selection in &mut self.selections {
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
let cursor = map
@@ -526,7 +526,7 @@ impl BufferView {
ctx.propagate_action();
} else {
let app = ctx.app();
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
for selection in &mut self.selections {
let start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.to_display_point(map, app).unwrap();
@@ -551,8 +551,8 @@ impl BufferView {
ctx.propagate_action();
} else {
let app = ctx.app();
let buffer = self.buffer.as_ref(app);
let map = self.display_map.as_ref(app);
let buffer = self.buffer.read(app);
let map = self.display_map.read(app);
for selection in &mut self.selections {
let head = selection.head().to_display_point(map, app).unwrap();
let (head, goal_column) =
@@ -569,7 +569,7 @@ impl BufferView {
ctx.propagate_action();
} else {
let app = ctx.app();
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
for selection in &mut self.selections {
let start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.to_display_point(map, app).unwrap();
@@ -594,8 +594,8 @@ impl BufferView {
ctx.propagate_action();
} else {
let app = ctx.app();
let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let map = self.display_map.read(ctx);
for selection in &mut self.selections {
let head = selection.head().to_display_point(map, app).unwrap();
let (head, goal_column) =
@@ -615,7 +615,7 @@ impl BufferView {
}
fn merge_selections(&mut self, ctx: &AppContext) {
let buffer = self.buffer.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let mut i = 1;
while i < self.selections.len() {
if self.selections[i - 1]
@@ -651,14 +651,14 @@ impl BufferView {
self.selections
.first()
.unwrap()
.display_range(self.display_map.as_ref(app), app)
.display_range(self.display_map.read(app), app)
}
pub fn last_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
self.selections
.last()
.unwrap()
.display_range(self.display_map.as_ref(app), app)
.display_range(self.display_map.read(app), app)
}
pub fn selections_in_range<'a>(
@@ -666,7 +666,7 @@ impl BufferView {
range: Range<DisplayPoint>,
app: &'a AppContext,
) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
let start = map.anchor_before(range.start, Bias::Left, app).unwrap();
let start_index = self.selection_insertion_index(&start, app);
@@ -686,7 +686,7 @@ impl BufferView {
}
fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize {
let buffer = self.buffer.as_ref(app);
let buffer = self.buffer.read(app);
match self
.selections
@@ -720,7 +720,7 @@ impl BufferView {
let mut fold_ranges = Vec::new();
let app = ctx.app();
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
for selection in &self.selections {
let (start, end) = selection.display_range(map, app).sorted();
let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row;
@@ -750,8 +750,8 @@ impl BufferView {
use super::RangeExt;
let app = ctx.app();
let map = self.display_map.as_ref(app);
let buffer = self.buffer.as_ref(app);
let map = self.display_map.read(app);
let buffer = self.buffer.read(app);
let ranges = self
.selections
.iter()
@@ -796,7 +796,7 @@ impl BufferView {
let mut is_blank = true;
for c in self
.display_map
.as_ref(app)
.read(app)
.chars_at(DisplayPoint::new(display_row, 0), app)?
{
if c == ' ' {
@@ -810,7 +810,7 @@ impl BufferView {
}
fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Result<Range<Point>> {
let map = self.display_map.as_ref(app);
let map = self.display_map.read(app);
let max_point = self.max_point(app);
let (start_indent, _) = self.line_indent(start_row, app)?;
@@ -831,7 +831,7 @@ impl BufferView {
pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
self.display_map.update(ctx, |map, ctx| {
let buffer = self.buffer.as_ref(ctx);
let buffer = self.buffer.read(ctx);
let ranges = self
.selections
.iter()
@@ -842,23 +842,23 @@ impl BufferView {
}
pub fn line(&self, display_row: u32, app: &AppContext) -> Result<String> {
self.display_map.as_ref(app).line(display_row, app)
self.display_map.read(app).line(display_row, app)
}
pub fn line_len(&self, display_row: u32, app: &AppContext) -> Result<u32> {
self.display_map.as_ref(app).line_len(display_row, app)
self.display_map.read(app).line_len(display_row, app)
}
pub fn rightmost_point(&self, app: &AppContext) -> DisplayPoint {
self.display_map.as_ref(app).rightmost_point()
self.display_map.read(app).rightmost_point()
}
pub fn max_point(&self, app: &AppContext) -> DisplayPoint {
self.display_map.as_ref(app).max_point(app)
self.display_map.read(app).max_point(app)
}
pub fn text(&self, app: &AppContext) -> String {
self.display_map.as_ref(app).text(app)
self.display_map.read(app).text(app)
}
pub fn font_size(&self) -> f32 {
@@ -902,7 +902,7 @@ impl BufferView {
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.as_ref(app).max_point().row + 1) as f32)
let digit_count = ((self.buffer.read(app).max_point().row + 1) as f32)
.log10()
.floor() as usize
+ 1;
@@ -923,7 +923,7 @@ impl BufferView {
layout_cache: &TextLayoutCache,
app: &AppContext,
) -> Result<Vec<Arc<text_layout::Line>>> {
let display_map = self.display_map.as_ref(app);
let display_map = self.display_map.read(app);
let settings = smol::block_on(self.settings.read());
let font_size = settings.buffer_font_size;
@@ -959,7 +959,7 @@ impl BufferView {
layout_cache: &TextLayoutCache,
app: &AppContext,
) -> Result<Vec<Arc<text_layout::Line>>> {
let display_map = self.display_map.as_ref(app);
let display_map = self.display_map.read(app);
rows.end = cmp::min(rows.end, display_map.max_point(app).row() + 1);
if rows.start >= rows.end {
@@ -1149,7 +1149,7 @@ impl workspace::ItemView for BufferView {
}
fn title(&self, app: &AppContext) -> std::string::String {
if let Some(path) = self.buffer.as_ref(app).path(app) {
if let Some(path) = self.buffer.read(app).path(app) {
path.file_name()
.expect("buffer's path is always to a file")
.to_string_lossy()
@@ -1160,7 +1160,7 @@ impl workspace::ItemView for BufferView {
}
fn entry_id(&self, app: &AppContext) -> Option<(usize, usize)> {
self.buffer.as_ref(app).entry_id()
self.buffer.read(app).entry_id()
}
fn clone_on_split(&self, ctx: &mut ViewContext<Self>) -> Option<Self>
@@ -1177,7 +1177,7 @@ impl workspace::ItemView for BufferView {
}
fn is_dirty(&self, ctx: &AppContext) -> bool {
self.buffer.as_ref(ctx).is_dirty()
self.buffer.read(ctx).is_dirty()
}
}
@@ -1255,7 +1255,7 @@ mod tests {
view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
});
let view = buffer_view.as_ref(app);
let view = buffer_view.read(app);
let selections = view
.selections_in_range(
DisplayPoint::zero()..view.max_point(app.as_ref()),
@@ -1271,7 +1271,7 @@ mod tests {
view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
});
let view = buffer_view.as_ref(app);
let view = buffer_view.read(app);
let selections = view
.selections_in_range(
DisplayPoint::zero()..view.max_point(app.as_ref()),
@@ -1287,7 +1287,7 @@ mod tests {
view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
});
let view = buffer_view.as_ref(app);
let view = buffer_view.read(app);
let selections = view
.selections_in_range(
DisplayPoint::zero()..view.max_point(app.as_ref()),
@@ -1304,7 +1304,7 @@ mod tests {
view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
});
let view = buffer_view.as_ref(app);
let view = buffer_view.read(app);
let selections = view
.selections_in_range(
DisplayPoint::zero()..view.max_point(app.as_ref()),
@@ -1321,7 +1321,7 @@ mod tests {
view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx);
});
let view = buffer_view.as_ref(app);
let view = buffer_view.read(app);
let selections = view
.selections_in_range(
DisplayPoint::zero()..view.max_point(app.as_ref()),
@@ -1340,7 +1340,7 @@ mod tests {
view.end_selection(ctx);
});
let view = buffer_view.as_ref(app);
let view = buffer_view.read(app);
let selections = view
.selections_in_range(
DisplayPoint::zero()..view.max_point(app.as_ref()),
@@ -1367,7 +1367,7 @@ mod tests {
app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
let layouts = view
.as_ref(app)
.read(app)
.layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref())
.unwrap();
assert_eq!(layouts.len(), 6);
@@ -1460,7 +1460,7 @@ mod tests {
);
view.unfold(&(), ctx);
assert_eq!(view.text(ctx.app()), buffer.as_ref(ctx).text());
assert_eq!(view.text(ctx.app()), buffer.read(ctx).text());
});
});
}
@@ -1529,7 +1529,7 @@ mod tests {
});
assert_eq!(
buffer.as_ref(app).text(),
buffer.read(app).text(),
"oe two three\nfou five six\nseven ten\n"
);
})
+9 -9
View File
@@ -22,7 +22,7 @@ pub struct FoldMap {
impl FoldMap {
pub fn new(buffer: ModelHandle<Buffer>, app: &AppContext) -> Self {
let text_summary = buffer.as_ref(app).text_summary();
let text_summary = buffer.read(app).text_summary();
Self {
buffer,
folds: Vec::new(),
@@ -72,7 +72,7 @@ impl FoldMap {
let offset = self.to_display_offset(point, app)?;
let mut cursor = self.transforms.cursor();
cursor.seek(&offset, SeekBias::Right);
let buffer = self.buffer.as_ref(app);
let buffer = self.buffer.read(app);
Ok(Chars {
cursor,
offset: offset.0,
@@ -95,7 +95,7 @@ impl FoldMap {
app: &AppContext,
) -> Result<()> {
let mut edits = Vec::new();
let buffer = self.buffer.as_ref(app);
let buffer = self.buffer.read(app);
for range in ranges.into_iter() {
let start = range.start.to_offset(buffer)?;
let end = range.end.to_offset(buffer)?;
@@ -124,7 +124,7 @@ impl FoldMap {
ranges: impl IntoIterator<Item = Range<T>>,
app: &AppContext,
) -> Result<()> {
let buffer = self.buffer.as_ref(app);
let buffer = self.buffer.read(app);
let mut edits = Vec::new();
for range in ranges.into_iter() {
@@ -184,7 +184,7 @@ impl FoldMap {
.ok_or_else(|| anyhow!("display point {:?} is out of range", point))?;
assert!(transform.display_text.is_none());
let end_buffer_offset =
(cursor.start().buffer.lines + overshoot).to_offset(self.buffer.as_ref(app))?;
(cursor.start().buffer.lines + overshoot).to_offset(self.buffer.read(app))?;
offset += end_buffer_offset - cursor.start().buffer.chars;
}
Ok(DisplayOffset(offset))
@@ -208,7 +208,7 @@ impl FoldMap {
}
pub fn apply_edits(&mut self, edits: &[Edit], app: &AppContext) -> Result<()> {
let buffer = self.buffer.as_ref(app);
let buffer = self.buffer.read(app);
let mut edits = edits.iter().cloned().peekable();
let mut new_transforms = SumTree::new();
@@ -597,7 +597,7 @@ mod tests {
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
{
let buffer = buffer.as_ref(app);
let buffer = buffer.read(app);
let fold_count = rng.gen_range(0..10);
let mut fold_ranges: Vec<Range<usize>> = Vec::new();
@@ -632,7 +632,7 @@ mod tests {
map.apply_edits(&edits, app.as_ref()).unwrap();
let buffer = map.buffer.as_ref(app);
let buffer = map.buffer.read(app);
let mut expected_text = buffer.text();
let mut expected_buffer_rows = Vec::new();
let mut next_row = buffer.max_point().row;
@@ -694,7 +694,7 @@ mod tests {
}
fn merged_fold_ranges(&self, app: &AppContext) -> Vec<Range<usize>> {
let buffer = self.buffer.as_ref(app);
let buffer = self.buffer.read(app);
let mut fold_ranges = self
.folds
.iter()
+5 -5
View File
@@ -108,7 +108,7 @@ impl DisplayMap {
app: &AppContext,
) -> Result<Anchor> {
self.buffer
.as_ref(app)
.read(app)
.anchor_before(point.to_buffer_point(self, bias, app)?)
}
@@ -119,7 +119,7 @@ impl DisplayMap {
app: &AppContext,
) -> Result<Anchor> {
self.buffer
.as_ref(app)
.read(app)
.anchor_after(point.to_buffer_point(self, bias, app)?)
}
@@ -206,7 +206,7 @@ impl Point {
impl Anchor {
pub fn to_display_point(&self, map: &DisplayMap, app: &AppContext) -> Result<DisplayPoint> {
self.to_point(map.buffer.as_ref(app))?
self.to_point(map.buffer.read(app))?
.to_display_point(map, app)
}
}
@@ -314,7 +314,7 @@ mod tests {
})
.unwrap();
let map = map.as_ref(app);
let map = map.read(app);
assert_eq!(
map.chars_at(DisplayPoint::new(1, 0), app.as_ref())
.unwrap()
@@ -368,7 +368,7 @@ mod tests {
let buffer = app.add_model(|_| Buffer::new(0, "aaa\n\t\tbbb"));
let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx));
assert_eq!(
map.as_ref(app).max_point(app.as_ref()),
map.read(app).max_point(app.as_ref()),
DisplayPoint::new(1, 11)
)
});
+22 -18
View File
@@ -114,7 +114,7 @@ impl FileFinder {
self.matches.len(),
move |mut range, items, app| {
let finder = handle.upgrade(app).unwrap();
let finder = finder.as_ref(app);
let finder = finder.read(app);
let start = range.start;
range.end = cmp::min(range.end, finder.matches.len());
items.extend(finder.matches[range].iter().enumerate().filter_map(
@@ -287,7 +287,7 @@ impl FileFinder {
}
fn workspace_updated(&mut self, _: ModelHandle<Workspace>, ctx: &mut ViewContext<Self>) {
self.spawn_search(self.query_buffer.as_ref(ctx).text(ctx.app()), ctx);
self.spawn_search(self.query_buffer.read(ctx).text(ctx.app()), ctx);
}
fn on_query_buffer_event(
@@ -299,7 +299,7 @@ impl FileFinder {
use buffer_view::Event::*;
match event {
Edited => {
let query = self.query_buffer.as_ref(ctx).text(ctx.app());
let query = self.query_buffer.read(ctx).text(ctx.app());
if query.is_empty() {
self.latest_search_id = util::post_inc(&mut self.search_count);
self.matches.clear();
@@ -371,18 +371,18 @@ impl FileFinder {
fn worktree<'a>(&'a self, tree_id: usize, app: &'a AppContext) -> Option<&'a Worktree> {
self.workspace
.as_ref(app)
.read(app)
.worktrees()
.get(&tree_id)
.map(|worktree| worktree.as_ref(app))
.map(|worktree| worktree.read(app))
}
fn worktrees(&self, app: &AppContext) -> Vec<Worktree> {
self.workspace
.as_ref(app)
.read(app)
.worktrees()
.iter()
.map(|worktree| worktree.as_ref(app).clone())
.map(|worktree| worktree.read(app).clone())
.collect()
}
}
@@ -400,7 +400,7 @@ mod tests {
#[test]
fn test_matching_paths() {
App::test_async((), |app| async move {
App::test_async((), |mut app| async move {
let tmp_dir = TempDir::new("example").unwrap();
fs::create_dir(tmp_dir.path().join("a")).await.unwrap();
fs::write(tmp_dir.path().join("a/banana"), "banana")
@@ -409,8 +409,10 @@ mod tests {
fs::write(tmp_dir.path().join("a/bandana"), "bandana")
.await
.unwrap();
super::init(app);
editor::init(app);
app.update(|ctx| {
super::init(ctx);
editor::init(ctx);
});
let settings = settings::channel(&app.font_cache()).unwrap().1;
let workspace = app.add_model(|ctx| Workspace::new(vec![tmp_dir.path().into()], ctx));
@@ -424,14 +426,16 @@ mod tests {
(),
);
let finder = workspace_view
.as_ref(app)
.modal()
.cloned()
.unwrap()
.downcast::<FileFinder>()
.unwrap();
let query_buffer = finder.as_ref(app).query_buffer.clone();
let finder = app.read(|ctx| {
workspace_view
.read(ctx)
.modal()
.cloned()
.unwrap()
.downcast::<FileFinder>()
.unwrap()
});
let query_buffer = app.read(|ctx| finder.read(ctx).query_buffer.clone());
let chain = vec![finder.id(), query_buffer.id()];
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string());
+2 -2
View File
@@ -109,9 +109,9 @@ mod tests {
.unwrap();
assert_eq!(
workspace_view_1
.as_ref(app)
.read(app)
.workspace
.as_ref(app)
.read(app)
.worktrees()
.len(),
2
+11 -11
View File
@@ -101,7 +101,7 @@ impl Workspace {
pub fn contains_path(&self, path: &Path, app: &AppContext) -> bool {
self.worktrees
.iter()
.any(|worktree| worktree.as_ref(app).contains_path(path))
.any(|worktree| worktree.read(app).contains_path(path))
}
pub fn open_paths(&mut self, paths: &[PathBuf], ctx: &mut ModelContext<Self>) {
@@ -112,7 +112,7 @@ impl Workspace {
pub fn open_path<'a>(&'a mut self, path: PathBuf, ctx: &mut ModelContext<Self>) {
for tree in self.worktrees.iter() {
if tree.as_ref(ctx).contains_path(&path) {
if tree.read(ctx).contains_path(&path) {
return;
}
}
@@ -200,18 +200,18 @@ impl Entity for Workspace {
#[cfg(test)]
pub trait WorkspaceHandle {
fn file_entries(&self, app: &mut MutableAppContext) -> Vec<(usize, usize)>;
fn file_entries(&self, app: &AppContext) -> Vec<(usize, usize)>;
}
#[cfg(test)]
impl WorkspaceHandle for ModelHandle<Workspace> {
fn file_entries(&self, app: &mut MutableAppContext) -> Vec<(usize, usize)> {
self.as_ref(app)
fn file_entries(&self, app: &AppContext) -> Vec<(usize, usize)> {
self.read(app)
.worktrees()
.iter()
.flat_map(|tree| {
let tree_id = tree.id();
tree.as_ref(app)
tree.read(app)
.files()
.map(move |file| (tree_id, file.entry_id))
})
@@ -228,7 +228,7 @@ mod tests {
#[test]
fn test_open_entry() {
App::test_async((), |app| async move {
App::test_async((), |mut app| async move {
let dir = temp_tree(json!({
"a": {
"aa": "aa contents",
@@ -240,12 +240,12 @@ mod tests {
app.finish_pending_tasks().await; // Open and populate worktree.
// Get the first file entry.
let tree = workspace.as_ref(app).worktrees.iter().next().unwrap();
let entry_id = tree.as_ref(app).files().next().unwrap().entry_id;
let tree = app.read(|ctx| workspace.read(ctx).worktrees.iter().next().unwrap().clone());
let entry_id = app.read(|ctx| tree.read(ctx).files().next().unwrap().entry_id);
let entry = (tree.id(), entry_id);
// Open the same entry twice before it finishes loading.
let (future_1, future_2) = workspace.update(app, |w, app| {
let (future_1, future_2) = workspace.update(&mut app, |w, app| {
(
w.open_entry(entry, app).unwrap(),
w.open_entry(entry, app).unwrap(),
@@ -258,7 +258,7 @@ mod tests {
// Open the same entry again now that it has loaded
let handle_3 = workspace
.update(app, |w, app| w.open_entry(entry, app).unwrap())
.update(&mut app, |w, app| w.open_entry(entry, app).unwrap())
.await
.unwrap();
+75 -63
View File
@@ -54,11 +54,11 @@ pub trait ItemViewHandle: Send + Sync {
impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
fn title(&self, app: &AppContext) -> String {
self.as_ref(app).title(app)
self.read(app).title(app)
}
fn entry_id(&self, app: &AppContext) -> Option<(usize, usize)> {
self.as_ref(app).entry_id(app)
self.read(app).entry_id(app)
}
fn boxed_clone(&self) -> Box<dyn ItemViewHandle> {
@@ -93,7 +93,7 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
}
fn is_dirty(&self, ctx: &AppContext) -> bool {
self.as_ref(ctx).is_dirty(ctx)
self.read(ctx).is_dirty(ctx)
}
fn id(&self) -> usize {
@@ -154,7 +154,7 @@ impl WorkspaceView {
}
pub fn contains_paths(&self, paths: &[PathBuf], app: &AppContext) -> bool {
self.workspace.as_ref(app).contains_paths(paths, app)
self.workspace.read(app).contains_paths(paths, app)
}
pub fn open_paths(&self, paths: &[PathBuf], app: &mut MutableAppContext) {
@@ -228,8 +228,8 @@ impl WorkspaceView {
}
pub fn open_example_entry(&mut self, ctx: &mut ViewContext<Self>) {
if let Some(tree) = self.workspace.as_ref(ctx).worktrees().iter().next() {
if let Some(file) = tree.as_ref(ctx).files().next() {
if let Some(tree) = self.workspace.read(ctx).worktrees().iter().next() {
if let Some(file) = tree.read(ctx).files().next() {
info!("open_entry ({}, {})", tree.id(), file.entry_id);
self.open_entry((tree.id(), file.entry_id), ctx);
} else {
@@ -322,7 +322,7 @@ impl WorkspaceView {
) -> ViewHandle<Pane> {
let new_pane = self.add_pane(ctx);
self.activate_pane(new_pane.clone(), ctx);
if let Some(item) = pane.as_ref(ctx).active_item() {
if let Some(item) = pane.read(ctx).active_item() {
if let Some(clone) = item.clone_on_split(ctx.app_mut()) {
self.add_item(clone, ctx);
}
@@ -394,7 +394,7 @@ mod tests {
#[test]
fn test_open_entry() {
App::test_async((), |app| async move {
App::test_async((), |mut app| async move {
let dir = temp_tree(json!({
"a": {
"aa": "aa contents",
@@ -406,70 +406,78 @@ mod tests {
let settings = settings::channel(&app.font_cache()).unwrap().1;
let workspace = app.add_model(|ctx| Workspace::new(vec![dir.path().into()], ctx));
app.finish_pending_tasks().await; // Open and populate worktree.
let entries = workspace.file_entries(app);
let entries = app.read(|ctx| workspace.file_entries(ctx));
let (_, workspace_view) =
app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx));
// Open the first entry
workspace_view.update(app, |w, ctx| w.open_entry(entries[0], ctx));
workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[0], ctx));
app.finish_pending_tasks().await;
assert_eq!(
workspace_view
.as_ref(app)
.active_pane()
.as_ref(app)
.items()
.len(),
1
);
app.read(|ctx| {
assert_eq!(
workspace_view
.read(ctx)
.active_pane()
.read(ctx)
.items()
.len(),
1
)
});
// Open the second entry
workspace_view.update(app, |w, ctx| w.open_entry(entries[1], ctx));
workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[1], ctx));
app.finish_pending_tasks().await;
let active_pane = workspace_view.as_ref(app).active_pane().as_ref(app);
assert_eq!(active_pane.items().len(), 2);
assert_eq!(
active_pane.active_item().unwrap().entry_id(app.as_ref()),
Some(entries[1])
);
app.read(|ctx| {
let active_pane = workspace_view.read(ctx).active_pane().read(ctx);
assert_eq!(active_pane.items().len(), 2);
assert_eq!(
active_pane.active_item().unwrap().entry_id(ctx),
Some(entries[1])
);
});
// Open the first entry again
workspace_view.update(app, |w, ctx| w.open_entry(entries[0], ctx));
workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[0], ctx));
app.finish_pending_tasks().await;
let active_pane = workspace_view.as_ref(app).active_pane().as_ref(app);
assert_eq!(active_pane.items().len(), 2);
assert_eq!(
active_pane.active_item().unwrap().entry_id(app.as_ref()),
Some(entries[0])
);
app.read(|ctx| {
let active_pane = workspace_view.read(ctx).active_pane().read(ctx);
assert_eq!(active_pane.items().len(), 2);
assert_eq!(
active_pane.active_item().unwrap().entry_id(ctx),
Some(entries[0])
);
});
// Open the third entry twice concurrently
workspace_view.update(app, |w, ctx| {
workspace_view.update(&mut app, |w, ctx| {
w.open_entry(entries[2], ctx);
w.open_entry(entries[2], ctx);
});
app.finish_pending_tasks().await;
assert_eq!(
workspace_view
.as_ref(app)
.active_pane()
.as_ref(app)
.items()
.len(),
3
);
app.read(|ctx| {
assert_eq!(
workspace_view
.read(ctx)
.active_pane()
.read(ctx)
.items()
.len(),
3
);
});
});
}
#[test]
fn test_pane_actions() {
App::test_async((), |app| async move {
pane::init(app);
App::test_async((), |mut app| async move {
app.update(|ctx| pane::init(ctx));
let dir = temp_tree(json!({
"a": {
@@ -479,37 +487,41 @@ mod tests {
},
}));
let settings = settings::channel(app.font_cache()).unwrap().1;
let settings = settings::channel(&app.font_cache()).unwrap().1;
let workspace = app.add_model(|ctx| Workspace::new(vec![dir.path().into()], ctx));
app.finish_pending_tasks().await; // Open and populate worktree.
let entries = workspace.file_entries(app);
let entries = app.read(|ctx| workspace.file_entries(ctx));
let (window_id, workspace_view) =
app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx));
workspace_view.update(app, |w, ctx| w.open_entry(entries[0], ctx));
workspace_view.update(&mut app, |w, ctx| w.open_entry(entries[0], ctx));
app.finish_pending_tasks().await;
let pane_1 = workspace_view.as_ref(app).active_pane().clone();
let pane_1 = app.read(|ctx| workspace_view.read(ctx).active_pane().clone());
app.dispatch_action(window_id, vec![pane_1.id()], "pane:split_right", ());
let pane_2 = workspace_view.as_ref(app).active_pane().clone();
assert_ne!(pane_1, pane_2);
app.update(|ctx| {
let pane_2 = workspace_view.read(ctx).active_pane().clone();
assert_ne!(pane_1, pane_2);
assert_eq!(
pane_2
.as_ref(app)
.active_item()
.unwrap()
.entry_id(app.downgrade()),
Some(entries[0])
);
assert_eq!(
pane_2
.read(ctx)
.active_item()
.unwrap()
.entry_id(ctx.as_ref()),
Some(entries[0])
);
app.dispatch_action(window_id, vec![pane_2.id()], "pane:close_active_item", ());
ctx.dispatch_action(window_id, vec![pane_2.id()], "pane:close_active_item", ());
});
let w = workspace_view.as_ref(app);
assert_eq!(w.panes.len(), 1);
assert_eq!(w.active_pane(), &pane_1);
app.read(|ctx| {
let w = workspace_view.read(ctx);
assert_eq!(w.panes.len(), 1);
assert_eq!(w.active_pane(), &pane_1);
})
});
}
}
+34 -26
View File
@@ -409,7 +409,7 @@ pub trait WorktreeHandle {
impl WorktreeHandle for ModelHandle<Worktree> {
fn file(&self, entry_id: usize, app: &AppContext) -> Result<FileHandle> {
if entry_id >= self.as_ref(app).entry_count() {
if entry_id >= self.read(app).entry_count() {
return Err(anyhow!("Entry does not exist in tree"));
}
@@ -461,15 +461,15 @@ pub struct FileHandle {
impl FileHandle {
pub fn path(&self, app: &AppContext) -> PathBuf {
self.worktree.as_ref(app).entry_path(self.entry_id).unwrap()
self.worktree.read(app).entry_path(self.entry_id).unwrap()
}
pub fn load_history(&self, app: &AppContext) -> impl Future<Output = Result<History>> {
self.worktree.as_ref(app).load_history(self.entry_id)
self.worktree.read(app).load_history(self.entry_id)
}
pub fn save<'a>(&self, content: Snapshot, ctx: &AppContext) -> Task<Result<()>> {
let worktree = self.worktree.as_ref(ctx);
let worktree = self.worktree.read(ctx);
worktree.save(self.entry_id, content, ctx)
}
@@ -649,7 +649,7 @@ mod test {
#[test]
fn test_populate_and_search() {
App::test_async((), |app| async move {
App::test_async((), |mut app| async move {
let dir = temp_tree(json!({
"root": {
"apple": "",
@@ -671,26 +671,28 @@ mod test {
let tree = app.add_model(|ctx| Worktree::new(1, root_link_path, Some(ctx)));
app.finish_pending_tasks().await;
let tree = tree.as_ref(app);
assert_eq!(tree.file_count(), 4);
let results = match_paths(&[tree.clone()], "bna", false, false, 10)
.iter()
.map(|result| tree.entry_path(result.entry_id))
.collect::<Result<Vec<PathBuf>, _>>()
.unwrap();
assert_eq!(
results,
vec![
PathBuf::from("root_link/banana/carrot/date"),
PathBuf::from("root_link/banana/carrot/endive"),
]
);
app.read(|ctx| {
let tree = tree.read(ctx);
assert_eq!(tree.file_count(), 4);
let results = match_paths(&[tree.clone()], "bna", false, false, 10)
.iter()
.map(|result| tree.entry_path(result.entry_id))
.collect::<Result<Vec<PathBuf>, _>>()
.unwrap();
assert_eq!(
results,
vec![
PathBuf::from("root_link/banana/carrot/date"),
PathBuf::from("root_link/banana/carrot/endive"),
]
);
})
});
}
#[test]
fn test_save_file() {
App::test_async((), |app| async move {
App::test_async((), |mut app| async move {
let dir = temp_tree(json!({
"file1": "the old contents",
}));
@@ -698,17 +700,23 @@ mod test {
let tree = app.add_model(|ctx| Worktree::new(1, dir.path(), Some(ctx)));
app.finish_pending_tasks().await;
let entry = tree.as_ref(app).files().next().unwrap();
assert_eq!(entry.path.file_name().unwrap(), "file1");
let file_id = entry.entry_id;
let buffer = Buffer::new(1, "a line of text.\n".repeat(10 * 1024));
tree.update(app, |tree, ctx| {
let entry = app.read(|ctx| {
let entry = tree.read(ctx).files().next().unwrap();
assert_eq!(entry.path.file_name().unwrap(), "file1");
entry
});
let file_id = entry.entry_id;
tree.update(&mut app, |tree, ctx| {
smol::block_on(tree.save(file_id, buffer.snapshot(), ctx.app())).unwrap()
});
let history = tree.as_ref(app).load_history(file_id).await.unwrap();
let history = app
.read(|ctx| tree.read(ctx).load_history(file_id))
.await
.unwrap();
assert_eq!(history.base_text, buffer.text());
});
}