@@ -5070,6 +5070,7 @@ dependencies = [
"multi_buffer",
"ordered-float 2.10.1",
"parking_lot",
+ "postage",
"pretty_assertions",
"project",
"rand 0.8.5",
@@ -20462,6 +20463,7 @@ dependencies = [
"parking_lot",
"paths",
"picker",
+ "postage",
"pretty_assertions",
"profiling",
"project",
@@ -176,17 +176,15 @@ use snippet::Snippet;
use std::{
any::TypeId,
borrow::Cow,
- cell::OnceCell,
- cell::RefCell,
+ cell::{OnceCell, RefCell},
cmp::{self, Ordering, Reverse},
iter::Peekable,
mem,
num::NonZeroU32,
- ops::Not,
- ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
+ ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
path::{Path, PathBuf},
rc::Rc,
- sync::Arc,
+ sync::{Arc, LazyLock},
time::{Duration, Instant},
};
use sum_tree::TreeMap;
@@ -237,6 +235,21 @@ pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct LastCursorPosition {
+ pub path: PathBuf,
+ pub worktree_path: Arc<Path>,
+ pub point: Point,
+}
+
+pub static LAST_CURSOR_POSITION_WATCH: LazyLock<(
+ Mutex<postage::watch::Sender<Option<LastCursorPosition>>>,
+ postage::watch::Receiver<Option<LastCursorPosition>>,
+)> = LazyLock::new(|| {
+ let (sender, receiver) = postage::watch::channel();
+ (Mutex::new(sender), receiver)
+});
+
pub type RenderDiffHunkControlsFn = Arc<
dyn Fn(
u32,
@@ -3018,10 +3031,28 @@ impl Editor {
let new_cursor_position = newest_selection.head();
let selection_start = newest_selection.start;
+ let new_cursor_point = new_cursor_position.to_point(buffer);
+ if let Some(project) = self.project()
+ && let Some((path, worktree_path)) =
+ self.file_at(new_cursor_point, cx).and_then(|file| {
+ file.as_local().and_then(|file| {
+ let worktree =
+ project.read(cx).worktree_for_id(file.worktree_id(cx), cx)?;
+ Some((file.abs_path(cx), worktree.read(cx).abs_path()))
+ })
+ })
+ {
+ *LAST_CURSOR_POSITION_WATCH.0.lock().borrow_mut() = Some(LastCursorPosition {
+ path,
+ worktree_path,
+ point: new_cursor_point,
+ });
+ }
+
if effects.nav_history.is_none() || effects.nav_history == Some(true) {
self.push_to_nav_history(
*old_cursor_position,
- Some(new_cursor_position.to_point(buffer)),
+ Some(new_cursor_point),
false,
effects.nav_history == Some(true),
cx,
@@ -17,6 +17,7 @@ use fs::{Fs, RealFs};
use futures::{StreamExt, channel::oneshot, future};
use git::GitHostingProviderRegistry;
use gpui::{App, AppContext as _, Application, AsyncApp, Focusable as _, UpdateGlobal as _};
+use postage::stream::Stream as _;
use gpui_tokio::Tokio;
use http_client::{Url, read_proxy_from_env};
@@ -747,6 +748,49 @@ pub fn main() {
}
})
.detach();
+
+ if let Ok(selection_change_command) = env::var("ZED_SELECTION_CHANGE_CMD") {
+ log::info!(
+ "Will run {} when the selection changes",
+ selection_change_command
+ );
+ let mut cursor_reciever = editor::LAST_CURSOR_POSITION_WATCH.1.clone();
+ cx.background_spawn(async move {
+ while let Some(mut cursor) = cursor_reciever.recv().await {
+ loop {
+ // todo! Check if it's changed meanwhile and refresh.
+ if let Some(cursor) = dbg!(&cursor) {
+ let status = smol::process::Command::new(&selection_change_command)
+ .arg(cursor.worktree_path.as_ref())
+ .arg(format!(
+ "{}:{}:{}",
+ cursor.path.display(),
+ cursor.point.row + 1,
+ cursor.point.column + 1
+ ))
+ .status()
+ .await;
+ match status {
+ Ok(status) => {
+ if !status.success() {
+ log::error!("Command failed with status {}", status);
+ }
+ }
+ Err(err) => {
+ log::error!("Command failed with error {}", err);
+ }
+ }
+ }
+ let new_cursor = cursor_reciever.borrow();
+ if *new_cursor == cursor {
+ break;
+ }
+ cursor = new_cursor.clone();
+ }
+ }
+ })
+ .detach();
+ }
});
}