mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 19:25:33 +03:00
open new buffer (#11203)
Release Notes: - Allow creating new untitled buffers in remote projects TODO: - Add a Test - Fix version number check
This commit is contained in:
parent
28bcc95468
commit
3752ed294d
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -16,7 +16,6 @@ dependencies = [
|
|||||||
"project",
|
"project",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"ui",
|
"ui",
|
||||||
"util",
|
|
||||||
"workspace",
|
"workspace",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ language.workspace = true
|
|||||||
project.workspace = true
|
project.workspace = true
|
||||||
smallvec.workspace = true
|
smallvec.workspace = true
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
util.workspace = true
|
|
||||||
workspace.workspace = true
|
workspace.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -12,7 +12,6 @@ use project::{LanguageServerProgress, Project};
|
|||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cmp::Reverse, fmt::Write, sync::Arc};
|
use std::{cmp::Reverse, fmt::Write, sync::Arc};
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use util::ResultExt;
|
|
||||||
use workspace::{item::ItemHandle, StatusItemView, Workspace};
|
use workspace::{item::ItemHandle, StatusItemView, Workspace};
|
||||||
|
|
||||||
actions!(activity_indicator, [ShowErrorMessage]);
|
actions!(activity_indicator, [ShowErrorMessage]);
|
||||||
@ -82,27 +81,37 @@ impl ActivityIndicator {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.subscribe(&this, move |workspace, _, event, cx| match event {
|
cx.subscribe(&this, move |_, _, event, cx| match event {
|
||||||
Event::ShowError { lsp_name, error } => {
|
Event::ShowError { lsp_name, error } => {
|
||||||
if let Some(buffer) = project
|
let create_buffer = project.update(cx, |project, cx| project.create_buffer(cx));
|
||||||
.update(cx, |project, cx| project.create_buffer(error, None, cx))
|
let project = project.clone();
|
||||||
.log_err()
|
let error = error.clone();
|
||||||
{
|
let lsp_name = lsp_name.clone();
|
||||||
buffer.update(cx, |buffer, cx| {
|
cx.spawn(|workspace, mut cx| async move {
|
||||||
|
let buffer = create_buffer.await?;
|
||||||
|
buffer.update(&mut cx, |buffer, cx| {
|
||||||
buffer.edit(
|
buffer.edit(
|
||||||
[(0..0, format!("Language server error: {}\n\n", lsp_name))],
|
[(
|
||||||
|
0..0,
|
||||||
|
format!("Language server error: {}\n\n{}", lsp_name, error),
|
||||||
|
)],
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
});
|
})?;
|
||||||
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
workspace.add_item_to_active_pane(
|
workspace.add_item_to_active_pane(
|
||||||
Box::new(
|
Box::new(cx.new_view(|cx| {
|
||||||
cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
|
Editor::for_buffer(buffer, Some(project.clone()), cx)
|
||||||
),
|
})),
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}
|
})?;
|
||||||
|
|
||||||
|
anyhow::Ok(())
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
@ -221,9 +221,9 @@ fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext<Wo
|
|||||||
workspace
|
workspace
|
||||||
.update(&mut cx, |workspace, cx| {
|
.update(&mut cx, |workspace, cx| {
|
||||||
let project = workspace.project().clone();
|
let project = workspace.project().clone();
|
||||||
let buffer = project
|
let buffer = project.update(cx, |project, cx| {
|
||||||
.update(cx, |project, cx| project.create_buffer("", markdown, cx))
|
project.create_local_buffer("", markdown, cx)
|
||||||
.expect("creating buffers on a local workspace always succeeds");
|
});
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit([(0..0, body.release_notes)], None, cx)
|
buffer.edit([(0..0, body.release_notes)], None, cx)
|
||||||
});
|
});
|
||||||
|
@ -74,6 +74,8 @@ use tracing::{
|
|||||||
};
|
};
|
||||||
use util::http::IsahcHttpClient;
|
use util::http::IsahcHttpClient;
|
||||||
|
|
||||||
|
use self::connection_pool::VersionedMessage;
|
||||||
|
|
||||||
pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
|
pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
|
|
||||||
// kubernetes gives terminated pods 10s to shutdown gracefully. After they're gone, we can clean up old resources.
|
// kubernetes gives terminated pods 10s to shutdown gracefully. After they're gone, we can clean up old resources.
|
||||||
@ -465,6 +467,9 @@ impl Server {
|
|||||||
.add_request_handler(user_handler(
|
.add_request_handler(user_handler(
|
||||||
forward_mutating_project_request::<proto::ApplyCompletionAdditionalEdits>,
|
forward_mutating_project_request::<proto::ApplyCompletionAdditionalEdits>,
|
||||||
))
|
))
|
||||||
|
.add_request_handler(user_handler(
|
||||||
|
forward_versioned_mutating_project_request::<proto::OpenNewBuffer>,
|
||||||
|
))
|
||||||
.add_request_handler(user_handler(
|
.add_request_handler(user_handler(
|
||||||
forward_mutating_project_request::<proto::ResolveCompletionDocumentation>,
|
forward_mutating_project_request::<proto::ResolveCompletionDocumentation>,
|
||||||
))
|
))
|
||||||
@ -505,7 +510,7 @@ impl Server {
|
|||||||
forward_mutating_project_request::<proto::OnTypeFormatting>,
|
forward_mutating_project_request::<proto::OnTypeFormatting>,
|
||||||
))
|
))
|
||||||
.add_request_handler(user_handler(
|
.add_request_handler(user_handler(
|
||||||
forward_mutating_project_request::<proto::SaveBuffer>,
|
forward_versioned_mutating_project_request::<proto::SaveBuffer>,
|
||||||
))
|
))
|
||||||
.add_request_handler(user_handler(
|
.add_request_handler(user_handler(
|
||||||
forward_mutating_project_request::<proto::BlameBuffer>,
|
forward_mutating_project_request::<proto::BlameBuffer>,
|
||||||
@ -2677,6 +2682,7 @@ where
|
|||||||
T: EntityMessage + RequestMessage,
|
T: EntityMessage + RequestMessage,
|
||||||
{
|
{
|
||||||
let project_id = ProjectId::from_proto(request.remote_entity_id());
|
let project_id = ProjectId::from_proto(request.remote_entity_id());
|
||||||
|
|
||||||
let host_connection_id = session
|
let host_connection_id = session
|
||||||
.db()
|
.db()
|
||||||
.await
|
.await
|
||||||
@ -2690,6 +2696,45 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// forward a project request to the host. These requests are disallowed
|
||||||
|
/// for guests.
|
||||||
|
async fn forward_versioned_mutating_project_request<T>(
|
||||||
|
request: T,
|
||||||
|
response: Response<T>,
|
||||||
|
session: UserSession,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
T: EntityMessage + RequestMessage + VersionedMessage,
|
||||||
|
{
|
||||||
|
let project_id = ProjectId::from_proto(request.remote_entity_id());
|
||||||
|
|
||||||
|
let host_connection_id = session
|
||||||
|
.db()
|
||||||
|
.await
|
||||||
|
.host_for_mutating_project_request(project_id, session.connection_id, session.user_id())
|
||||||
|
.await?;
|
||||||
|
if let Some(host_version) = session
|
||||||
|
.connection_pool()
|
||||||
|
.await
|
||||||
|
.connection(host_connection_id)
|
||||||
|
.map(|c| c.zed_version)
|
||||||
|
{
|
||||||
|
if let Some(min_required_version) = request.required_host_version() {
|
||||||
|
if min_required_version > host_version {
|
||||||
|
return Err(anyhow!(ErrorCode::RemoteUpgradeRequired
|
||||||
|
.with_tag("required", &min_required_version.to_string())))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload = session
|
||||||
|
.peer
|
||||||
|
.forward_request(session.connection_id, host_connection_id, request)
|
||||||
|
.await?;
|
||||||
|
response.send(payload)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Notify other participants that a new buffer has been created
|
/// Notify other participants that a new buffer has been created
|
||||||
async fn create_buffer_for_peer(
|
async fn create_buffer_for_peer(
|
||||||
request: proto::CreateBufferForPeer,
|
request: proto::CreateBufferForPeer,
|
||||||
|
@ -21,7 +21,7 @@ struct ConnectedPrincipal {
|
|||||||
connection_ids: HashSet<ConnectionId>,
|
connection_ids: HashSet<ConnectionId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Copy, Clone, Debug, Serialize, PartialOrd, PartialEq, Eq, Ord)]
|
||||||
pub struct ZedVersion(pub SemanticVersion);
|
pub struct ZedVersion(pub SemanticVersion);
|
||||||
|
|
||||||
impl fmt::Display for ZedVersion {
|
impl fmt::Display for ZedVersion {
|
||||||
@ -34,6 +34,32 @@ impl ZedVersion {
|
|||||||
pub fn can_collaborate(&self) -> bool {
|
pub fn can_collaborate(&self) -> bool {
|
||||||
self.0 >= SemanticVersion::new(0, 129, 2)
|
self.0 >= SemanticVersion::new(0, 129, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_save_as() -> ZedVersion {
|
||||||
|
ZedVersion(SemanticVersion::new(0, 134, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait VersionedMessage {
|
||||||
|
fn required_host_version(&self) -> Option<ZedVersion> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionedMessage for proto::SaveBuffer {
|
||||||
|
fn required_host_version(&self) -> Option<ZedVersion> {
|
||||||
|
if self.new_path.is_some() {
|
||||||
|
Some(ZedVersion::with_save_as())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionedMessage for proto::OpenNewBuffer {
|
||||||
|
fn required_host_version(&self) -> Option<ZedVersion> {
|
||||||
|
Some(ZedVersion::with_save_as())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@ -50,6 +76,10 @@ impl ConnectionPool {
|
|||||||
self.channels.clear();
|
self.channels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connection(&mut self, connection_id: ConnectionId) -> Option<&Connection> {
|
||||||
|
self.connections.get(&connection_id)
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
pub fn add_connection(
|
pub fn add_connection(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -398,3 +398,33 @@ async fn test_save_as_remote(cx1: &mut gpui::TestAppContext, cx2: &mut gpui::Tes
|
|||||||
"remote\nremote\nremote"
|
"remote\nremote\nremote"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_new_file_remote(cx1: &mut gpui::TestAppContext, cx2: &mut gpui::TestAppContext) {
|
||||||
|
let (server, client1) = TestServer::start1(cx1).await;
|
||||||
|
|
||||||
|
// Creating a project with a path that does exist should not fail
|
||||||
|
let (dev_server, remote_workspace) =
|
||||||
|
create_remote_project(&server, client1.app_state.clone(), cx1, cx2).await;
|
||||||
|
|
||||||
|
let mut cx = VisualTestContext::from_window(remote_workspace.into(), cx1);
|
||||||
|
|
||||||
|
cx.simulate_keystrokes("cmd-n");
|
||||||
|
cx.simulate_input("new!");
|
||||||
|
cx.simulate_keystrokes("cmd-shift-s");
|
||||||
|
cx.simulate_input("2.txt");
|
||||||
|
cx.simulate_keystrokes("enter");
|
||||||
|
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
let title = remote_workspace
|
||||||
|
.update(&mut cx, |ws, cx| {
|
||||||
|
ws.active_item(cx).unwrap().tab_description(0, &cx).unwrap()
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(title, "2.txt");
|
||||||
|
|
||||||
|
let path = Path::new("/remote/2.txt");
|
||||||
|
assert_eq!(dev_server.fs().load(&path).await.unwrap(), "new!");
|
||||||
|
}
|
||||||
|
@ -2450,7 +2450,8 @@ async fn test_propagate_saves_and_fs_changes(
|
|||||||
});
|
});
|
||||||
|
|
||||||
let new_buffer_a = project_a
|
let new_buffer_a = project_a
|
||||||
.update(cx_a, |p, cx| p.create_buffer("", None, cx))
|
.update(cx_a, |p, cx| p.create_buffer(cx))
|
||||||
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let new_buffer_id = new_buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
|
let new_buffer_id = new_buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
|
||||||
|
@ -99,7 +99,7 @@ use project::{
|
|||||||
CodeAction, Completion, FormatTrigger, Item, Location, Project, ProjectPath, ProjectTransaction,
|
CodeAction, Completion, FormatTrigger, Item, Location, Project, ProjectPath, ProjectTransaction,
|
||||||
};
|
};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rpc::proto::*;
|
use rpc::{proto::*, ErrorExt};
|
||||||
use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
|
use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
|
||||||
use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
|
use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -131,7 +131,7 @@ use ui::{
|
|||||||
};
|
};
|
||||||
use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
|
use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
|
||||||
use workspace::item::{ItemHandle, PreviewTabsSettings};
|
use workspace::item::{ItemHandle, PreviewTabsSettings};
|
||||||
use workspace::notifications::NotificationId;
|
use workspace::notifications::{DetachAndPromptErr, NotificationId};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
|
searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
|
||||||
};
|
};
|
||||||
@ -1610,18 +1610,27 @@ impl Editor {
|
|||||||
cx: &mut ViewContext<Workspace>,
|
cx: &mut ViewContext<Workspace>,
|
||||||
) {
|
) {
|
||||||
let project = workspace.project().clone();
|
let project = workspace.project().clone();
|
||||||
if project.read(cx).is_remote() {
|
let create = project.update(cx, |project, cx| project.create_buffer(cx));
|
||||||
cx.propagate();
|
|
||||||
} else if let Some(buffer) = project
|
cx.spawn(|workspace, mut cx| async move {
|
||||||
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
let buffer = create.await?;
|
||||||
.log_err()
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
{
|
|
||||||
workspace.add_item_to_active_pane(
|
workspace.add_item_to_active_pane(
|
||||||
Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
|
Box::new(
|
||||||
|
cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
|
||||||
|
),
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
)
|
||||||
}
|
})
|
||||||
|
})
|
||||||
|
.detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
|
||||||
|
ErrorCode::RemoteUpgradeRequired => Some(format!(
|
||||||
|
"The remote instance of Zed does not support this yet. It must be upgraded to {}",
|
||||||
|
e.error_tag("required").unwrap_or("the latest version")
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_file_in_direction(
|
pub fn new_file_in_direction(
|
||||||
@ -1630,18 +1639,29 @@ impl Editor {
|
|||||||
cx: &mut ViewContext<Workspace>,
|
cx: &mut ViewContext<Workspace>,
|
||||||
) {
|
) {
|
||||||
let project = workspace.project().clone();
|
let project = workspace.project().clone();
|
||||||
if project.read(cx).is_remote() {
|
let create = project.update(cx, |project, cx| project.create_buffer(cx));
|
||||||
cx.propagate();
|
let direction = action.0;
|
||||||
} else if let Some(buffer) = project
|
|
||||||
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
cx.spawn(|workspace, mut cx| async move {
|
||||||
.log_err()
|
let buffer = create.await?;
|
||||||
{
|
workspace.update(&mut cx, move |workspace, cx| {
|
||||||
workspace.split_item(
|
workspace.split_item(
|
||||||
action.0,
|
direction,
|
||||||
Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
|
Box::new(
|
||||||
|
cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
|
||||||
|
),
|
||||||
cx,
|
cx,
|
||||||
);
|
)
|
||||||
}
|
})?;
|
||||||
|
anyhow::Ok(())
|
||||||
|
})
|
||||||
|
.detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
|
||||||
|
ErrorCode::RemoteUpgradeRequired => Some(format!(
|
||||||
|
"The remote instance of Zed does not support this yet. It must be upgraded to {}",
|
||||||
|
e.error_tag("required").unwrap_or("the latest version")
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
|
pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
|
||||||
|
@ -7356,9 +7356,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) {
|
|||||||
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
|
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
|
||||||
|
|
||||||
let buffer = project.update(cx, |project, cx| {
|
let buffer = project.update(cx, |project, cx| {
|
||||||
let buffer = project
|
let buffer = project.create_local_buffer(&sample_text(16, 8, 'a'), None, cx);
|
||||||
.create_buffer(&sample_text(16, 8, 'a'), None, cx)
|
|
||||||
.unwrap();
|
|
||||||
cx.new_model(|cx| MultiBuffer::singleton(buffer, cx))
|
cx.new_model(|cx| MultiBuffer::singleton(buffer, cx))
|
||||||
});
|
});
|
||||||
let leader = cx.add_window(|cx| build_editor(buffer.clone(), cx));
|
let leader = cx.add_window(|cx| build_editor(buffer.clone(), cx));
|
||||||
@ -7565,12 +7563,8 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
|
|||||||
|
|
||||||
let (buffer_1, buffer_2) = project.update(cx, |project, cx| {
|
let (buffer_1, buffer_2) = project.update(cx, |project, cx| {
|
||||||
(
|
(
|
||||||
project
|
project.create_local_buffer("abc\ndef\nghi\njkl\n", None, cx),
|
||||||
.create_buffer("abc\ndef\nghi\njkl\n", None, cx)
|
project.create_local_buffer("mno\npqr\nstu\nvwx\n", None, cx),
|
||||||
.unwrap(),
|
|
||||||
project
|
|
||||||
.create_buffer("mno\npqr\nstu\nvwx\n", None, cx)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -108,9 +108,8 @@ mod tests {
|
|||||||
let project = Project::test(fs, [], cx).await;
|
let project = Project::test(fs, [], cx).await;
|
||||||
|
|
||||||
// buffer has two modified hunks with two rows each
|
// buffer has two modified hunks with two rows each
|
||||||
let buffer_1 = project
|
let buffer_1 = project.update(cx, |project, cx| {
|
||||||
.update(cx, |project, cx| {
|
project.create_local_buffer(
|
||||||
project.create_buffer(
|
|
||||||
"
|
"
|
||||||
1.zero
|
1.zero
|
||||||
1.ONE
|
1.ONE
|
||||||
@ -125,8 +124,7 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})
|
});
|
||||||
.unwrap();
|
|
||||||
buffer_1.update(cx, |buffer, cx| {
|
buffer_1.update(cx, |buffer, cx| {
|
||||||
buffer.set_diff_base(
|
buffer.set_diff_base(
|
||||||
Some(
|
Some(
|
||||||
@ -146,9 +144,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// buffer has a deletion hunk and an insertion hunk
|
// buffer has a deletion hunk and an insertion hunk
|
||||||
let buffer_2 = project
|
let buffer_2 = project.update(cx, |project, cx| {
|
||||||
.update(cx, |project, cx| {
|
project.create_local_buffer(
|
||||||
project.create_buffer(
|
|
||||||
"
|
"
|
||||||
2.zero
|
2.zero
|
||||||
2.one
|
2.one
|
||||||
@ -163,8 +160,7 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})
|
});
|
||||||
.unwrap();
|
|
||||||
buffer_2.update(cx, |buffer, cx| {
|
buffer_2.update(cx, |buffer, cx| {
|
||||||
buffer.set_diff_base(
|
buffer.set_diff_base(
|
||||||
Some(
|
Some(
|
||||||
|
@ -97,15 +97,19 @@ pub fn expand_macro_recursively(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = project.update(&mut cx, |project, cx| {
|
let buffer = project
|
||||||
project.create_buffer(¯o_expansion.expansion, Some(rust_language), cx)
|
.update(&mut cx, |project, cx| project.create_buffer(cx))?
|
||||||
})??;
|
.await?;
|
||||||
workspace.update(&mut cx, |workspace, cx| {
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
let buffer = cx.new_model(|cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
|
buffer.edit([(0..0, macro_expansion.expansion)], None, cx);
|
||||||
|
buffer.set_language(Some(rust_language), cx)
|
||||||
|
});
|
||||||
|
let multibuffer = cx.new_model(|cx| {
|
||||||
MultiBuffer::singleton(buffer, cx).with_title(macro_expansion.name)
|
MultiBuffer::singleton(buffer, cx).with_title(macro_expansion.name)
|
||||||
});
|
});
|
||||||
workspace.add_item_to_active_pane(
|
workspace.add_item_to_active_pane(
|
||||||
Box::new(cx.new_view(|cx| Editor::for_multibuffer(buffer, Some(project), cx))),
|
Box::new(cx.new_view(|cx| Editor::for_multibuffer(multibuffer, Some(project), cx))),
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
@ -142,11 +142,9 @@ impl FeedbackModal {
|
|||||||
|
|
||||||
cx.spawn(|workspace, mut cx| async move {
|
cx.spawn(|workspace, mut cx| async move {
|
||||||
let markdown = markdown.await.log_err();
|
let markdown = markdown.await.log_err();
|
||||||
let buffer = project
|
let buffer = project.update(&mut cx, |project, cx| {
|
||||||
.update(&mut cx, |project, cx| {
|
project.create_local_buffer("", markdown, cx)
|
||||||
project.create_buffer("", markdown, cx)
|
})?;
|
||||||
})?
|
|
||||||
.expect("creating buffers on a local workspace always succeeds");
|
|
||||||
|
|
||||||
workspace.update(&mut cx, |workspace, cx| {
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
let system_specs = SystemSpecs::new(cx);
|
let system_specs = SystemSpecs::new(cx);
|
||||||
|
@ -665,6 +665,7 @@ impl Project {
|
|||||||
client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
|
client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
|
||||||
client.add_model_request_handler(Self::handle_open_buffer_by_id);
|
client.add_model_request_handler(Self::handle_open_buffer_by_id);
|
||||||
client.add_model_request_handler(Self::handle_open_buffer_by_path);
|
client.add_model_request_handler(Self::handle_open_buffer_by_path);
|
||||||
|
client.add_model_request_handler(Self::handle_open_new_buffer);
|
||||||
client.add_model_request_handler(Self::handle_save_buffer);
|
client.add_model_request_handler(Self::handle_save_buffer);
|
||||||
client.add_model_message_handler(Self::handle_update_diff_base);
|
client.add_model_message_handler(Self::handle_update_diff_base);
|
||||||
client.add_model_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
|
client.add_model_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
|
||||||
@ -1955,21 +1956,41 @@ impl Project {
|
|||||||
!self.is_local()
|
!self.is_local()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_buffer(
|
pub fn create_buffer(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<Model<Buffer>>> {
|
||||||
|
if self.is_remote() {
|
||||||
|
let create = self.client.request(proto::OpenNewBuffer {
|
||||||
|
project_id: self.remote_id().unwrap(),
|
||||||
|
});
|
||||||
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
let response = create.await?;
|
||||||
|
let buffer_id = BufferId::new(response.buffer_id)?;
|
||||||
|
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
this.wait_for_remote_buffer(buffer_id, cx)
|
||||||
|
})?
|
||||||
|
.await
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Task::ready(Ok(self.create_local_buffer("", None, cx)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_local_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
text: &str,
|
text: &str,
|
||||||
language: Option<Arc<Language>>,
|
language: Option<Arc<Language>>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Result<Model<Buffer>> {
|
) -> Model<Buffer> {
|
||||||
if self.is_remote() {
|
if self.is_remote() {
|
||||||
return Err(anyhow!("creating buffers as a guest is not supported yet"));
|
panic!("called create_local_buffer on a remote project")
|
||||||
}
|
}
|
||||||
let buffer = cx.new_model(|cx| {
|
let buffer = cx.new_model(|cx| {
|
||||||
Buffer::local(text, cx)
|
Buffer::local(text, cx)
|
||||||
.with_language(language.unwrap_or_else(|| language::PLAIN_TEXT.clone()), cx)
|
.with_language(language.unwrap_or_else(|| language::PLAIN_TEXT.clone()), cx)
|
||||||
});
|
});
|
||||||
self.register_buffer(&buffer, cx)?;
|
self.register_buffer(&buffer, cx)
|
||||||
Ok(buffer)
|
.expect("creating local buffers always succeeds");
|
||||||
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_path(
|
pub fn open_path(
|
||||||
@ -9415,6 +9436,18 @@ impl Project {
|
|||||||
Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
|
Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_open_new_buffer(
|
||||||
|
this: Model<Self>,
|
||||||
|
envelope: TypedEnvelope<proto::OpenNewBuffer>,
|
||||||
|
_: Arc<Client>,
|
||||||
|
mut cx: AsyncAppContext,
|
||||||
|
) -> Result<proto::OpenBufferResponse> {
|
||||||
|
let buffer = this.update(&mut cx, |this, cx| this.create_local_buffer("", None, cx))?;
|
||||||
|
let peer_id = envelope.original_sender_id()?;
|
||||||
|
|
||||||
|
Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn respond_to_open_buffer_request(
|
fn respond_to_open_buffer_request(
|
||||||
this: Model<Self>,
|
this: Model<Self>,
|
||||||
buffer: Model<Buffer>,
|
buffer: Model<Buffer>,
|
||||||
|
@ -2931,9 +2931,7 @@ async fn test_save_as(cx: &mut gpui::TestAppContext) {
|
|||||||
let languages = project.update(cx, |project, _| project.languages().clone());
|
let languages = project.update(cx, |project, _| project.languages().clone());
|
||||||
languages.add(rust_lang());
|
languages.add(rust_lang());
|
||||||
|
|
||||||
let buffer = project.update(cx, |project, cx| {
|
let buffer = project.update(cx, |project, cx| project.create_local_buffer("", None, cx));
|
||||||
project.create_buffer("", None, cx).unwrap()
|
|
||||||
});
|
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit([(0..0, "abc")], None, cx);
|
buffer.edit([(0..0, "abc")], None, cx);
|
||||||
assert!(buffer.is_dirty());
|
assert!(buffer.is_dirty());
|
||||||
|
@ -3394,7 +3394,9 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// "Save as"" the buffer, creating a new backing file for it
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
// "Save as" the buffer, creating a new backing file for it
|
||||||
let save_task = workspace
|
let save_task = workspace
|
||||||
.update(cx, |workspace, cx| {
|
.update(cx, |workspace, cx| {
|
||||||
workspace.save_active_item(workspace::SaveIntent::Save, cx)
|
workspace.save_active_item(workspace::SaveIntent::Save, cx)
|
||||||
|
@ -235,8 +235,9 @@ message Envelope {
|
|||||||
RejoinRemoteProjectsResponse rejoin_remote_projects_response = 187;
|
RejoinRemoteProjectsResponse rejoin_remote_projects_response = 187;
|
||||||
|
|
||||||
RemoteProjectsUpdate remote_projects_update = 193;
|
RemoteProjectsUpdate remote_projects_update = 193;
|
||||||
ValidateRemoteProjectRequest validate_remote_project_request = 194; // Current max
|
ValidateRemoteProjectRequest validate_remote_project_request = 194;
|
||||||
DeleteDevServer delete_dev_server = 195;
|
DeleteDevServer delete_dev_server = 195;
|
||||||
|
OpenNewBuffer open_new_buffer = 196; // Current max
|
||||||
}
|
}
|
||||||
|
|
||||||
reserved 158 to 161;
|
reserved 158 to 161;
|
||||||
@ -275,6 +276,7 @@ enum ErrorCode {
|
|||||||
DevServerAlreadyOnline = 14;
|
DevServerAlreadyOnline = 14;
|
||||||
DevServerOffline = 15;
|
DevServerOffline = 15;
|
||||||
RemoteProjectPathDoesNotExist = 16;
|
RemoteProjectPathDoesNotExist = 16;
|
||||||
|
RemoteUpgradeRequired = 17;
|
||||||
reserved 6;
|
reserved 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,6 +738,10 @@ message OpenBufferById {
|
|||||||
uint64 id = 2;
|
uint64 id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message OpenNewBuffer {
|
||||||
|
uint64 project_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message OpenBufferResponse {
|
message OpenBufferResponse {
|
||||||
uint64 buffer_id = 1;
|
uint64 buffer_id = 1;
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,8 @@ messages!(
|
|||||||
(MultiLspQueryResponse, Background),
|
(MultiLspQueryResponse, Background),
|
||||||
(RemoteProjectsUpdate, Foreground),
|
(RemoteProjectsUpdate, Foreground),
|
||||||
(ValidateRemoteProjectRequest, Background),
|
(ValidateRemoteProjectRequest, Background),
|
||||||
(DeleteDevServer, Foreground)
|
(DeleteDevServer, Foreground),
|
||||||
|
(OpenNewBuffer, Foreground)
|
||||||
);
|
);
|
||||||
|
|
||||||
request_messages!(
|
request_messages!(
|
||||||
@ -377,6 +378,7 @@ request_messages!(
|
|||||||
(OpenBufferById, OpenBufferResponse),
|
(OpenBufferById, OpenBufferResponse),
|
||||||
(OpenBufferByPath, OpenBufferResponse),
|
(OpenBufferByPath, OpenBufferResponse),
|
||||||
(OpenBufferForSymbol, OpenBufferForSymbolResponse),
|
(OpenBufferForSymbol, OpenBufferForSymbolResponse),
|
||||||
|
(OpenNewBuffer, OpenBufferResponse),
|
||||||
(PerformRename, PerformRenameResponse),
|
(PerformRename, PerformRenameResponse),
|
||||||
(Ping, Ack),
|
(Ping, Ack),
|
||||||
(PrepareRename, PrepareRenameResponse),
|
(PrepareRename, PrepareRenameResponse),
|
||||||
@ -453,6 +455,7 @@ entity_messages!(
|
|||||||
LeaveProject,
|
LeaveProject,
|
||||||
MultiLspQuery,
|
MultiLspQuery,
|
||||||
OnTypeFormatting,
|
OnTypeFormatting,
|
||||||
|
OpenNewBuffer,
|
||||||
OpenBufferById,
|
OpenBufferById,
|
||||||
OpenBufferByPath,
|
OpenBufferByPath,
|
||||||
OpenBufferForSymbol,
|
OpenBufferForSymbol,
|
||||||
|
@ -599,9 +599,9 @@ fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let project = workspace.project().clone();
|
let project = workspace.project().clone();
|
||||||
let buffer = project
|
let buffer = project.update(cx, |project, cx| {
|
||||||
.update(cx, |project, cx| project.create_buffer(&log, None, cx))
|
project.create_local_buffer(&log, None, cx)
|
||||||
.expect("creating buffers on a local workspace always succeeds");
|
});
|
||||||
|
|
||||||
let buffer = cx.new_model(|cx| {
|
let buffer = cx.new_model(|cx| {
|
||||||
MultiBuffer::singleton(buffer, cx).with_title("Log".into())
|
MultiBuffer::singleton(buffer, cx).with_title("Log".into())
|
||||||
@ -812,8 +812,7 @@ fn open_telemetry_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Works
|
|||||||
workspace.update(&mut cx, |workspace, cx| {
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
let project = workspace.project().clone();
|
let project = workspace.project().clone();
|
||||||
let buffer = project
|
let buffer = project
|
||||||
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
.update(cx, |project, cx| project.create_local_buffer("", None, cx));
|
||||||
.expect("creating buffers on a local workspace always succeeds");
|
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.set_language(json, cx);
|
buffer.set_language(json, cx);
|
||||||
buffer.edit(
|
buffer.edit(
|
||||||
@ -862,9 +861,7 @@ fn open_bundled_file(
|
|||||||
workspace.with_local_workspace(cx, |workspace, cx| {
|
workspace.with_local_workspace(cx, |workspace, cx| {
|
||||||
let project = workspace.project();
|
let project = workspace.project();
|
||||||
let buffer = project.update(cx, move |project, cx| {
|
let buffer = project.update(cx, move |project, cx| {
|
||||||
project
|
project.create_local_buffer(text.as_ref(), language, cx)
|
||||||
.create_buffer(text.as_ref(), language, cx)
|
|
||||||
.expect("creating buffers on a local workspace always succeeds")
|
|
||||||
});
|
});
|
||||||
let buffer = cx.new_model(|cx| {
|
let buffer = cx.new_model(|cx| {
|
||||||
MultiBuffer::singleton(buffer, cx).with_title(title.into())
|
MultiBuffer::singleton(buffer, cx).with_title(title.into())
|
||||||
@ -1335,6 +1332,7 @@ mod tests {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
cx.run_until_parked();
|
||||||
|
|
||||||
let workspace = cx
|
let workspace = cx
|
||||||
.update(|cx| cx.windows().first().unwrap().downcast::<Workspace>())
|
.update(|cx| cx.windows().first().unwrap().downcast::<Workspace>())
|
||||||
|
Loading…
Reference in New Issue
Block a user