Attempt to open rows and columns from CLI input

Kirill Bulatov created

Change summary

crates/cli/src/cli.rs                 |  7 ++
crates/cli/src/main.rs                | 13 ++--
crates/file_finder/src/file_finder.rs |  2 
crates/util/src/paths.rs              | 15 ++++
crates/zed/src/main.rs                | 86 +++++++++++++++++++++-------
5 files changed, 91 insertions(+), 32 deletions(-)

Detailed changes

crates/cli/src/cli.rs 🔗

@@ -1,6 +1,7 @@
 pub use ipc_channel::ipc;
 use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
+use util::paths::PathLikeWithPosition;
 
 #[derive(Serialize, Deserialize)]
 pub struct IpcHandshake {
@@ -10,7 +11,11 @@ pub struct IpcHandshake {
 
 #[derive(Debug, Serialize, Deserialize)]
 pub enum CliRequest {
-    Open { paths: Vec<PathBuf>, wait: bool },
+    Open {
+        // TODO kb old cli won't be able to communicate to new Zed with this change
+        paths: Vec<PathLikeWithPosition<PathBuf>>,
+        wait: bool,
+    },
 }
 
 #[derive(Debug, Serialize, Deserialize)]

crates/cli/src/main.rs 🔗

@@ -21,7 +21,7 @@ use util::paths::PathLikeWithPosition;
 #[derive(Parser)]
 #[clap(name = "zed", global_setting(clap::AppSettings::NoAutoVersion))]
 struct Args {
-    /// Wait for all of the given paths to be closed before exiting.
+    /// Wait for all of the given paths to be opened/closed before exiting.
     #[clap(short, long)]
     wait: bool,
     /// A sequence of space-separated paths that you want to open.
@@ -78,12 +78,13 @@ fn main() -> Result<()> {
         paths: args
             .paths_with_position
             .into_iter()
-            // TODO kb continue sendint path with the position further
-            .map(|path_with_position| path_with_position.path_like)
-            .map(|path| {
-                fs::canonicalize(&path).with_context(|| format!("path {path:?} canonicalization"))
+            .map(|path_with_position| {
+                path_with_position.convert_path(|path| {
+                    fs::canonicalize(&path)
+                        .with_context(|| format!("path {path:?} canonicalization"))
+                })
             })
-            .collect::<Result<Vec<PathBuf>>>()?,
+            .collect::<Result<_>>()?,
         wait: args.wait,
     })?;
 

crates/file_finder/src/file_finder.rs 🔗

@@ -295,8 +295,6 @@ impl PickerDelegate for FileFinderDelegate {
                                     let point = snapshot
                                         .buffer_snapshot
                                         .clip_point(Point::new(row, col), Bias::Left);
-                                    let point =
-                                        snapshot.buffer_snapshot.clip_point(point, Bias::Left);
                                     editor.change_selections(Some(Autoscroll::center()), cx, |s| {
                                         s.select_ranges([point..point])
                                     });

crates/util/src/paths.rs 🔗

@@ -1,5 +1,7 @@
 use std::path::{Path, PathBuf};
 
+use serde::{Deserialize, Serialize};
+
 lazy_static::lazy_static! {
     pub static ref HOME: PathBuf = dirs::home_dir().expect("failed to determine home directory");
     pub static ref CONFIG_DIR: PathBuf = HOME.join(".config").join("zed");
@@ -73,7 +75,7 @@ pub fn compact(path: &Path) -> PathBuf {
 
 pub const FILE_ROW_COLUMN_DELIMITER: char = ':';
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct PathLikeWithPosition<P> {
     pub path_like: P,
     pub row: Option<u32>,
@@ -106,4 +108,15 @@ impl<P> PathLikeWithPosition<P> {
             },
         })
     }
+
+    pub fn convert_path<P2, E>(
+        self,
+        mapping: impl FnOnce(P) -> Result<P2, E>,
+    ) -> Result<PathLikeWithPosition<P2>, E> {
+        Ok(PathLikeWithPosition {
+            path_like: mapping(self.path_like)?,
+            row: self.row,
+            column: self.column,
+        })
+    }
 }

crates/zed/src/main.rs 🔗

@@ -10,7 +10,7 @@ use cli::{
 };
 use client::{self, UserStore, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN};
 use db::kvp::KEY_VALUE_STORE;
-use editor::Editor;
+use editor::{scroll::autoscroll::Autoscroll, Editor};
 use futures::{
     channel::{mpsc, oneshot},
     FutureExt, SinkExt, StreamExt,
@@ -30,6 +30,7 @@ use settings::{
 use simplelog::ConfigBuilder;
 use smol::process::Command;
 use std::{
+    collections::HashMap,
     env,
     ffi::OsStr,
     fs::OpenOptions,
@@ -44,7 +45,9 @@ use std::{
     thread,
     time::Duration,
 };
+use sum_tree::Bias;
 use terminal_view::{get_working_directory, TerminalView};
+use text::Point;
 use util::http::{self, HttpClient};
 use welcome::{show_welcome_experience, FIRST_OPEN};
 
@@ -678,13 +681,29 @@ async fn handle_cli_connection(
     if let Some(request) = requests.next().await {
         match request {
             CliRequest::Open { paths, wait } => {
+                let mut caret_positions = HashMap::new();
+
                 let paths = if paths.is_empty() {
                     workspace::last_opened_workspace_paths()
                         .await
                         .map(|location| location.paths().to_vec())
-                        .unwrap_or(paths)
+                        .unwrap_or_default()
                 } else {
                     paths
+                        .into_iter()
+                        .map(|path_with_position| {
+                            let path = path_with_position.path_like;
+                            if let Some(row) = path_with_position.row {
+                                if path.is_file() {
+                                    let row = row.saturating_sub(1);
+                                    let col =
+                                        path_with_position.column.unwrap_or(0).saturating_sub(1);
+                                    caret_positions.insert(path.clone(), Point::new(row, col));
+                                }
+                            }
+                            path
+                        })
+                        .collect()
                 };
 
                 let mut errored = false;
@@ -694,11 +713,37 @@ async fn handle_cli_connection(
                 {
                     Ok((workspace, items)) => {
                         let mut item_release_futures = Vec::new();
-                        cx.update(|cx| {
-                            for (item, path) in items.into_iter().zip(&paths) {
-                                match item {
-                                    Some(Ok(item)) => {
-                                        let released = oneshot::channel();
+
+                        for (item, path) in items.into_iter().zip(&paths) {
+                            match item {
+                                Some(Ok(item)) => {
+                                    if let Some(point) = caret_positions.remove(path) {
+                                        // TODO kb does not work
+                                        log::info!("@@@@@@@@ {path:?}@{point:?}");
+                                        if let Some(active_editor) = item.downcast::<Editor>() {
+                                            log::info!("@@@@@@@@ editor");
+                                            active_editor
+                                                .downgrade()
+                                                .update(&mut cx, |editor, cx| {
+                                                    log::info!("@@@@@@@@ update");
+                                                    let snapshot =
+                                                        editor.snapshot(cx).display_snapshot;
+                                                    let point = snapshot
+                                                        .buffer_snapshot
+                                                        .clip_point(point, Bias::Left);
+                                                    editor.change_selections(
+                                                        Some(Autoscroll::center()),
+                                                        cx,
+                                                        |s| s.select_ranges([point..point]),
+                                                    );
+                                                    log::info!("@@@@@@@@ finished");
+                                                })
+                                                .log_err();
+                                        }
+                                    }
+
+                                    let released = oneshot::channel();
+                                    cx.update(|cx| {
                                         item.on_release(
                                             cx,
                                             Box::new(move |_| {
@@ -706,23 +751,20 @@ async fn handle_cli_connection(
                                             }),
                                         )
                                         .detach();
-                                        item_release_futures.push(released.1);
-                                    }
-                                    Some(Err(err)) => {
-                                        responses
-                                            .send(CliResponse::Stderr {
-                                                message: format!(
-                                                    "error opening {:?}: {}",
-                                                    path, err
-                                                ),
-                                            })
-                                            .log_err();
-                                        errored = true;
-                                    }
-                                    None => {}
+                                    });
+                                    item_release_futures.push(released.1);
+                                }
+                                Some(Err(err)) => {
+                                    responses
+                                        .send(CliResponse::Stderr {
+                                            message: format!("error opening {:?}: {}", path, err),
+                                        })
+                                        .log_err();
+                                    errored = true;
                                 }
+                                None => {}
                             }
-                        });
+                        }
 
                         if wait {
                             let background = cx.background();