ep cli: Include cursor file in errors (#46192)

Agus Zubiaga created

Errors now include the cursor file path so we can just cmd+click it for
inspection

Release Notes:

- N/A

Change summary

crates/edit_prediction_cli/src/example.rs      | 29 +++++++++++++++----
crates/edit_prediction_cli/src/load_project.rs |  9 ++----
crates/edit_prediction_cli/src/main.rs         |  9 ++++++
3 files changed, 35 insertions(+), 12 deletions(-)

Detailed changes

crates/edit_prediction_cli/src/example.rs 🔗

@@ -1,3 +1,4 @@
+use crate::paths::WORKTREES_DIR;
 use crate::{PredictionProvider, PromptFormat};
 use anyhow::{Context as _, Result};
 use collections::HashMap;
@@ -90,7 +91,7 @@ pub struct ExampleScore {
 }
 
 impl Example {
-    pub fn repo_name(&self) -> Result<(Cow<'_, str>, Cow<'_, str>)> {
+    pub fn repo_name(&self) -> Result<RepoName<'_>> {
         // git@github.com:owner/repo.git
         if self.spec.repository_url.contains('@') {
             let (owner, repo) = self
@@ -101,10 +102,10 @@ impl Example {
                 .1
                 .split_once('/')
                 .context("expected / in git url")?;
-            Ok((
-                Cow::Borrowed(owner),
-                Cow::Borrowed(repo.trim_end_matches(".git")),
-            ))
+            Ok(RepoName {
+                owner: Cow::Borrowed(owner),
+                name: Cow::Borrowed(repo.trim_end_matches(".git")),
+            })
         // http://github.com/owner/repo.git
         } else {
             let url = Url::parse(&self.spec.repository_url)?;
@@ -120,11 +121,27 @@ impl Example {
                 .to_string();
             assert!(segments.next().is_none());
 
-            Ok((owner.into(), repo.into()))
+            Ok(RepoName {
+                owner: Cow::Owned(owner),
+                name: Cow::Owned(repo),
+            })
         }
     }
 }
 
+pub struct RepoName<'a> {
+    pub owner: Cow<'a, str>,
+    pub name: Cow<'a, str>,
+}
+
+impl RepoName<'_> {
+    pub fn worktree_path(&self) -> PathBuf {
+        WORKTREES_DIR
+            .join(self.owner.as_ref())
+            .join(self.name.as_ref())
+    }
+}
+
 pub fn read_example_files(inputs: &[PathBuf]) -> Vec<Example> {
     let mut examples = Vec::new();
 

crates/edit_prediction_cli/src/load_project.rs 🔗

@@ -2,7 +2,6 @@ use crate::{
     example::{Example, ExampleBuffer, ExampleState},
     git,
     headless::EpAppState,
-    paths::WORKTREES_DIR,
     progress::{InfoStyle, Progress, Step, StepProgress},
 };
 use anyhow::{Context as _, Result};
@@ -187,15 +186,13 @@ async fn setup_project(
 }
 
 async fn setup_worktree(example: &Example, step_progress: &StepProgress) -> Result<PathBuf> {
-    let (repo_owner, repo_name) = example.repo_name().context("failed to get repo name")?;
+    let repo_name = example.repo_name().context("failed to get repo name")?;
     let repo_dir = git::repo_path_for_url(&example.spec.repository_url)?;
-    let worktree_path = WORKTREES_DIR
-        .join(repo_owner.as_ref())
-        .join(repo_name.as_ref());
+    let worktree_path = repo_name.worktree_path();
     let repo_lock = git::lock_repo(&repo_dir).await;
 
     if !repo_dir.is_dir() {
-        step_progress.set_substatus(format!("cloning {}", repo_name));
+        step_progress.set_substatus(format!("cloning {}", repo_name.name));
         fs::create_dir_all(&repo_dir)?;
         git::run_git(&repo_dir, &["init"]).await?;
         git::run_git(

crates/edit_prediction_cli/src/main.rs 🔗

@@ -433,6 +433,12 @@ fn main() {
                                     .await
                                     .unwrap();
 
+                                let file_path = example
+                                    .repo_name()
+                                    .unwrap()
+                                    .worktree_path()
+                                    .join(&example.spec.cursor_path);
+
                                 let msg = format!(
                                     indoc::indoc! {"
                                         While processing \"{}\":
@@ -441,6 +447,8 @@ fn main() {
 
                                         Written to: \x1b[36m{}\x1b[0m
 
+                                        Cursor File: \x1b[36m{}\x1b[0m
+
                                         Explore this example data with:
                                             fx \x1b[36m{}\x1b[0m
 
@@ -450,6 +458,7 @@ fn main() {
                                     example.spec.name,
                                     e,
                                     err_path.display(),
+                                    file_path.display(),
                                     failed_example_path.display(),
                                     command,
                                     failed_example_path.display(),