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:
parent
448dace281
commit
97a8a8ed43
10 changed files with 317 additions and 315 deletions
210
gpui/src/app.rs
210
gpui/src/app.rs
|
@ -45,8 +45,8 @@ pub trait View: Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ModelAsRef {
|
pub trait ReadModel {
|
||||||
fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T;
|
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UpdateModel {
|
pub trait UpdateModel {
|
||||||
|
@ -56,8 +56,8 @@ pub trait UpdateModel {
|
||||||
F: FnOnce(&mut T, &mut ModelContext<T>) -> S;
|
F: FnOnce(&mut T, &mut ModelContext<T>) -> S;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ViewAsRef {
|
pub trait ReadView {
|
||||||
fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T;
|
fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UpdateView {
|
pub trait UpdateView {
|
||||||
|
@ -84,6 +84,9 @@ pub enum MenuItem<'a> {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct App(Rc<RefCell<MutableAppContext>>);
|
pub struct App(Rc<RefCell<MutableAppContext>>);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TestAppContext(Rc<RefCell<MutableAppContext>>);
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn test<T, A: AssetSource, F: FnOnce(&mut MutableAppContext) -> T>(
|
pub fn test<T, A: AssetSource, F: FnOnce(&mut MutableAppContext) -> T>(
|
||||||
asset_source: A,
|
asset_source: A,
|
||||||
|
@ -101,27 +104,21 @@ impl App {
|
||||||
f(&mut *ctx)
|
f(&mut *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_async<'a, T, F, A: AssetSource, Fn>(asset_source: A, f: Fn) -> T
|
pub fn test_async<T, F, A: AssetSource, Fn>(asset_source: A, f: Fn) -> T
|
||||||
where
|
where
|
||||||
Fn: FnOnce(&'a mut MutableAppContext) -> F,
|
Fn: FnOnce(TestAppContext) -> F,
|
||||||
F: Future<Output = T> + 'a,
|
F: Future<Output = T>,
|
||||||
{
|
{
|
||||||
let platform = platform::test::platform();
|
let platform = platform::test::platform();
|
||||||
let foreground = Rc::new(executor::Foreground::test());
|
let foreground = Rc::new(executor::Foreground::test());
|
||||||
let ctx = Rc::new(RefCell::new(MutableAppContext::new(
|
let ctx = TestAppContext(Rc::new(RefCell::new(MutableAppContext::new(
|
||||||
foreground.clone(),
|
foreground.clone(),
|
||||||
Rc::new(platform),
|
Rc::new(platform),
|
||||||
asset_source,
|
asset_source,
|
||||||
)));
|
))));
|
||||||
let mut ctx_ref = ctx.borrow_mut();
|
ctx.0.borrow_mut().weak_self = Some(Rc::downgrade(&ctx.0));
|
||||||
ctx_ref.weak_self = Some(Rc::downgrade(&ctx));
|
|
||||||
let ctx = &mut *ctx_ref;
|
|
||||||
|
|
||||||
// TODO - is there a better way of getting this to compile?
|
|
||||||
let ctx = unsafe { std::mem::transmute(ctx) };
|
|
||||||
let future = f(ctx);
|
let future = f(ctx);
|
||||||
|
|
||||||
drop(ctx_ref);
|
|
||||||
smol::block_on(foreground.run(future))
|
smol::block_on(foreground.run(future))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,42 +205,27 @@ impl App {
|
||||||
where
|
where
|
||||||
F: 'static + FnOnce(&mut MutableAppContext),
|
F: 'static + FnOnce(&mut MutableAppContext),
|
||||||
{
|
{
|
||||||
let platform = self.platform();
|
let platform = self.0.borrow().platform.clone();
|
||||||
platform.run(Box::new(move || {
|
platform.run(Box::new(move || {
|
||||||
let mut ctx = self.0.borrow_mut();
|
let mut ctx = self.0.borrow_mut();
|
||||||
on_finish_launching(&mut *ctx);
|
on_finish_launching(&mut *ctx);
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_window_invalidated<F: 'static + FnMut(WindowInvalidation, &mut MutableAppContext)>(
|
pub fn font_cache(&self) -> Arc<FontCache> {
|
||||||
&self,
|
self.0.borrow().font_cache.clone()
|
||||||
window_id: usize,
|
|
||||||
callback: F,
|
|
||||||
) {
|
|
||||||
self.0
|
|
||||||
.borrow_mut()
|
|
||||||
.on_window_invalidated(window_id, callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_action<S, V, T, F>(&self, name: S, handler: F)
|
fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
|
||||||
where
|
let mut state = self.0.borrow_mut();
|
||||||
S: Into<String>,
|
state.pending_flushes += 1;
|
||||||
V: View,
|
let result = callback(&mut *state);
|
||||||
T: Any,
|
state.flush_effects();
|
||||||
F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>),
|
result
|
||||||
{
|
|
||||||
self.0.borrow_mut().add_action(name, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_global_action<S, T, F>(&self, name: S, handler: F)
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
T: 'static + Any,
|
|
||||||
F: 'static + FnMut(&T, &mut MutableAppContext),
|
|
||||||
{
|
|
||||||
self.0.borrow_mut().add_global_action(name, handler);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestAppContext {
|
||||||
pub fn dispatch_action<T: 'static + Any>(
|
pub fn dispatch_action<T: 'static + Any>(
|
||||||
&self,
|
&self,
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
|
@ -259,10 +241,6 @@ impl App {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&self, bindings: T) {
|
|
||||||
self.0.borrow_mut().add_bindings(bindings);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dispatch_keystroke(
|
pub fn dispatch_keystroke(
|
||||||
&self,
|
&self,
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
|
@ -329,7 +307,7 @@ impl App {
|
||||||
handle
|
handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<T, F: FnOnce(&AppContext) -> T>(&mut self, callback: F) -> T {
|
pub fn read<T, F: FnOnce(&AppContext) -> T>(&self, callback: F) -> T {
|
||||||
callback(self.0.borrow().downgrade())
|
callback(self.0.borrow().downgrade())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +332,7 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateModel for App {
|
impl UpdateModel for TestAppContext {
|
||||||
fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
|
fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
|
||||||
where
|
where
|
||||||
T: Entity,
|
T: Entity,
|
||||||
|
@ -368,7 +346,7 @@ impl UpdateModel for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateView for App {
|
impl UpdateView for TestAppContext {
|
||||||
fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
|
fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
|
||||||
where
|
where
|
||||||
T: View,
|
T: View,
|
||||||
|
@ -1249,8 +1227,8 @@ impl MutableAppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelAsRef for MutableAppContext {
|
impl ReadModel for MutableAppContext {
|
||||||
fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
||||||
if let Some(model) = self.ctx.models.get(&handle.model_id) {
|
if let Some(model) = self.ctx.models.get(&handle.model_id) {
|
||||||
model
|
model
|
||||||
.as_any()
|
.as_any()
|
||||||
|
@ -1287,8 +1265,8 @@ impl UpdateModel for MutableAppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ViewAsRef for MutableAppContext {
|
impl ReadView for MutableAppContext {
|
||||||
fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
|
fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
|
||||||
if let Some(window) = self.ctx.windows.get(&handle.window_id) {
|
if let Some(window) = self.ctx.windows.get(&handle.window_id) {
|
||||||
if let Some(view) = window.views.get(&handle.view_id) {
|
if let Some(view) = window.views.get(&handle.view_id) {
|
||||||
view.as_any().downcast_ref().expect("Downcast is type safe")
|
view.as_any().downcast_ref().expect("Downcast is type safe")
|
||||||
|
@ -1387,8 +1365,8 @@ impl AppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelAsRef for AppContext {
|
impl ReadModel for AppContext {
|
||||||
fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
||||||
if let Some(model) = self.models.get(&handle.model_id) {
|
if let Some(model) = self.models.get(&handle.model_id) {
|
||||||
model
|
model
|
||||||
.as_any()
|
.as_any()
|
||||||
|
@ -1400,8 +1378,8 @@ impl ModelAsRef for AppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ViewAsRef for AppContext {
|
impl ReadView for AppContext {
|
||||||
fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
|
fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
|
||||||
if let Some(window) = self.windows.get(&handle.window_id) {
|
if let Some(window) = self.windows.get(&handle.window_id) {
|
||||||
if let Some(view) = window.views.get(&handle.view_id) {
|
if let Some(view) = window.views.get(&handle.view_id) {
|
||||||
view.as_any()
|
view.as_any()
|
||||||
|
@ -1672,9 +1650,9 @@ impl<'a, T: Entity> ModelContext<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> ModelAsRef for ModelContext<'_, M> {
|
impl<M> ReadModel for ModelContext<'_, M> {
|
||||||
fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
||||||
self.app.model(handle)
|
self.app.read_model(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1927,9 +1905,9 @@ impl<'a, T: View> ViewContext<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> ModelAsRef for ViewContext<'_, V> {
|
impl<V> ReadModel for ViewContext<'_, V> {
|
||||||
fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
|
||||||
self.app.model(handle)
|
self.app.read_model(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1943,9 +1921,9 @@ impl<V: View> UpdateModel for ViewContext<'_, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View> ViewAsRef for ViewContext<'_, V> {
|
impl<V: View> ReadView for ViewContext<'_, V> {
|
||||||
fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
|
fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
|
||||||
self.app.view(handle)
|
self.app.read_view(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1994,8 +1972,8 @@ impl<T: Entity> ModelHandle<T> {
|
||||||
self.model_id
|
self.model_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ref<'a, A: ModelAsRef>(&self, app: &'a A) -> &'a T {
|
pub fn read<'a, A: ReadModel>(&self, app: &'a A) -> &'a T {
|
||||||
app.model(self)
|
app.read_model(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
|
pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
|
||||||
|
@ -2122,8 +2100,8 @@ impl<T: View> ViewHandle<T> {
|
||||||
self.view_id
|
self.view_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ref<'a, A: ViewAsRef>(&self, app: &'a A) -> &'a T {
|
pub fn read<'a, A: ReadView>(&self, app: &'a A) -> &'a T {
|
||||||
app.view(self)
|
app.read_view(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
|
pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
|
||||||
|
@ -2470,9 +2448,9 @@ mod tests {
|
||||||
ctx.notify();
|
ctx.notify();
|
||||||
ctx.emit(2);
|
ctx.emit(2);
|
||||||
});
|
});
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec!["updated".to_string()]);
|
assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
handle_2.as_ref(app).events,
|
handle_2.read(app).events,
|
||||||
vec![
|
vec![
|
||||||
"observed event 1".to_string(),
|
"observed event 1".to_string(),
|
||||||
"notified".to_string(),
|
"notified".to_string(),
|
||||||
|
@ -2518,10 +2496,10 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
handle_2.update(app, |_, c| c.emit(7));
|
handle_2.update(app, |_, c| c.emit(7));
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec![7]);
|
assert_eq!(handle_1.read(app).events, vec![7]);
|
||||||
|
|
||||||
handle_2.update(app, |_, c| c.emit(5));
|
handle_2.update(app, |_, c| c.emit(5));
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5]);
|
assert_eq!(handle_1.read(app).events, vec![7, 10, 5]);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2544,9 +2522,9 @@ mod tests {
|
||||||
|
|
||||||
handle_1.update(app, |_, c| {
|
handle_1.update(app, |_, c| {
|
||||||
c.observe(&handle_2, move |model, observed, c| {
|
c.observe(&handle_2, move |model, observed, c| {
|
||||||
model.events.push(observed.as_ref(c).count);
|
model.events.push(observed.read(c).count);
|
||||||
c.observe(&handle_2b, |model, observed, c| {
|
c.observe(&handle_2b, |model, observed, c| {
|
||||||
model.events.push(observed.as_ref(c).count * 2);
|
model.events.push(observed.read(c).count * 2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2555,13 +2533,13 @@ mod tests {
|
||||||
model.count = 7;
|
model.count = 7;
|
||||||
c.notify()
|
c.notify()
|
||||||
});
|
});
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec![7]);
|
assert_eq!(handle_1.read(app).events, vec![7]);
|
||||||
|
|
||||||
handle_2.update(app, |model, c| {
|
handle_2.update(app, |model, c| {
|
||||||
model.count = 5;
|
model.count = 5;
|
||||||
c.notify()
|
c.notify()
|
||||||
});
|
});
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5])
|
assert_eq!(handle_1.read(app).events, vec![7, 10, 5])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2576,25 +2554,25 @@ mod tests {
|
||||||
type Event = ();
|
type Event = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let handle = app.add_model(|_| Model::default());
|
let handle = app.add_model(|_| Model::default());
|
||||||
handle
|
handle
|
||||||
.update(app, |_, c| {
|
.update(&mut app, |_, c| {
|
||||||
c.spawn(async { 7 }, |model, output, _| {
|
c.spawn(async { 7 }, |model, output, _| {
|
||||||
model.count = output;
|
model.count = output;
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(handle.as_ref(app).count, 7);
|
app.read(|ctx| assert_eq!(handle.read(ctx).count, 7));
|
||||||
|
|
||||||
handle
|
handle
|
||||||
.update(app, |_, c| {
|
.update(&mut app, |_, c| {
|
||||||
c.spawn(async { 14 }, |model, output, _| {
|
c.spawn(async { 14 }, |model, output, _| {
|
||||||
model.count = output;
|
model.count = output;
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(handle.as_ref(app).count, 14);
|
app.read(|ctx| assert_eq!(handle.read(ctx).count, 14));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2609,10 +2587,10 @@ mod tests {
|
||||||
type Event = ();
|
type Event = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let handle = app.add_model(|_| Model::default());
|
let handle = app.add_model(|_| Model::default());
|
||||||
handle
|
handle
|
||||||
.update(app, |_, c| {
|
.update(&mut app, |_, c| {
|
||||||
c.spawn_stream(
|
c.spawn_stream(
|
||||||
smol::stream::iter(vec![1, 2, 3]),
|
smol::stream::iter(vec![1, 2, 3]),
|
||||||
|model, output, _| {
|
|model, output, _| {
|
||||||
|
@ -2624,7 +2602,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(handle.as_ref(app).events, [Some(1), Some(2), Some(3), None])
|
app.read(|ctx| assert_eq!(handle.read(ctx).events, [Some(1), Some(2), Some(3), None]));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2674,9 +2652,9 @@ mod tests {
|
||||||
ctx.emit(1);
|
ctx.emit(1);
|
||||||
ctx.emit(2);
|
ctx.emit(2);
|
||||||
});
|
});
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec!["updated".to_string()]);
|
assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
handle_2.as_ref(app).events,
|
handle_2.read(app).events,
|
||||||
vec![
|
vec![
|
||||||
"observed event 1".to_string(),
|
"observed event 1".to_string(),
|
||||||
"observed event 2".to_string(),
|
"observed event 2".to_string(),
|
||||||
|
@ -2742,13 +2720,13 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
handle_2.update(app, |_, c| c.emit(7));
|
handle_2.update(app, |_, c| c.emit(7));
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec![7]);
|
assert_eq!(handle_1.read(app).events, vec![7]);
|
||||||
|
|
||||||
handle_2.update(app, |_, c| c.emit(5));
|
handle_2.update(app, |_, c| c.emit(5));
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5]);
|
assert_eq!(handle_1.read(app).events, vec![7, 10, 5]);
|
||||||
|
|
||||||
handle_3.update(app, |_, c| c.emit(9));
|
handle_3.update(app, |_, c| c.emit(9));
|
||||||
assert_eq!(handle_1.as_ref(app).events, vec![7, 10, 5, 9]);
|
assert_eq!(handle_1.read(app).events, vec![7, 10, 5, 9]);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2837,7 +2815,7 @@ mod tests {
|
||||||
|
|
||||||
view.update(app, |_, c| {
|
view.update(app, |_, c| {
|
||||||
c.observe(&model, |me, observed, c| {
|
c.observe(&model, |me, observed, c| {
|
||||||
me.events.push(observed.as_ref(c).count)
|
me.events.push(observed.read(c).count)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2845,7 +2823,7 @@ mod tests {
|
||||||
model.count = 11;
|
model.count = 11;
|
||||||
c.notify();
|
c.notify();
|
||||||
});
|
});
|
||||||
assert_eq!(view.as_ref(app).events, vec![11]);
|
assert_eq!(view.read(app).events, vec![11]);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2942,7 +2920,7 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
view_1.as_ref(app).events,
|
view_1.read(app).events,
|
||||||
[
|
[
|
||||||
"self focused".to_string(),
|
"self focused".to_string(),
|
||||||
"self blurred".to_string(),
|
"self blurred".to_string(),
|
||||||
|
@ -2975,24 +2953,24 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let (_, handle) = app.add_window(|_| View::default());
|
let handle = app.add_window(|_| View::default()).1;
|
||||||
handle
|
handle
|
||||||
.update(app, |_, c| {
|
.update(&mut app, |_, c| {
|
||||||
c.spawn(async { 7 }, |me, output, _| {
|
c.spawn(async { 7 }, |me, output, _| {
|
||||||
me.count = output;
|
me.count = output;
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(handle.as_ref(app).count, 7);
|
app.read(|ctx| assert_eq!(handle.read(ctx).count, 7));
|
||||||
handle
|
handle
|
||||||
.update(app, |_, c| {
|
.update(&mut app, |_, c| {
|
||||||
c.spawn(async { 14 }, |me, output, _| {
|
c.spawn(async { 14 }, |me, output, _| {
|
||||||
me.count = output;
|
me.count = output;
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(handle.as_ref(app).count, 14);
|
app.read(|ctx| assert_eq!(handle.read(ctx).count, 14));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3017,10 +2995,10 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let (_, handle) = app.add_window(|_| View::default());
|
let (_, handle) = app.add_window(|_| View::default());
|
||||||
handle
|
handle
|
||||||
.update(app, |_, c| {
|
.update(&mut app, |_, c| {
|
||||||
c.spawn_stream(
|
c.spawn_stream(
|
||||||
smol::stream::iter(vec![1_usize, 2, 3]),
|
smol::stream::iter(vec![1_usize, 2, 3]),
|
||||||
|me, output, _| {
|
|me, output, _| {
|
||||||
|
@ -3033,7 +3011,7 @@ mod tests {
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert_eq!(handle.as_ref(app).events, [Some(1), Some(2), Some(3), None])
|
app.read(|ctx| assert_eq!(handle.read(ctx).events, [Some(1), Some(2), Some(3), None]))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3335,49 +3313,49 @@ mod tests {
|
||||||
type Event = ();
|
type Event = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let model = app.add_model(|_| Model);
|
let model = app.add_model(|_| Model);
|
||||||
let (_, view) = app.add_window(|_| View);
|
let (_, view) = app.add_window(|_| View);
|
||||||
|
|
||||||
model.update(app, |_, ctx| {
|
model.update(&mut app, |_, ctx| {
|
||||||
ctx.spawn(async {}, |_, _, _| {}).detach();
|
ctx.spawn(async {}, |_, _, _| {}).detach();
|
||||||
// Cancel this task
|
// Cancel this task
|
||||||
drop(ctx.spawn(async {}, |_, _, _| {}));
|
drop(ctx.spawn(async {}, |_, _, _| {}));
|
||||||
});
|
});
|
||||||
|
|
||||||
view.update(app, |_, ctx| {
|
view.update(&mut app, |_, ctx| {
|
||||||
ctx.spawn(async {}, |_, _, _| {}).detach();
|
ctx.spawn(async {}, |_, _, _| {}).detach();
|
||||||
// Cancel this task
|
// Cancel this task
|
||||||
drop(ctx.spawn(async {}, |_, _, _| {}));
|
drop(ctx.spawn(async {}, |_, _, _| {}));
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(!app.future_handlers.borrow().is_empty());
|
assert!(!app.0.borrow().future_handlers.borrow().is_empty());
|
||||||
app.finish_pending_tasks().await;
|
app.finish_pending_tasks().await;
|
||||||
assert!(app.future_handlers.borrow().is_empty());
|
assert!(app.0.borrow().future_handlers.borrow().is_empty());
|
||||||
app.finish_pending_tasks().await; // Don't block if there are no tasks
|
app.finish_pending_tasks().await; // Don't block if there are no tasks
|
||||||
|
|
||||||
model.update(app, |_, ctx| {
|
model.update(&mut app, |_, ctx| {
|
||||||
ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})
|
ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})
|
||||||
.detach();
|
.detach();
|
||||||
// Cancel this task
|
// Cancel this task
|
||||||
drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}));
|
drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}));
|
||||||
});
|
});
|
||||||
|
|
||||||
view.update(app, |_, ctx| {
|
view.update(&mut app, |_, ctx| {
|
||||||
ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})
|
ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})
|
||||||
.detach();
|
.detach();
|
||||||
// Cancel this task
|
// Cancel this task
|
||||||
drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}));
|
drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}));
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(!app.stream_handlers.borrow().is_empty());
|
assert!(!app.0.borrow().stream_handlers.borrow().is_empty());
|
||||||
app.finish_pending_tasks().await;
|
app.finish_pending_tasks().await;
|
||||||
assert!(app.stream_handlers.borrow().is_empty());
|
assert!(app.0.borrow().stream_handlers.borrow().is_empty());
|
||||||
app.finish_pending_tasks().await; // Don't block if there are no tasks
|
app.finish_pending_tasks().await; // Don't block if there are no tasks
|
||||||
|
|
||||||
// Tasks are considered finished when we drop handles
|
// Tasks are considered finished when we drop handles
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
model.update(app, |_, ctx| {
|
model.update(&mut app, |_, ctx| {
|
||||||
tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {})));
|
tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {})));
|
||||||
tasks.push(Box::new(ctx.spawn_stream(
|
tasks.push(Box::new(ctx.spawn_stream(
|
||||||
smol::stream::iter(vec![1, 2, 3]),
|
smol::stream::iter(vec![1, 2, 3]),
|
||||||
|
@ -3386,7 +3364,7 @@ mod tests {
|
||||||
)));
|
)));
|
||||||
});
|
});
|
||||||
|
|
||||||
view.update(app, |_, ctx| {
|
view.update(&mut app, |_, ctx| {
|
||||||
tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {})));
|
tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {})));
|
||||||
tasks.push(Box::new(ctx.spawn_stream(
|
tasks.push(Box::new(ctx.spawn_stream(
|
||||||
smol::stream::iter(vec![1, 2, 3]),
|
smol::stream::iter(vec![1, 2, 3]),
|
||||||
|
@ -3395,12 +3373,12 @@ mod tests {
|
||||||
)));
|
)));
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(!app.stream_handlers.borrow().is_empty());
|
assert!(!app.0.borrow().stream_handlers.borrow().is_empty());
|
||||||
|
|
||||||
let finish_pending_tasks = app.finish_pending_tasks();
|
let finish_pending_tasks = app.finish_pending_tasks();
|
||||||
drop(tasks);
|
drop(tasks);
|
||||||
finish_pending_tasks.await;
|
finish_pending_tasks.await;
|
||||||
assert!(app.stream_handlers.borrow().is_empty());
|
assert!(app.0.borrow().stream_handlers.borrow().is_empty());
|
||||||
app.finish_pending_tasks().await; // Don't block if there are no tasks
|
app.finish_pending_tasks().await; // Don't block if there are no tasks
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl BufferElement {
|
||||||
ctx: &mut EventContext,
|
ctx: &mut EventContext,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if paint.text_bounds.contains_point(position) {
|
if paint.text_bounds.contains_point(position) {
|
||||||
let view = self.view.as_ref(ctx.app);
|
let view = self.view.read(ctx.app);
|
||||||
let position =
|
let position =
|
||||||
paint.point_for_position(view, layout, position, ctx.font_cache, ctx.app);
|
paint.point_for_position(view, layout, position, ctx.font_cache, ctx.app);
|
||||||
ctx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd });
|
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 {
|
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);
|
ctx.dispatch_action("buffer:select", SelectAction::End);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -63,7 +63,7 @@ impl BufferElement {
|
||||||
paint: &mut PaintState,
|
paint: &mut PaintState,
|
||||||
ctx: &mut EventContext,
|
ctx: &mut EventContext,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let view = self.view.as_ref(ctx.app);
|
let view = self.view.read(ctx.app);
|
||||||
|
|
||||||
if view.is_selecting() {
|
if view.is_selecting() {
|
||||||
let rect = paint.text_bounds;
|
let rect = paint.text_bounds;
|
||||||
|
@ -145,7 +145,7 @@ impl BufferElement {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let view = self.view.as_ref(ctx.app);
|
let view = self.view.read(ctx.app);
|
||||||
let font_cache = &ctx.font_cache;
|
let font_cache = &ctx.font_cache;
|
||||||
let layout_cache = &ctx.text_layout_cache;
|
let layout_cache = &ctx.text_layout_cache;
|
||||||
let max_glyph_width = view.em_width(font_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) {
|
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 line_height = view.line_height(ctx.font_cache);
|
||||||
let scroll_top = view.scroll_position().y() * line_height;
|
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) {
|
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 line_height = view.line_height(ctx.font_cache);
|
||||||
let descent = view.font_descent(ctx.font_cache);
|
let descent = view.font_descent(ctx.font_cache);
|
||||||
let start_row = view.scroll_position().y() as u32;
|
let start_row = view.scroll_position().y() as u32;
|
||||||
|
@ -313,14 +313,14 @@ impl Element for BufferElement {
|
||||||
let app = ctx.app;
|
let app = ctx.app;
|
||||||
let mut size = constraint.max;
|
let mut size = constraint.max;
|
||||||
if size.y().is_infinite() {
|
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));
|
size.set_y((view.max_point(app).row() + 1) as f32 * view.line_height(ctx.font_cache));
|
||||||
}
|
}
|
||||||
if size.x().is_infinite() {
|
if size.x().is_infinite() {
|
||||||
unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
|
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 font_cache = &ctx.font_cache;
|
||||||
let layout_cache = &ctx.text_layout_cache;
|
let layout_cache = &ctx.text_layout_cache;
|
||||||
let line_height = view.line_height(font_cache);
|
let line_height = view.line_height(font_cache);
|
||||||
|
@ -404,7 +404,7 @@ impl Element for BufferElement {
|
||||||
if let Some(layout) = layout {
|
if let Some(layout) = layout {
|
||||||
let app = ctx.app.downgrade();
|
let app = ctx.app.downgrade();
|
||||||
|
|
||||||
let view = self.view.as_ref(app);
|
let view = self.view.read(app);
|
||||||
view.clamp_scroll_left(
|
view.clamp_scroll_left(
|
||||||
layout
|
layout
|
||||||
.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app)
|
.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app)
|
||||||
|
@ -437,7 +437,7 @@ impl Element for BufferElement {
|
||||||
layout.text_size,
|
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_gutter(gutter_bounds, layout, ctx);
|
||||||
}
|
}
|
||||||
self.paint_text(text_bounds, layout, ctx);
|
self.paint_text(text_bounds, layout, ctx);
|
||||||
|
|
|
@ -125,7 +125,7 @@ impl BufferView {
|
||||||
});
|
});
|
||||||
ctx.observe(&display_map, Self::on_display_map_changed);
|
ctx.observe(&display_map, Self::on_display_map_changed);
|
||||||
|
|
||||||
let buffer_ref = buffer.as_ref(ctx);
|
let buffer_ref = buffer.read(ctx);
|
||||||
Self {
|
Self {
|
||||||
handle: ctx.handle().downgrade(),
|
handle: ctx.handle().downgrade(),
|
||||||
buffer,
|
buffer,
|
||||||
|
@ -188,7 +188,7 @@ impl BufferView {
|
||||||
return false;
|
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 visible_lines = viewport_height / line_height;
|
||||||
let first_cursor_top = self
|
let first_cursor_top = self
|
||||||
.selections
|
.selections
|
||||||
|
@ -238,7 +238,7 @@ impl BufferView {
|
||||||
layouts: &[Arc<text_layout::Line>],
|
layouts: &[Arc<text_layout::Line>],
|
||||||
app: &AppContext,
|
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_left = std::f32::INFINITY;
|
||||||
let mut target_right = 0.0_f32;
|
let mut target_right = 0.0_f32;
|
||||||
|
@ -287,7 +287,7 @@ impl BufferView {
|
||||||
ctx.emit(Event::Activate);
|
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
|
let cursor = display_map
|
||||||
.anchor_before(position, Bias::Left, ctx.app())
|
.anchor_before(position, Bias::Left, ctx.app())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -312,8 +312,8 @@ impl BufferView {
|
||||||
scroll_position: Vector2F,
|
scroll_position: Vector2F,
|
||||||
ctx: &mut ViewContext<Self>,
|
ctx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.read(ctx);
|
||||||
let map = self.display_map.as_ref(ctx);
|
let map = self.display_map.read(ctx);
|
||||||
let cursor = map.anchor_before(position, Bias::Left, ctx.app()).unwrap();
|
let cursor = map.anchor_before(position, Bias::Left, ctx.app()).unwrap();
|
||||||
if let Some(selection) = self.pending_selection.as_mut() {
|
if let Some(selection) = self.pending_selection.as_mut() {
|
||||||
selection.set_head(buffer, cursor);
|
selection.set_head(buffer, cursor);
|
||||||
|
@ -347,8 +347,8 @@ impl BufferView {
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = &'a Range<DisplayPoint>>,
|
T: IntoIterator<Item = &'a Range<DisplayPoint>>,
|
||||||
{
|
{
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.read(ctx);
|
||||||
let map = self.display_map.as_ref(ctx);
|
let map = self.display_map.read(ctx);
|
||||||
let mut selections = Vec::new();
|
let mut selections = Vec::new();
|
||||||
for range in ranges {
|
for range in ranges {
|
||||||
selections.push(Selection {
|
selections.push(Selection {
|
||||||
|
@ -366,7 +366,7 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) {
|
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();
|
let mut offset_ranges = SmallVec::<[Range<usize>; 32]>::new();
|
||||||
for selection in &self.selections {
|
for selection in &self.selections {
|
||||||
let start = selection.start.to_offset(buffer).unwrap();
|
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 char_count = text.chars().count() as isize;
|
||||||
let mut delta = 0_isize;
|
let mut delta = 0_isize;
|
||||||
self.selections = offset_ranges
|
self.selections = offset_ranges
|
||||||
|
@ -416,8 +416,8 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.read(ctx);
|
||||||
let map = self.display_map.as_ref(ctx);
|
let map = self.display_map.read(ctx);
|
||||||
for selection in &mut self.selections {
|
for selection in &mut self.selections {
|
||||||
if selection.range(buffer).is_empty() {
|
if selection.range(buffer).is_empty() {
|
||||||
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
|
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>) {
|
pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
{
|
{
|
||||||
let app = ctx.app();
|
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 {
|
for selection in &mut self.selections {
|
||||||
let start = selection.start.to_display_point(map, app).unwrap();
|
let start = selection.start.to_display_point(map, app).unwrap();
|
||||||
let end = selection.end.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>) {
|
pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
{
|
{
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.read(ctx);
|
||||||
let map = self.display_map.as_ref(ctx);
|
let map = self.display_map.read(ctx);
|
||||||
for selection in &mut self.selections {
|
for selection in &mut self.selections {
|
||||||
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
|
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
|
||||||
let cursor = map
|
let cursor = map
|
||||||
|
@ -483,7 +483,7 @@ impl BufferView {
|
||||||
pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
{
|
{
|
||||||
let app = ctx.app();
|
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 {
|
for selection in &mut self.selections {
|
||||||
let start = selection.start.to_display_point(map, app).unwrap();
|
let start = selection.start.to_display_point(map, app).unwrap();
|
||||||
let end = selection.end.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>) {
|
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 app = ctx.app();
|
||||||
let map = self.display_map.as_ref(app);
|
let map = self.display_map.read(app);
|
||||||
for selection in &mut self.selections {
|
for selection in &mut self.selections {
|
||||||
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
|
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
|
||||||
let cursor = map
|
let cursor = map
|
||||||
|
@ -526,7 +526,7 @@ impl BufferView {
|
||||||
ctx.propagate_action();
|
ctx.propagate_action();
|
||||||
} else {
|
} else {
|
||||||
let app = ctx.app();
|
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 {
|
for selection in &mut self.selections {
|
||||||
let start = selection.start.to_display_point(map, app).unwrap();
|
let start = selection.start.to_display_point(map, app).unwrap();
|
||||||
let end = selection.end.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();
|
ctx.propagate_action();
|
||||||
} else {
|
} else {
|
||||||
let app = ctx.app();
|
let app = ctx.app();
|
||||||
let buffer = self.buffer.as_ref(app);
|
let buffer = self.buffer.read(app);
|
||||||
let map = self.display_map.as_ref(app);
|
let map = self.display_map.read(app);
|
||||||
for selection in &mut self.selections {
|
for selection in &mut self.selections {
|
||||||
let head = selection.head().to_display_point(map, app).unwrap();
|
let head = selection.head().to_display_point(map, app).unwrap();
|
||||||
let (head, goal_column) =
|
let (head, goal_column) =
|
||||||
|
@ -569,7 +569,7 @@ impl BufferView {
|
||||||
ctx.propagate_action();
|
ctx.propagate_action();
|
||||||
} else {
|
} else {
|
||||||
let app = ctx.app();
|
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 {
|
for selection in &mut self.selections {
|
||||||
let start = selection.start.to_display_point(map, app).unwrap();
|
let start = selection.start.to_display_point(map, app).unwrap();
|
||||||
let end = selection.end.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();
|
ctx.propagate_action();
|
||||||
} else {
|
} else {
|
||||||
let app = ctx.app();
|
let app = ctx.app();
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.read(ctx);
|
||||||
let map = self.display_map.as_ref(ctx);
|
let map = self.display_map.read(ctx);
|
||||||
for selection in &mut self.selections {
|
for selection in &mut self.selections {
|
||||||
let head = selection.head().to_display_point(map, app).unwrap();
|
let head = selection.head().to_display_point(map, app).unwrap();
|
||||||
let (head, goal_column) =
|
let (head, goal_column) =
|
||||||
|
@ -615,7 +615,7 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_selections(&mut self, ctx: &AppContext) {
|
fn merge_selections(&mut self, ctx: &AppContext) {
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.read(ctx);
|
||||||
let mut i = 1;
|
let mut i = 1;
|
||||||
while i < self.selections.len() {
|
while i < self.selections.len() {
|
||||||
if self.selections[i - 1]
|
if self.selections[i - 1]
|
||||||
|
@ -651,14 +651,14 @@ impl BufferView {
|
||||||
self.selections
|
self.selections
|
||||||
.first()
|
.first()
|
||||||
.unwrap()
|
.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> {
|
pub fn last_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
|
||||||
self.selections
|
self.selections
|
||||||
.last()
|
.last()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.display_range(self.display_map.as_ref(app), app)
|
.display_range(self.display_map.read(app), app)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selections_in_range<'a>(
|
pub fn selections_in_range<'a>(
|
||||||
|
@ -666,7 +666,7 @@ impl BufferView {
|
||||||
range: Range<DisplayPoint>,
|
range: Range<DisplayPoint>,
|
||||||
app: &'a AppContext,
|
app: &'a AppContext,
|
||||||
) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
|
) -> 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 = map.anchor_before(range.start, Bias::Left, app).unwrap();
|
||||||
let start_index = self.selection_insertion_index(&start, app);
|
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 {
|
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
|
match self
|
||||||
.selections
|
.selections
|
||||||
|
@ -720,7 +720,7 @@ impl BufferView {
|
||||||
let mut fold_ranges = Vec::new();
|
let mut fold_ranges = Vec::new();
|
||||||
|
|
||||||
let app = ctx.app();
|
let app = ctx.app();
|
||||||
let map = self.display_map.as_ref(app);
|
let map = self.display_map.read(app);
|
||||||
for selection in &self.selections {
|
for selection in &self.selections {
|
||||||
let (start, end) = selection.display_range(map, app).sorted();
|
let (start, end) = selection.display_range(map, app).sorted();
|
||||||
let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row;
|
let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row;
|
||||||
|
@ -750,8 +750,8 @@ impl BufferView {
|
||||||
use super::RangeExt;
|
use super::RangeExt;
|
||||||
|
|
||||||
let app = ctx.app();
|
let app = ctx.app();
|
||||||
let map = self.display_map.as_ref(app);
|
let map = self.display_map.read(app);
|
||||||
let buffer = self.buffer.as_ref(app);
|
let buffer = self.buffer.read(app);
|
||||||
let ranges = self
|
let ranges = self
|
||||||
.selections
|
.selections
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -796,7 +796,7 @@ impl BufferView {
|
||||||
let mut is_blank = true;
|
let mut is_blank = true;
|
||||||
for c in self
|
for c in self
|
||||||
.display_map
|
.display_map
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.chars_at(DisplayPoint::new(display_row, 0), app)?
|
.chars_at(DisplayPoint::new(display_row, 0), app)?
|
||||||
{
|
{
|
||||||
if c == ' ' {
|
if c == ' ' {
|
||||||
|
@ -810,7 +810,7 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Result<Range<Point>> {
|
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 max_point = self.max_point(app);
|
||||||
|
|
||||||
let (start_indent, _) = self.line_indent(start_row, 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>) {
|
pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
self.display_map.update(ctx, |map, ctx| {
|
self.display_map.update(ctx, |map, ctx| {
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.read(ctx);
|
||||||
let ranges = self
|
let ranges = self
|
||||||
.selections
|
.selections
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -842,23 +842,23 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line(&self, display_row: u32, app: &AppContext) -> Result<String> {
|
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> {
|
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 {
|
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 {
|
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 {
|
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 {
|
pub fn font_size(&self) -> f32 {
|
||||||
|
@ -902,7 +902,7 @@ impl BufferView {
|
||||||
let font_size = settings.buffer_font_size;
|
let font_size = settings.buffer_font_size;
|
||||||
let font_id =
|
let font_id =
|
||||||
font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
|
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()
|
.log10()
|
||||||
.floor() as usize
|
.floor() as usize
|
||||||
+ 1;
|
+ 1;
|
||||||
|
@ -923,7 +923,7 @@ impl BufferView {
|
||||||
layout_cache: &TextLayoutCache,
|
layout_cache: &TextLayoutCache,
|
||||||
app: &AppContext,
|
app: &AppContext,
|
||||||
) -> Result<Vec<Arc<text_layout::Line>>> {
|
) -> 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 settings = smol::block_on(self.settings.read());
|
||||||
let font_size = settings.buffer_font_size;
|
let font_size = settings.buffer_font_size;
|
||||||
|
@ -959,7 +959,7 @@ impl BufferView {
|
||||||
layout_cache: &TextLayoutCache,
|
layout_cache: &TextLayoutCache,
|
||||||
app: &AppContext,
|
app: &AppContext,
|
||||||
) -> Result<Vec<Arc<text_layout::Line>>> {
|
) -> 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);
|
rows.end = cmp::min(rows.end, display_map.max_point(app).row() + 1);
|
||||||
if rows.start >= rows.end {
|
if rows.start >= rows.end {
|
||||||
|
@ -1149,7 +1149,7 @@ impl workspace::ItemView for BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn title(&self, app: &AppContext) -> std::string::String {
|
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()
|
path.file_name()
|
||||||
.expect("buffer's path is always to a file")
|
.expect("buffer's path is always to a file")
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
|
@ -1160,7 +1160,7 @@ impl workspace::ItemView for BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entry_id(&self, app: &AppContext) -> Option<(usize, usize)> {
|
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>
|
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 {
|
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);
|
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
|
let selections = view
|
||||||
.selections_in_range(
|
.selections_in_range(
|
||||||
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
||||||
|
@ -1271,7 +1271,7 @@ mod tests {
|
||||||
view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
|
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
|
let selections = view
|
||||||
.selections_in_range(
|
.selections_in_range(
|
||||||
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
||||||
|
@ -1287,7 +1287,7 @@ mod tests {
|
||||||
view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
|
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
|
let selections = view
|
||||||
.selections_in_range(
|
.selections_in_range(
|
||||||
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
||||||
|
@ -1304,7 +1304,7 @@ mod tests {
|
||||||
view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
|
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
|
let selections = view
|
||||||
.selections_in_range(
|
.selections_in_range(
|
||||||
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
||||||
|
@ -1321,7 +1321,7 @@ mod tests {
|
||||||
view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx);
|
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
|
let selections = view
|
||||||
.selections_in_range(
|
.selections_in_range(
|
||||||
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
||||||
|
@ -1340,7 +1340,7 @@ mod tests {
|
||||||
view.end_selection(ctx);
|
view.end_selection(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
let view = buffer_view.as_ref(app);
|
let view = buffer_view.read(app);
|
||||||
let selections = view
|
let selections = view
|
||||||
.selections_in_range(
|
.selections_in_range(
|
||||||
DisplayPoint::zero()..view.max_point(app.as_ref()),
|
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));
|
app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
|
||||||
|
|
||||||
let layouts = view
|
let layouts = view
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref())
|
.layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(layouts.len(), 6);
|
assert_eq!(layouts.len(), 6);
|
||||||
|
@ -1460,7 +1460,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
view.unfold(&(), ctx);
|
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!(
|
assert_eq!(
|
||||||
buffer.as_ref(app).text(),
|
buffer.read(app).text(),
|
||||||
"oe two three\nfou five six\nseven ten\n"
|
"oe two three\nfou five six\nseven ten\n"
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub struct FoldMap {
|
||||||
|
|
||||||
impl FoldMap {
|
impl FoldMap {
|
||||||
pub fn new(buffer: ModelHandle<Buffer>, app: &AppContext) -> Self {
|
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 {
|
Self {
|
||||||
buffer,
|
buffer,
|
||||||
folds: Vec::new(),
|
folds: Vec::new(),
|
||||||
|
@ -72,7 +72,7 @@ impl FoldMap {
|
||||||
let offset = self.to_display_offset(point, app)?;
|
let offset = self.to_display_offset(point, app)?;
|
||||||
let mut cursor = self.transforms.cursor();
|
let mut cursor = self.transforms.cursor();
|
||||||
cursor.seek(&offset, SeekBias::Right);
|
cursor.seek(&offset, SeekBias::Right);
|
||||||
let buffer = self.buffer.as_ref(app);
|
let buffer = self.buffer.read(app);
|
||||||
Ok(Chars {
|
Ok(Chars {
|
||||||
cursor,
|
cursor,
|
||||||
offset: offset.0,
|
offset: offset.0,
|
||||||
|
@ -95,7 +95,7 @@ impl FoldMap {
|
||||||
app: &AppContext,
|
app: &AppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
let buffer = self.buffer.as_ref(app);
|
let buffer = self.buffer.read(app);
|
||||||
for range in ranges.into_iter() {
|
for range in ranges.into_iter() {
|
||||||
let start = range.start.to_offset(buffer)?;
|
let start = range.start.to_offset(buffer)?;
|
||||||
let end = range.end.to_offset(buffer)?;
|
let end = range.end.to_offset(buffer)?;
|
||||||
|
@ -124,7 +124,7 @@ impl FoldMap {
|
||||||
ranges: impl IntoIterator<Item = Range<T>>,
|
ranges: impl IntoIterator<Item = Range<T>>,
|
||||||
app: &AppContext,
|
app: &AppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let buffer = self.buffer.as_ref(app);
|
let buffer = self.buffer.read(app);
|
||||||
|
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
for range in ranges.into_iter() {
|
for range in ranges.into_iter() {
|
||||||
|
@ -184,7 +184,7 @@ impl FoldMap {
|
||||||
.ok_or_else(|| anyhow!("display point {:?} is out of range", point))?;
|
.ok_or_else(|| anyhow!("display point {:?} is out of range", point))?;
|
||||||
assert!(transform.display_text.is_none());
|
assert!(transform.display_text.is_none());
|
||||||
let end_buffer_offset =
|
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;
|
offset += end_buffer_offset - cursor.start().buffer.chars;
|
||||||
}
|
}
|
||||||
Ok(DisplayOffset(offset))
|
Ok(DisplayOffset(offset))
|
||||||
|
@ -208,7 +208,7 @@ impl FoldMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_edits(&mut self, edits: &[Edit], app: &AppContext) -> Result<()> {
|
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 edits = edits.iter().cloned().peekable();
|
||||||
|
|
||||||
let mut new_transforms = SumTree::new();
|
let mut new_transforms = SumTree::new();
|
||||||
|
@ -597,7 +597,7 @@ mod tests {
|
||||||
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
|
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 fold_count = rng.gen_range(0..10);
|
||||||
let mut fold_ranges: Vec<Range<usize>> = Vec::new();
|
let mut fold_ranges: Vec<Range<usize>> = Vec::new();
|
||||||
|
@ -632,7 +632,7 @@ mod tests {
|
||||||
|
|
||||||
map.apply_edits(&edits, app.as_ref()).unwrap();
|
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_text = buffer.text();
|
||||||
let mut expected_buffer_rows = Vec::new();
|
let mut expected_buffer_rows = Vec::new();
|
||||||
let mut next_row = buffer.max_point().row;
|
let mut next_row = buffer.max_point().row;
|
||||||
|
@ -694,7 +694,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merged_fold_ranges(&self, app: &AppContext) -> Vec<Range<usize>> {
|
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
|
let mut fold_ranges = self
|
||||||
.folds
|
.folds
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -108,7 +108,7 @@ impl DisplayMap {
|
||||||
app: &AppContext,
|
app: &AppContext,
|
||||||
) -> Result<Anchor> {
|
) -> Result<Anchor> {
|
||||||
self.buffer
|
self.buffer
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.anchor_before(point.to_buffer_point(self, bias, app)?)
|
.anchor_before(point.to_buffer_point(self, bias, app)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ impl DisplayMap {
|
||||||
app: &AppContext,
|
app: &AppContext,
|
||||||
) -> Result<Anchor> {
|
) -> Result<Anchor> {
|
||||||
self.buffer
|
self.buffer
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.anchor_after(point.to_buffer_point(self, bias, app)?)
|
.anchor_after(point.to_buffer_point(self, bias, app)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ impl Point {
|
||||||
|
|
||||||
impl Anchor {
|
impl Anchor {
|
||||||
pub fn to_display_point(&self, map: &DisplayMap, app: &AppContext) -> Result<DisplayPoint> {
|
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)
|
.to_display_point(map, app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@ mod tests {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let map = map.as_ref(app);
|
let map = map.read(app);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.chars_at(DisplayPoint::new(1, 0), app.as_ref())
|
map.chars_at(DisplayPoint::new(1, 0), app.as_ref())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -368,7 +368,7 @@ mod tests {
|
||||||
let buffer = app.add_model(|_| Buffer::new(0, "aaa\n\t\tbbb"));
|
let buffer = app.add_model(|_| Buffer::new(0, "aaa\n\t\tbbb"));
|
||||||
let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx));
|
let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.as_ref(app).max_point(app.as_ref()),
|
map.read(app).max_point(app.as_ref()),
|
||||||
DisplayPoint::new(1, 11)
|
DisplayPoint::new(1, 11)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
|
@ -114,7 +114,7 @@ impl FileFinder {
|
||||||
self.matches.len(),
|
self.matches.len(),
|
||||||
move |mut range, items, app| {
|
move |mut range, items, app| {
|
||||||
let finder = handle.upgrade(app).unwrap();
|
let finder = handle.upgrade(app).unwrap();
|
||||||
let finder = finder.as_ref(app);
|
let finder = finder.read(app);
|
||||||
let start = range.start;
|
let start = range.start;
|
||||||
range.end = cmp::min(range.end, finder.matches.len());
|
range.end = cmp::min(range.end, finder.matches.len());
|
||||||
items.extend(finder.matches[range].iter().enumerate().filter_map(
|
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>) {
|
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(
|
fn on_query_buffer_event(
|
||||||
|
@ -299,7 +299,7 @@ impl FileFinder {
|
||||||
use buffer_view::Event::*;
|
use buffer_view::Event::*;
|
||||||
match event {
|
match event {
|
||||||
Edited => {
|
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() {
|
if query.is_empty() {
|
||||||
self.latest_search_id = util::post_inc(&mut self.search_count);
|
self.latest_search_id = util::post_inc(&mut self.search_count);
|
||||||
self.matches.clear();
|
self.matches.clear();
|
||||||
|
@ -371,18 +371,18 @@ impl FileFinder {
|
||||||
|
|
||||||
fn worktree<'a>(&'a self, tree_id: usize, app: &'a AppContext) -> Option<&'a Worktree> {
|
fn worktree<'a>(&'a self, tree_id: usize, app: &'a AppContext) -> Option<&'a Worktree> {
|
||||||
self.workspace
|
self.workspace
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.worktrees()
|
.worktrees()
|
||||||
.get(&tree_id)
|
.get(&tree_id)
|
||||||
.map(|worktree| worktree.as_ref(app))
|
.map(|worktree| worktree.read(app))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worktrees(&self, app: &AppContext) -> Vec<Worktree> {
|
fn worktrees(&self, app: &AppContext) -> Vec<Worktree> {
|
||||||
self.workspace
|
self.workspace
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.worktrees()
|
.worktrees()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|worktree| worktree.as_ref(app).clone())
|
.map(|worktree| worktree.read(app).clone())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_matching_paths() {
|
fn test_matching_paths() {
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let tmp_dir = TempDir::new("example").unwrap();
|
let tmp_dir = TempDir::new("example").unwrap();
|
||||||
fs::create_dir(tmp_dir.path().join("a")).await.unwrap();
|
fs::create_dir(tmp_dir.path().join("a")).await.unwrap();
|
||||||
fs::write(tmp_dir.path().join("a/banana"), "banana")
|
fs::write(tmp_dir.path().join("a/banana"), "banana")
|
||||||
|
@ -409,8 +409,10 @@ mod tests {
|
||||||
fs::write(tmp_dir.path().join("a/bandana"), "bandana")
|
fs::write(tmp_dir.path().join("a/bandana"), "bandana")
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
super::init(app);
|
app.update(|ctx| {
|
||||||
editor::init(app);
|
super::init(ctx);
|
||||||
|
editor::init(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
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![tmp_dir.path().into()], ctx));
|
let workspace = app.add_model(|ctx| Workspace::new(vec![tmp_dir.path().into()], ctx));
|
||||||
|
@ -424,14 +426,16 @@ mod tests {
|
||||||
(),
|
(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let finder = workspace_view
|
let finder = app.read(|ctx| {
|
||||||
.as_ref(app)
|
workspace_view
|
||||||
.modal()
|
.read(ctx)
|
||||||
.cloned()
|
.modal()
|
||||||
.unwrap()
|
.cloned()
|
||||||
.downcast::<FileFinder>()
|
.unwrap()
|
||||||
.unwrap();
|
.downcast::<FileFinder>()
|
||||||
let query_buffer = finder.as_ref(app).query_buffer.clone();
|
.unwrap()
|
||||||
|
});
|
||||||
|
let query_buffer = app.read(|ctx| finder.read(ctx).query_buffer.clone());
|
||||||
|
|
||||||
let chain = vec![finder.id(), query_buffer.id()];
|
let chain = vec![finder.id(), query_buffer.id()];
|
||||||
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string());
|
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string());
|
||||||
|
|
|
@ -109,9 +109,9 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
workspace_view_1
|
workspace_view_1
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.workspace
|
.workspace
|
||||||
.as_ref(app)
|
.read(app)
|
||||||
.worktrees()
|
.worktrees()
|
||||||
.len(),
|
.len(),
|
||||||
2
|
2
|
||||||
|
|
|
@ -101,7 +101,7 @@ impl Workspace {
|
||||||
pub fn contains_path(&self, path: &Path, app: &AppContext) -> bool {
|
pub fn contains_path(&self, path: &Path, app: &AppContext) -> bool {
|
||||||
self.worktrees
|
self.worktrees
|
||||||
.iter()
|
.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>) {
|
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>) {
|
pub fn open_path<'a>(&'a mut self, path: PathBuf, ctx: &mut ModelContext<Self>) {
|
||||||
for tree in self.worktrees.iter() {
|
for tree in self.worktrees.iter() {
|
||||||
if tree.as_ref(ctx).contains_path(&path) {
|
if tree.read(ctx).contains_path(&path) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,18 +200,18 @@ impl Entity for Workspace {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub trait WorkspaceHandle {
|
pub trait WorkspaceHandle {
|
||||||
fn file_entries(&self, app: &mut MutableAppContext) -> Vec<(usize, usize)>;
|
fn file_entries(&self, app: &AppContext) -> Vec<(usize, usize)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl WorkspaceHandle for ModelHandle<Workspace> {
|
impl WorkspaceHandle for ModelHandle<Workspace> {
|
||||||
fn file_entries(&self, app: &mut MutableAppContext) -> Vec<(usize, usize)> {
|
fn file_entries(&self, app: &AppContext) -> Vec<(usize, usize)> {
|
||||||
self.as_ref(app)
|
self.read(app)
|
||||||
.worktrees()
|
.worktrees()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|tree| {
|
.flat_map(|tree| {
|
||||||
let tree_id = tree.id();
|
let tree_id = tree.id();
|
||||||
tree.as_ref(app)
|
tree.read(app)
|
||||||
.files()
|
.files()
|
||||||
.map(move |file| (tree_id, file.entry_id))
|
.map(move |file| (tree_id, file.entry_id))
|
||||||
})
|
})
|
||||||
|
@ -228,7 +228,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_open_entry() {
|
fn test_open_entry() {
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let dir = temp_tree(json!({
|
let dir = temp_tree(json!({
|
||||||
"a": {
|
"a": {
|
||||||
"aa": "aa contents",
|
"aa": "aa contents",
|
||||||
|
@ -240,12 +240,12 @@ mod tests {
|
||||||
app.finish_pending_tasks().await; // Open and populate worktree.
|
app.finish_pending_tasks().await; // Open and populate worktree.
|
||||||
|
|
||||||
// Get the first file entry.
|
// Get the first file entry.
|
||||||
let tree = workspace.as_ref(app).worktrees.iter().next().unwrap();
|
let tree = app.read(|ctx| workspace.read(ctx).worktrees.iter().next().unwrap().clone());
|
||||||
let entry_id = tree.as_ref(app).files().next().unwrap().entry_id;
|
let entry_id = app.read(|ctx| tree.read(ctx).files().next().unwrap().entry_id);
|
||||||
let entry = (tree.id(), entry_id);
|
let entry = (tree.id(), entry_id);
|
||||||
|
|
||||||
// Open the same entry twice before it finishes loading.
|
// 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(),
|
||||||
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
|
// Open the same entry again now that it has loaded
|
||||||
let handle_3 = workspace
|
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
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -54,11 +54,11 @@ pub trait ItemViewHandle: Send + Sync {
|
||||||
|
|
||||||
impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
|
impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
|
||||||
fn title(&self, app: &AppContext) -> String {
|
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)> {
|
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> {
|
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 {
|
fn is_dirty(&self, ctx: &AppContext) -> bool {
|
||||||
self.as_ref(ctx).is_dirty(ctx)
|
self.read(ctx).is_dirty(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id(&self) -> usize {
|
fn id(&self) -> usize {
|
||||||
|
@ -154,7 +154,7 @@ impl WorkspaceView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_paths(&self, paths: &[PathBuf], app: &AppContext) -> bool {
|
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) {
|
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>) {
|
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(tree) = self.workspace.read(ctx).worktrees().iter().next() {
|
||||||
if let Some(file) = tree.as_ref(ctx).files().next() {
|
if let Some(file) = tree.read(ctx).files().next() {
|
||||||
info!("open_entry ({}, {})", tree.id(), file.entry_id);
|
info!("open_entry ({}, {})", tree.id(), file.entry_id);
|
||||||
self.open_entry((tree.id(), file.entry_id), ctx);
|
self.open_entry((tree.id(), file.entry_id), ctx);
|
||||||
} else {
|
} else {
|
||||||
|
@ -322,7 +322,7 @@ impl WorkspaceView {
|
||||||
) -> ViewHandle<Pane> {
|
) -> ViewHandle<Pane> {
|
||||||
let new_pane = self.add_pane(ctx);
|
let new_pane = self.add_pane(ctx);
|
||||||
self.activate_pane(new_pane.clone(), 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()) {
|
if let Some(clone) = item.clone_on_split(ctx.app_mut()) {
|
||||||
self.add_item(clone, ctx);
|
self.add_item(clone, ctx);
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_open_entry() {
|
fn test_open_entry() {
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let dir = temp_tree(json!({
|
let dir = temp_tree(json!({
|
||||||
"a": {
|
"a": {
|
||||||
"aa": "aa contents",
|
"aa": "aa contents",
|
||||||
|
@ -406,70 +406,78 @@ 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));
|
let workspace = app.add_model(|ctx| Workspace::new(vec![dir.path().into()], ctx));
|
||||||
app.finish_pending_tasks().await; // Open and populate worktree.
|
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) =
|
let (_, workspace_view) =
|
||||||
app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx));
|
app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx));
|
||||||
|
|
||||||
// Open the first entry
|
// 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;
|
app.finish_pending_tasks().await;
|
||||||
|
|
||||||
assert_eq!(
|
app.read(|ctx| {
|
||||||
workspace_view
|
assert_eq!(
|
||||||
.as_ref(app)
|
workspace_view
|
||||||
.active_pane()
|
.read(ctx)
|
||||||
.as_ref(app)
|
.active_pane()
|
||||||
.items()
|
.read(ctx)
|
||||||
.len(),
|
.items()
|
||||||
1
|
.len(),
|
||||||
);
|
1
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
// Open the second entry
|
// 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;
|
app.finish_pending_tasks().await;
|
||||||
|
|
||||||
let active_pane = workspace_view.as_ref(app).active_pane().as_ref(app);
|
app.read(|ctx| {
|
||||||
assert_eq!(active_pane.items().len(), 2);
|
let active_pane = workspace_view.read(ctx).active_pane().read(ctx);
|
||||||
assert_eq!(
|
assert_eq!(active_pane.items().len(), 2);
|
||||||
active_pane.active_item().unwrap().entry_id(app.as_ref()),
|
assert_eq!(
|
||||||
Some(entries[1])
|
active_pane.active_item().unwrap().entry_id(ctx),
|
||||||
);
|
Some(entries[1])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Open the first entry again
|
// 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;
|
app.finish_pending_tasks().await;
|
||||||
|
|
||||||
let active_pane = workspace_view.as_ref(app).active_pane().as_ref(app);
|
app.read(|ctx| {
|
||||||
assert_eq!(active_pane.items().len(), 2);
|
let active_pane = workspace_view.read(ctx).active_pane().read(ctx);
|
||||||
assert_eq!(
|
assert_eq!(active_pane.items().len(), 2);
|
||||||
active_pane.active_item().unwrap().entry_id(app.as_ref()),
|
assert_eq!(
|
||||||
Some(entries[0])
|
active_pane.active_item().unwrap().entry_id(ctx),
|
||||||
);
|
Some(entries[0])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Open the third entry twice concurrently
|
// 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);
|
||||||
w.open_entry(entries[2], ctx);
|
w.open_entry(entries[2], ctx);
|
||||||
});
|
});
|
||||||
app.finish_pending_tasks().await;
|
app.finish_pending_tasks().await;
|
||||||
|
|
||||||
assert_eq!(
|
app.read(|ctx| {
|
||||||
workspace_view
|
assert_eq!(
|
||||||
.as_ref(app)
|
workspace_view
|
||||||
.active_pane()
|
.read(ctx)
|
||||||
.as_ref(app)
|
.active_pane()
|
||||||
.items()
|
.read(ctx)
|
||||||
.len(),
|
.items()
|
||||||
3
|
.len(),
|
||||||
);
|
3
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pane_actions() {
|
fn test_pane_actions() {
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
pane::init(app);
|
app.update(|ctx| pane::init(ctx));
|
||||||
|
|
||||||
let dir = temp_tree(json!({
|
let dir = temp_tree(json!({
|
||||||
"a": {
|
"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));
|
let workspace = app.add_model(|ctx| Workspace::new(vec![dir.path().into()], ctx));
|
||||||
app.finish_pending_tasks().await; // Open and populate worktree.
|
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) =
|
let (window_id, workspace_view) =
|
||||||
app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx));
|
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;
|
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", ());
|
app.dispatch_action(window_id, vec![pane_1.id()], "pane:split_right", ());
|
||||||
let pane_2 = workspace_view.as_ref(app).active_pane().clone();
|
app.update(|ctx| {
|
||||||
assert_ne!(pane_1, pane_2);
|
let pane_2 = workspace_view.read(ctx).active_pane().clone();
|
||||||
|
assert_ne!(pane_1, pane_2);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pane_2
|
pane_2
|
||||||
.as_ref(app)
|
.read(ctx)
|
||||||
.active_item()
|
.active_item()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.entry_id(app.downgrade()),
|
.entry_id(ctx.as_ref()),
|
||||||
Some(entries[0])
|
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);
|
app.read(|ctx| {
|
||||||
assert_eq!(w.panes.len(), 1);
|
let w = workspace_view.read(ctx);
|
||||||
assert_eq!(w.active_pane(), &pane_1);
|
assert_eq!(w.panes.len(), 1);
|
||||||
|
assert_eq!(w.active_pane(), &pane_1);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,7 +409,7 @@ pub trait WorktreeHandle {
|
||||||
|
|
||||||
impl WorktreeHandle for ModelHandle<Worktree> {
|
impl WorktreeHandle for ModelHandle<Worktree> {
|
||||||
fn file(&self, entry_id: usize, app: &AppContext) -> Result<FileHandle> {
|
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"));
|
return Err(anyhow!("Entry does not exist in tree"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,15 +461,15 @@ pub struct FileHandle {
|
||||||
|
|
||||||
impl FileHandle {
|
impl FileHandle {
|
||||||
pub fn path(&self, app: &AppContext) -> PathBuf {
|
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>> {
|
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<()>> {
|
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)
|
worktree.save(self.entry_id, content, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +649,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_populate_and_search() {
|
fn test_populate_and_search() {
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let dir = temp_tree(json!({
|
let dir = temp_tree(json!({
|
||||||
"root": {
|
"root": {
|
||||||
"apple": "",
|
"apple": "",
|
||||||
|
@ -671,26 +671,28 @@ mod test {
|
||||||
let tree = app.add_model(|ctx| Worktree::new(1, root_link_path, Some(ctx)));
|
let tree = app.add_model(|ctx| Worktree::new(1, root_link_path, Some(ctx)));
|
||||||
app.finish_pending_tasks().await;
|
app.finish_pending_tasks().await;
|
||||||
|
|
||||||
let tree = tree.as_ref(app);
|
app.read(|ctx| {
|
||||||
assert_eq!(tree.file_count(), 4);
|
let tree = tree.read(ctx);
|
||||||
let results = match_paths(&[tree.clone()], "bna", false, false, 10)
|
assert_eq!(tree.file_count(), 4);
|
||||||
.iter()
|
let results = match_paths(&[tree.clone()], "bna", false, false, 10)
|
||||||
.map(|result| tree.entry_path(result.entry_id))
|
.iter()
|
||||||
.collect::<Result<Vec<PathBuf>, _>>()
|
.map(|result| tree.entry_path(result.entry_id))
|
||||||
.unwrap();
|
.collect::<Result<Vec<PathBuf>, _>>()
|
||||||
assert_eq!(
|
.unwrap();
|
||||||
results,
|
assert_eq!(
|
||||||
vec![
|
results,
|
||||||
PathBuf::from("root_link/banana/carrot/date"),
|
vec![
|
||||||
PathBuf::from("root_link/banana/carrot/endive"),
|
PathBuf::from("root_link/banana/carrot/date"),
|
||||||
]
|
PathBuf::from("root_link/banana/carrot/endive"),
|
||||||
);
|
]
|
||||||
|
);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_save_file() {
|
fn test_save_file() {
|
||||||
App::test_async((), |app| async move {
|
App::test_async((), |mut app| async move {
|
||||||
let dir = temp_tree(json!({
|
let dir = temp_tree(json!({
|
||||||
"file1": "the old contents",
|
"file1": "the old contents",
|
||||||
}));
|
}));
|
||||||
|
@ -698,17 +700,23 @@ mod test {
|
||||||
let tree = app.add_model(|ctx| Worktree::new(1, dir.path(), Some(ctx)));
|
let tree = app.add_model(|ctx| Worktree::new(1, dir.path(), Some(ctx)));
|
||||||
app.finish_pending_tasks().await;
|
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));
|
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()
|
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());
|
assert_eq!(history.base_text, buffer.text());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue