Skip to content

Commit

Permalink
Merge branch 'main' into ssh-reload
Browse files Browse the repository at this point in the history
  • Loading branch information
mikayla-maki committed Sep 23, 2024
2 parents 65371f7 + 20c0654 commit 8357a53
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 61 deletions.
4 changes: 2 additions & 2 deletions crates/editor/src/selections_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl SelectionsCollection {

pub fn all<'a, D>(&self, cx: &AppContext) -> Vec<Selection<D>>
where
D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
D: 'a + TextDimension + Ord + Sub<D, Output = D>,
{
let disjoint_anchors = &self.disjoint;
let mut disjoint =
Expand Down Expand Up @@ -850,7 +850,7 @@ pub(crate) fn resolve_multiple<'a, D, I>(
snapshot: &MultiBufferSnapshot,
) -> impl 'a + Iterator<Item = Selection<D>>
where
D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
D: TextDimension + Ord + Sub<D, Output = D>,
I: 'a + IntoIterator<Item = &'a Selection<Anchor>>,
{
let (to_summarize, selections) = selections.into_iter().tee();
Expand Down
67 changes: 38 additions & 29 deletions crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2963,32 +2963,36 @@ impl Project {
buffer: &Model<Buffer>,
cx: &mut ModelContext<Self>,
) -> Task<Option<ResolvedPath>> {
// TODO: ssh based remoting.
if self.ssh_session.is_some() {
return Task::ready(None);
}

if self.is_local_or_ssh() {
let expanded = PathBuf::from(shellexpand::tilde(&path).into_owned());
let path_buf = PathBuf::from(path);
if path_buf.is_absolute() || path.starts_with("~") {
if self.is_local() {
let expanded = PathBuf::from(shellexpand::tilde(&path).into_owned());

if expanded.is_absolute() {
let fs = self.fs.clone();
cx.background_executor().spawn(async move {
let path = expanded.as_path();
let exists = fs.is_file(path).await;

exists.then(|| ResolvedPath::AbsPath(expanded))
})
} else if let Some(ssh_session) = self.ssh_session.as_ref() {
let request = ssh_session.request(proto::CheckFileExists {
project_id: SSH_PROJECT_ID,
path: path.to_string(),
});
cx.background_executor().spawn(async move {
let response = request.await.log_err()?;
if response.exists {
Some(ResolvedPath::AbsPath(PathBuf::from(response.path)))
} else {
None
}
})
} else {
self.resolve_path_in_worktrees(expanded, buffer, cx)
}
} else {
let path = PathBuf::from(path);
if path.is_absolute() || path.starts_with("~") {
return Task::ready(None);
}

self.resolve_path_in_worktrees(path, buffer, cx)
} else {
self.resolve_path_in_worktrees(path_buf, buffer, cx)
}
}

Expand Down Expand Up @@ -3907,17 +3911,7 @@ impl Project {
}

pub fn worktree_metadata_protos(&self, cx: &AppContext) -> Vec<proto::WorktreeMetadata> {
self.worktrees(cx)
.map(|worktree| {
let worktree = worktree.read(cx);
proto::WorktreeMetadata {
id: worktree.id().to_proto(),
root_name: worktree.root_name().into(),
visible: worktree.is_visible(),
abs_path: worktree.abs_path().to_string_lossy().into(),
}
})
.collect()
self.worktree_store.read(cx).worktree_metadata_protos(cx)
}

fn set_worktrees_from_proto(
Expand All @@ -3926,10 +3920,9 @@ impl Project {
cx: &mut ModelContext<Project>,
) -> Result<()> {
cx.notify();
let result = self.worktree_store.update(cx, |worktree_store, cx| {
self.worktree_store.update(cx, |worktree_store, cx| {
worktree_store.set_worktrees_from_proto(worktrees, self.replica_id(), cx)
});
result
})
}

fn set_collaborators_from_proto(
Expand Down Expand Up @@ -4438,6 +4431,22 @@ pub enum ResolvedPath {
AbsPath(PathBuf),
}

impl ResolvedPath {
pub fn abs_path(&self) -> Option<&Path> {
match self {
Self::AbsPath(path) => Some(path.as_path()),
_ => None,
}
}

pub fn project_path(&self) -> Option<&ProjectPath> {
match self {
Self::ProjectPath(path) => Some(&path),
_ => None,
}
}
}

impl Item for Buffer {
fn try_open(
project: &Model<Project>,
Expand Down
15 changes: 14 additions & 1 deletion crates/proto/proto/zed.proto
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,10 @@ message Envelope {

TryExec try_exec = 252;
ReadTextFile read_text_file = 253;
ReadTextFileResponse read_text_file_response = 254; // current max
ReadTextFileResponse read_text_file_response = 254;

CheckFileExists check_file_exists = 255;
CheckFileExistsResponse check_file_exists_response = 256; // current max
}

reserved 158 to 161;
Expand Down Expand Up @@ -2574,3 +2577,13 @@ message TryExec {
message TryExecResponse {
string text = 1;
}

message CheckFileExists {
uint64 project_id = 1;
string path = 2;
}

message CheckFileExistsResponse {
bool exists = 1;
string path = 2;
}
8 changes: 6 additions & 2 deletions crates/proto/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,9 @@ messages!(
(ShellEnvResponse, Foreground),
(TryExec, Foreground),
(ReadTextFile, Foreground),
(ReadTextFileResponse, Foreground)
(ReadTextFileResponse, Foreground),
(CheckFileExists, Background),
(CheckFileExistsResponse, Background)
);

request_messages!(
Expand Down Expand Up @@ -501,6 +503,7 @@ request_messages!(
(ShellEnv, ShellEnvResponse),
(ReadTextFile, ReadTextFileResponse),
(TryExec, Ack),
(CheckFileExists, CheckFileExistsResponse)
);

entity_messages!(
Expand Down Expand Up @@ -578,7 +581,8 @@ entity_messages!(
WhichCommand,
ShellEnv,
TryExec,
ReadTextFile
ReadTextFile,
CheckFileExists,
);

entity_messages!(
Expand Down
17 changes: 17 additions & 0 deletions crates/remote_server/src/headless_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl HeadlessProject {
session.subscribe_to_entity(SSH_PROJECT_ID, &settings_observer);

client.add_request_handler(cx.weak_model(), Self::handle_list_remote_directory);
client.add_request_handler(cx.weak_model(), Self::handle_check_file_exists);

client.add_model_request_handler(Self::handle_add_worktree);
client.add_model_request_handler(Self::handle_open_buffer_by_path);
Expand Down Expand Up @@ -297,4 +298,20 @@ impl HeadlessProject {
}
Ok(proto::ListRemoteDirectoryResponse { entries })
}

pub async fn handle_check_file_exists(
this: Model<Self>,
envelope: TypedEnvelope<proto::CheckFileExists>,
cx: AsyncAppContext,
) -> Result<proto::CheckFileExistsResponse> {
let fs = cx.read_model(&this, |this, _| this.fs.clone())?;
let expanded = shellexpand::tilde(&envelope.payload.path).to_string();

let exists = fs.is_file(&PathBuf::from(expanded.clone())).await;

Ok(proto::CheckFileExistsResponse {
exists,
path: expanded,
})
}
}
48 changes: 47 additions & 1 deletion crates/remote_server/src/remote_editing_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use lsp::{CompletionContext, CompletionResponse, CompletionTriggerKind};
use node_runtime::NodeRuntime;
use project::{
search::{SearchQuery, SearchResult},
Project,
Project, ProjectPath,
};
use remote::SshSession;
use serde_json::json;
Expand Down Expand Up @@ -474,24 +474,70 @@ async fn test_remote_reload(cx: &mut TestAppContext, server_cx: &mut TestAppCont
.await
.unwrap();

dbg!("******* EDITED FILE OUT FROM UNDER YOU!!!!");
cx.run_until_parked();
cx.update(|cx| {
assert!(buffer.read(cx).has_conflict());
});

dbg!("******* calling reload");
project
.update(cx, |project, cx| {
project.reload_buffers([buffer.clone()].into_iter().collect(), false, cx)
})
.await
.unwrap();
cx.run_until_parked();
dbg!("******* done calling reload");

cx.update(|cx| {
assert!(!buffer.read(cx).has_conflict());
});
}

#[gpui::test]
async fn test_remote_resolve_file_path(cx: &mut TestAppContext, server_cx: &mut TestAppContext) {
let (project, _headless, _fs) = init_test(cx, server_cx).await;
let (worktree, _) = project
.update(cx, |project, cx| {
project.find_or_create_worktree("/code/project1", true, cx)
})
.await
.unwrap();

let worktree_id = cx.update(|cx| worktree.read(cx).id());

let buffer = project
.update(cx, |project, cx| {
project.open_buffer((worktree_id, Path::new("src/lib.rs")), cx)
})
.await
.unwrap();

let path = project
.update(cx, |project, cx| {
project.resolve_existing_file_path("/code/project1/README.md", &buffer, cx)
})
.await
.unwrap();
assert_eq!(
path.abs_path().unwrap().to_string_lossy(),
"/code/project1/README.md"
);

let path = project
.update(cx, |project, cx| {
project.resolve_existing_file_path("../README.md", &buffer, cx)
})
.await
.unwrap();

assert_eq!(
path.project_path().unwrap().clone(),
ProjectPath::from((worktree_id, "README.md"))
);
}

fn init_logger() {
if std::env::var("RUST_LOG").is_ok() {
env_logger::try_init().ok();
Expand Down
6 changes: 2 additions & 4 deletions crates/sum_tree/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,9 @@ where
aggregate: &mut dyn SeekAggregate<'a, T>,
cx: &<T::Summary as Summary>::Context,
) -> bool {
debug_assert!(
assert!(
target.cmp(&self.position, cx) >= Ordering::Equal,
"cannot seek backward from {:?} to {:?}",
self.position,
target
"cannot seek backward",
);

if !self.did_seek {
Expand Down
53 changes: 48 additions & 5 deletions crates/sum_tree/src/sum_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub trait KeyedItem: Item {
///
/// Each Summary type can have multiple [`Dimensions`] that it measures,
/// which can be used to navigate the tree
pub trait Summary: Clone + fmt::Debug {
pub trait Summary: Clone {
type Context;

fn zero(cx: &Self::Context) -> Self;
Expand All @@ -49,7 +49,7 @@ pub trait Summary: Clone + fmt::Debug {
/// # Example:
/// Zed's rope has a `TextSummary` type that summarizes lines, characters, and bytes.
/// Each of these are different dimensions we may want to seek to
pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug {
pub trait Dimension<'a, S: Summary>: Clone {
fn zero(cx: &S::Context) -> Self;

fn add_summary(&mut self, summary: &'a S, cx: &S::Context);
Expand All @@ -71,7 +71,7 @@ impl<'a, T: Summary> Dimension<'a, T> for T {
}
}

pub trait SeekTarget<'a, S: Summary, D: Dimension<'a, S>>: fmt::Debug {
pub trait SeekTarget<'a, S: Summary, D: Dimension<'a, S>> {
fn cmp(&self, cursor_location: &D, cx: &S::Context) -> Ordering;
}

Expand Down Expand Up @@ -173,9 +173,19 @@ impl Bias {
/// The maximum number of items per node is `TREE_BASE * 2`.
///
/// Any [`Dimension`] supported by the [`Summary`] type can be used to seek to a specific location in the tree.
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct SumTree<T: Item>(Arc<Node<T>>);

impl<T> fmt::Debug for SumTree<T>
where
T: fmt::Debug + Item,
T::Summary: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("SumTree").field(&self.0).finish()
}
}

impl<T: Item> SumTree<T> {
pub fn new(cx: &<T::Summary as Summary>::Context) -> Self {
SumTree(Arc::new(Node::Leaf {
Expand Down Expand Up @@ -763,7 +773,7 @@ where
}
}

#[derive(Clone, Debug)]
#[derive(Clone)]
pub enum Node<T: Item> {
Internal {
height: u8,
Expand All @@ -778,6 +788,39 @@ pub enum Node<T: Item> {
},
}

impl<T> fmt::Debug for Node<T>
where
T: Item + fmt::Debug,
T::Summary: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Node::Internal {
height,
summary,
child_summaries,
child_trees,
} => f
.debug_struct("Internal")
.field("height", height)
.field("summary", summary)
.field("child_summaries", child_summaries)
.field("child_trees", child_trees)
.finish(),
Node::Leaf {
summary,
items,
item_summaries,
} => f
.debug_struct("Leaf")
.field("summary", summary)
.field("items", items)
.field("item_summaries", item_summaries)
.finish(),
}
}
}

impl<T: Item> Node<T> {
fn is_leaf(&self) -> bool {
matches!(self, Node::Leaf { .. })
Expand Down
Loading

0 comments on commit 8357a53

Please sign in to comment.