Detailed changes
@@ -568,18 +568,15 @@ impl WrapSnapshot {
let mut old_start = old_cursor.start().output.lines;
old_start += tab_edit.old.start.0 - old_cursor.start().input.lines;
- // todo(lw): Should these be seek_forward?
- old_cursor.seek(&tab_edit.old.end, Bias::Right);
+ old_cursor.seek_forward(&tab_edit.old.end, Bias::Right);
let mut old_end = old_cursor.start().output.lines;
old_end += tab_edit.old.end.0 - old_cursor.start().input.lines;
- // todo(lw): Should these be seek_forward?
new_cursor.seek(&tab_edit.new.start, Bias::Right);
let mut new_start = new_cursor.start().output.lines;
new_start += tab_edit.new.start.0 - new_cursor.start().input.lines;
- // todo(lw): Should these be seek_forward?
- new_cursor.seek(&tab_edit.new.end, Bias::Right);
+ new_cursor.seek_forward(&tab_edit.new.end, Bias::Right);
let mut new_end = new_cursor.start().output.lines;
new_end += tab_edit.new.end.0 - new_cursor.start().input.lines;
@@ -602,6 +602,7 @@ impl GitBlame {
}
fn regenerate_on_edit(&mut self, cx: &mut Context<Self>) {
+ // todo(lw): hot foreground spawn
self.regenerate_on_edit_task = cx.spawn(async move |this, cx| {
cx.background_executor()
.timer(REGENERATE_ON_EDIT_DEBOUNCE_INTERVAL)
@@ -1,4 +1,4 @@
-use editor::{Editor, MultiBufferSnapshot};
+use editor::{Editor, EditorEvent, MultiBufferSnapshot};
use gpui::{App, Entity, FocusHandle, Focusable, Styled, Subscription, Task, WeakEntity};
use settings::Settings;
use std::{fmt::Write, num::NonZeroU32, time::Duration};
@@ -81,7 +81,7 @@ impl CursorPosition {
fn update_position(
&mut self,
- editor: Entity<Editor>,
+ editor: &Entity<Editor>,
debounce: Option<Duration>,
window: &mut Window,
cx: &mut Context<Self>,
@@ -269,19 +269,21 @@ impl StatusItemView for CursorPosition {
cx: &mut Context<Self>,
) {
if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
- self._observe_active_editor =
- Some(
- cx.observe_in(&editor, window, |cursor_position, editor, window, cx| {
- Self::update_position(
- cursor_position,
- editor,
- Some(UPDATE_DEBOUNCE),
- window,
- cx,
- )
- }),
- );
- self.update_position(editor, None, window, cx);
+ self._observe_active_editor = Some(cx.subscribe_in(
+ &editor,
+ window,
+ |cursor_position, editor, event, window, cx| match event {
+ EditorEvent::SelectionsChanged { .. } => Self::update_position(
+ cursor_position,
+ editor,
+ Some(UPDATE_DEBOUNCE),
+ window,
+ cx,
+ ),
+ _ => {}
+ },
+ ));
+ self.update_position(&editor, None, window, cx);
} else {
self.position = None;
self._observe_active_editor = None;
@@ -176,7 +176,7 @@ impl AsyncApp {
lock.open_window(options, build_root_view)
}
- /// Schedule a future to be polled in the background.
+ /// Schedule a future to be polled in the foreground.
#[track_caller]
pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
where
@@ -479,7 +479,6 @@ impl ForegroundExecutor {
}
/// Enqueues the given Task to run on the main thread at some point in the future.
- #[track_caller]
pub fn spawn<R>(&self, future: impl Future<Output = R> + 'static) -> Task<R>
where
R: 'static,
@@ -1573,21 +1573,24 @@ impl Buffer {
self.reparse = None;
}
Err(parse_task) => {
+ // todo(lw): hot foreground spawn
self.reparse = Some(cx.spawn(async move |this, cx| {
- let new_syntax_map = parse_task.await;
+ let new_syntax_map = cx.background_spawn(parse_task).await;
this.update(cx, move |this, cx| {
- let grammar_changed =
+ let grammar_changed = || {
this.language.as_ref().is_none_or(|current_language| {
!Arc::ptr_eq(&language, current_language)
- });
- let language_registry_changed = new_syntax_map
- .contains_unknown_injections()
- && language_registry.is_some_and(|registry| {
- registry.version() != new_syntax_map.language_registry_version()
- });
- let parse_again = language_registry_changed
- || grammar_changed
- || this.version.changed_since(&parsed_version);
+ })
+ };
+ let language_registry_changed = || {
+ new_syntax_map.contains_unknown_injections()
+ && language_registry.is_some_and(|registry| {
+ registry.version() != new_syntax_map.language_registry_version()
+ })
+ };
+ let parse_again = this.version.changed_since(&parsed_version)
+ || language_registry_changed()
+ || grammar_changed();
this.did_finish_parsing(new_syntax_map, cx);
this.reparse = None;
if parse_again {
@@ -1,7 +1,7 @@
use std::{mem, ops::Range, sync::Arc};
use collections::HashSet;
-use gpui::{App, AppContext, Context, Entity, Task};
+use gpui::{App, AppContext, Context, Entity};
use itertools::Itertools;
use language::{Buffer, BufferSnapshot};
use rope::Point;
@@ -117,12 +117,14 @@ impl MultiBuffer {
buffer: Entity<Buffer>,
ranges: Vec<Range<text::Anchor>>,
context_line_count: u32,
- cx: &mut Context<Self>,
- ) -> Task<Vec<Range<Anchor>>> {
+ cx: &Context<Self>,
+ ) -> impl Future<Output = Vec<Range<Anchor>>> + use<> {
let buffer_snapshot = buffer.read(cx).snapshot();
- cx.spawn(async move |multi_buffer, cx| {
+ let multi_buffer = cx.weak_entity();
+ let mut app = cx.to_async();
+ async move {
let snapshot = buffer_snapshot.clone();
- let (excerpt_ranges, new, counts) = cx
+ let (excerpt_ranges, new, counts) = app
.background_spawn(async move {
let ranges = ranges.into_iter().map(|range| range.to_point(&snapshot));
let excerpt_ranges =
@@ -133,7 +135,7 @@ impl MultiBuffer {
.await;
multi_buffer
- .update(cx, move |multi_buffer, cx| {
+ .update(&mut app, move |multi_buffer, cx| {
let (ranges, _) = multi_buffer.set_merged_excerpt_ranges_for_path(
path_key,
buffer,
@@ -147,7 +149,7 @@ impl MultiBuffer {
})
.ok()
.unwrap_or_default()
- })
+ }
}
pub(super) fn expand_excerpts_with_paths(
@@ -619,29 +619,24 @@ impl LocalBufferStore {
worktree: Entity<Worktree>,
cx: &mut Context<BufferStore>,
) -> Task<Result<Entity<Buffer>>> {
- let load_buffer = worktree.update(cx, |worktree, cx| {
- let load_file = worktree.load_file(path.as_ref(), cx);
- let reservation = cx.reserve_entity();
- let buffer_id = BufferId::from(reservation.entity_id().as_non_zero_u64());
- let path = path.clone();
- cx.spawn(async move |_, cx| {
- let loaded = load_file.await.with_context(|| {
- format!("Could not open path: {}", path.display(PathStyle::local()))
- })?;
- let text_buffer = cx
- .background_spawn(async move {
- text::Buffer::new(ReplicaId::LOCAL, buffer_id, loaded.text)
- })
- .await;
- cx.insert_entity(reservation, |_| {
- Buffer::build(text_buffer, Some(loaded.file), Capability::ReadWrite)
- })
- })
- });
-
+ let load_file = worktree.update(cx, |worktree, cx| worktree.load_file(path.as_ref(), cx));
cx.spawn(async move |this, cx| {
- let buffer = match load_buffer.await {
- Ok(buffer) => Ok(buffer),
+ let path = path.clone();
+ let buffer = match load_file.await.with_context(|| {
+ format!("Could not open path: {}", path.display(PathStyle::local()))
+ }) {
+ Ok(loaded) => {
+ let reservation = cx.reserve_entity::<Buffer>()?;
+ let buffer_id = BufferId::from(reservation.entity_id().as_non_zero_u64());
+ let text_buffer = cx
+ .background_spawn(async move {
+ text::Buffer::new(ReplicaId::LOCAL, buffer_id, loaded.text)
+ })
+ .await;
+ cx.insert_entity(reservation, |_| {
+ Buffer::build(text_buffer, Some(loaded.file), Capability::ReadWrite)
+ })?
+ }
Err(error) if is_not_found_error(&error) => cx.new(|cx| {
let buffer_id = BufferId::from(cx.entity_id().as_non_zero_u64());
let text_buffer = text::Buffer::new(ReplicaId::LOCAL, buffer_id, "");
@@ -657,9 +652,9 @@ impl LocalBufferStore {
})),
Capability::ReadWrite,
)
- }),
- Err(e) => Err(e),
- }?;
+ })?,
+ Err(e) => return Err(e),
+ };
this.update(cx, |this, cx| {
this.add_buffer(buffer.clone(), cx)?;
let buffer_id = buffer.read(cx).remote_id();
@@ -840,6 +835,7 @@ impl BufferStore {
entry
.insert(
+ // todo(lw): hot foreground spawn
cx.spawn(async move |this, cx| {
let load_result = load_buffer.await;
this.update(cx, |this, cx| {
@@ -709,6 +709,7 @@ impl GitStore {
repo.load_committed_text(buffer_id, repo_path, cx)
});
+ // todo(lw): hot foreground spawn
cx.spawn(async move |this, cx| {
Self::open_diff_internal(this, DiffKind::Uncommitted, changes.await, buffer, cx)
.await
@@ -9171,7 +9171,9 @@ async fn test_odd_events_for_ignored_dirs(
repository_updates.lock().drain(..).collect::<Vec<_>>(),
vec![
RepositoryEvent::MergeHeadsChanged,
- RepositoryEvent::BranchChanged
+ RepositoryEvent::BranchChanged,
+ RepositoryEvent::StatusesChanged { full_scan: false },
+ RepositoryEvent::StatusesChanged { full_scan: false },
],
"Initial worktree scan should produce a repo update event"
);
@@ -322,18 +322,25 @@ impl ProjectSearch {
let mut limit_reached = false;
while let Some(results) = matches.next().await {
- let mut buffers_with_ranges = Vec::with_capacity(results.len());
- for result in results {
- match result {
- project::search::SearchResult::Buffer { buffer, ranges } => {
- buffers_with_ranges.push((buffer, ranges));
- }
- project::search::SearchResult::LimitReached => {
- limit_reached = true;
+ let (buffers_with_ranges, has_reached_limit) = cx
+ .background_executor()
+ .spawn(async move {
+ let mut limit_reached = false;
+ let mut buffers_with_ranges = Vec::with_capacity(results.len());
+ for result in results {
+ match result {
+ project::search::SearchResult::Buffer { buffer, ranges } => {
+ buffers_with_ranges.push((buffer, ranges));
+ }
+ project::search::SearchResult::LimitReached => {
+ limit_reached = true;
+ }
+ }
}
- }
- }
-
+ (buffers_with_ranges, limit_reached)
+ })
+ .await;
+ limit_reached |= has_reached_limit;
let mut new_ranges = project_search
.update(cx, |project_search, cx| {
project_search.excerpts.update(cx, |excerpts, cx| {
@@ -352,7 +359,6 @@ impl ProjectSearch {
})
})
.ok()?;
-
while let Some(new_ranges) = new_ranges.next().await {
project_search
.update(cx, |project_search, cx| {
@@ -1318,7 +1318,8 @@ impl LocalWorktree {
let entry = self.refresh_entry(path.clone(), None, cx);
let is_private = self.is_path_private(path.as_ref());
- cx.spawn(async move |this, _cx| {
+ let this = cx.weak_entity();
+ cx.background_spawn(async move {
// WARN: Temporary workaround for #27283.
// We are not efficient with our memory usage per file, and use in excess of 64GB for a 10GB file
// Therefore, as a temporary workaround to prevent system freezes, we just bail before opening a file
@@ -1702,6 +1703,7 @@ impl LocalWorktree {
};
let t0 = Instant::now();
let mut refresh = self.refresh_entries_for_paths(paths);
+ // todo(lw): Hot foreground spawn
cx.spawn(async move |this, cx| {
refresh.recv().await;
log::trace!("refreshed entry {path:?} in {:?}", t0.elapsed());
@@ -2860,16 +2860,20 @@ mod tests {
});
// Split the pane with the first entry, then open the second entry again.
- let (task1, task2) = window
+ window
.update(cx, |w, window, cx| {
- (
- w.split_and_clone(w.active_pane().clone(), SplitDirection::Right, window, cx),
- w.open_path(file2.clone(), None, true, window, cx),
- )
+ w.split_and_clone(w.active_pane().clone(), SplitDirection::Right, window, cx)
+ })
+ .unwrap()
+ .await
+ .unwrap();
+ window
+ .update(cx, |w, window, cx| {
+ w.open_path(file2.clone(), None, true, window, cx)
})
+ .unwrap()
+ .await
.unwrap();
- task1.await.unwrap();
- task2.await.unwrap();
window
.read_with(cx, |w, cx| {