ep cli: Handle opening buffers from files created by the edit history (#46254)

Since we don't persist new files to disk, they don't have entries, so we
have to look them up in memory first.

Release Notes:

- N/A
This commit is contained in:
Agus Zubiaga authored and GitHub committed 2026-01-07 13:52:42 +00:00
1 parent 963c2afb48
commit d066181d70
2 files changed
+60 -38

No files matched your search

+32 -18
View File
@@ -8,7 +8,7 @@ use std::{
};
use anyhow::{Context as _, Result, anyhow};
use collections::HashMap;
use collections::{HashMap, hash_map::Entry};
use gpui::{AsyncApp, Entity};
use language::{Anchor, Buffer, OffsetRangeExt as _, TextBufferSnapshot, text_diff};
use postage::stream::Stream as _;
@@ -17,7 +17,13 @@ use util::{paths::PathStyle, rel_path::RelPath};
use worktree::Worktree;
#[derive(Clone, Debug)]
pub struct OpenedBuffers(#[allow(unused)] HashMap<String, Entity<Buffer>>);
pub struct OpenedBuffers(HashMap<String, Entity<Buffer>>);
impl OpenedBuffers {
pub fn get(&self, path: &str) -> Option<&Entity<Buffer>> {
self.0.get(path)
}
}
#[must_use]
pub async fn apply_diff(
@@ -42,12 +48,12 @@ pub async fn apply_diff(
.collect();
refresh_worktree_entries(&worktree, paths.iter().map(|p| p.as_path()), cx).await?;
let mut included_files = HashMap::default();
let mut included_files: HashMap<String, Entity<Buffer>> = HashMap::default();
let ranges = [Anchor::MIN..Anchor::MAX];
let mut diff = DiffParser::new(diff_str);
let mut current_file = None;
let mut edits = vec![];
let mut edits: Vec<(std::ops::Range<Anchor>, Arc<str>)> = vec![];
while let Some(event) = diff.next()? {
match event {
@@ -58,21 +64,29 @@ pub async fn apply_diff(
} => {
let buffer = match current_file {
None => {
let buffer = if is_new_file {
project
.update(cx, |project, cx| project.create_buffer(true, cx))?
.await?
} else {
let project_path = project
.update(cx, |project, cx| {
project.find_project_path(path.as_ref(), cx)
})?
.with_context(|| format!("no such path: {}", path))?;
project
.update(cx, |project, cx| project.open_buffer(project_path, cx))?
.await?
let buffer = match included_files.entry(path.to_string()) {
Entry::Occupied(entry) => entry.get().clone(),
Entry::Vacant(entry) => {
let buffer = if is_new_file {
project
.update(cx, |project, cx| project.create_buffer(true, cx))?
.await?
} else {
let project_path = project
.update(cx, |project, cx| {
project.find_project_path(path.as_ref(), cx)
})?
.with_context(|| format!("no such path: {}", path))?;
project
.update(cx, |project, cx| {
project.open_buffer(project_path, cx)
})?
.await?
};
entry.insert(buffer.clone());
buffer
}
};
included_files.insert(path.to_string(), buffer.clone());
current_file = Some(buffer);
current_file.as_ref().unwrap()
}
+28 -20
View File
@@ -27,9 +27,10 @@ pub async fn run_load_project(
let project = setup_project(example, &app_state, &progress, &mut cx).await?;
let _open_buffers = apply_edit_history(example, &project, &mut cx).await?;
let open_buffers = apply_edit_history(example, &project, &mut cx).await?;
let (buffer, cursor_position) = cursor_position(example, &project, &mut cx).await?;
let (buffer, cursor_position) =
cursor_position(example, &project, &open_buffers, &mut cx).await?;
let (example_buffer, language_name) = buffer.read_with(&cx, |buffer, _cx| {
let cursor_point = cursor_position.to_point(&buffer);
let language_name = buffer
@@ -54,7 +55,7 @@ pub async fn run_load_project(
buffer,
project,
cursor_position,
_open_buffers,
_open_buffers: open_buffers,
});
Ok(())
}
@@ -62,6 +63,7 @@ pub async fn run_load_project(
async fn cursor_position(
example: &Example,
project: &Entity<Project>,
open_buffers: &OpenedBuffers,
cx: &mut AsyncApp,
) -> Result<(Entity<Buffer>, Anchor)> {
let language_registry = project.read_with(cx, |project, _| project.languages().clone())?;
@@ -75,25 +77,31 @@ async fn cursor_position(
return Err(error);
}
// Since the worktree scanner is disabled, manually refresh entries for the cursor path.
if let Some(worktree) = project.read_with(cx, |project, cx| project.worktrees(cx).next())? {
refresh_worktree_entries(&worktree, [&*example.spec.cursor_path], cx).await?;
}
let cursor_path_str = example.spec.cursor_path.to_string_lossy();
// We try open_buffers first because the file might be new and not saved to disk
let cursor_buffer = if let Some(buffer) = open_buffers.get(&cursor_path_str) {
buffer.clone()
} else {
// Since the worktree scanner is disabled, manually refresh entries for the cursor path.
if let Some(worktree) = project.read_with(cx, |project, cx| project.worktrees(cx).next())? {
refresh_worktree_entries(&worktree, [&*example.spec.cursor_path], cx).await?;
}
let cursor_path = project
.read_with(cx, |project, cx| {
project.find_project_path(&example.spec.cursor_path, cx)
})?
.with_context(|| {
format!(
"failed to find cursor path {}",
example.spec.cursor_path.display()
)
})?;
let cursor_path = project
.read_with(cx, |project, cx| {
project.find_project_path(&example.spec.cursor_path, cx)
})?
.with_context(|| {
format!(
"failed to find cursor path {}",
example.spec.cursor_path.display()
)
})?;
let cursor_buffer = project
.update(cx, |project, cx| project.open_buffer(cursor_path, cx))?
.await?;
project
.update(cx, |project, cx| project.open_buffer(cursor_path, cx))?
.await?
};
let (cursor_excerpt, cursor_offset_within_excerpt) = example.spec.cursor_excerpt()?;