SSH remoting: terminal & tasks (#15321)

This also rolls back the `TerminalWorkDir` abstraction I added for the
original remoting, and tidies up the terminal creation code to be clear
about whether we're creating a task *or* a terminal. The previous logic
was a little muddy because it assumed we could be doing both at the same
time (which was not true).

Release Notes:

- remoting alpha: Removed the ability to specify `gh cs ssh` or `gcloud
compute ssh` etc. See https://zed.dev/docs/remote-development for
alternatives.
- remoting alpha: Added support for terminal and tasks to new
experimental ssh remoting
This commit is contained in:
Conrad Irwin 2024-07-28 22:45:00 -06:00 committed by GitHub
parent 26d0a33e79
commit 583b6235fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 404 additions and 454 deletions

View file

@ -1,6 +1,6 @@
use std::{ops::ControlFlow, path::PathBuf, sync::Arc};
use crate::TerminalView;
use crate::{default_working_directory, TerminalView};
use collections::{HashMap, HashSet};
use db::kvp::KEY_VALUE_STORE;
use futures::future::join_all;
@ -10,11 +10,11 @@ use gpui::{
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
};
use itertools::Itertools;
use project::{Fs, ProjectEntryId};
use project::{terminals::TerminalKind, Fs, ProjectEntryId};
use search::{buffer_search::DivRegistrar, BufferSearchBar};
use serde::{Deserialize, Serialize};
use settings::Settings;
use task::{RevealStrategy, Shell, SpawnInTerminal, TaskId, TerminalWorkDir};
use task::{RevealStrategy, Shell, SpawnInTerminal, TaskId};
use terminal::{
terminal_settings::{TerminalDockPosition, TerminalSettings},
Terminal,
@ -348,14 +348,13 @@ impl TerminalPanel {
return;
};
let terminal_work_dir = workspace
.project()
.read(cx)
.terminal_work_dir_for(Some(&action.working_directory), cx);
terminal_panel
.update(cx, |panel, cx| {
panel.add_terminal(terminal_work_dir, None, RevealStrategy::Always, cx)
panel.add_terminal(
TerminalKind::Shell(Some(action.working_directory.clone())),
RevealStrategy::Always,
cx,
)
})
.detach_and_log_err(cx);
}
@ -484,7 +483,7 @@ impl TerminalPanel {
cx: &mut ViewContext<Self>,
) -> Task<Result<Model<Terminal>>> {
let reveal = spawn_task.reveal;
self.add_terminal(spawn_task.cwd.clone(), Some(spawn_task), reveal, cx)
self.add_terminal(TerminalKind::Task(spawn_task), reveal, cx)
}
/// Create a new Terminal in the current working directory or the user's home directory
@ -497,9 +496,11 @@ impl TerminalPanel {
return;
};
let kind = TerminalKind::Shell(default_working_directory(workspace, cx));
terminal_panel
.update(cx, |this, cx| {
this.add_terminal(None, None, RevealStrategy::Always, cx)
this.add_terminal(kind, RevealStrategy::Always, cx)
})
.detach_and_log_err(cx);
}
@ -533,22 +534,14 @@ impl TerminalPanel {
fn add_terminal(
&mut self,
working_directory: Option<TerminalWorkDir>,
spawn_task: Option<SpawnInTerminal>,
kind: TerminalKind,
reveal_strategy: RevealStrategy,
cx: &mut ViewContext<Self>,
) -> Task<Result<Model<Terminal>>> {
if !self.enabled {
if spawn_task.is_none()
|| !matches!(
spawn_task.as_ref().unwrap().cwd,
Some(TerminalWorkDir::Ssh { .. })
)
{
return Task::ready(Err(anyhow::anyhow!(
"terminal not yet supported for remote projects"
)));
}
return Task::ready(Err(anyhow::anyhow!(
"terminal not yet supported for remote projects"
)));
}
let workspace = self.workspace.clone();
@ -557,18 +550,10 @@ impl TerminalPanel {
cx.spawn(|terminal_panel, mut cx| async move {
let pane = terminal_panel.update(&mut cx, |this, _| this.pane.clone())?;
let result = workspace.update(&mut cx, |workspace, cx| {
let working_directory = if let Some(working_directory) = working_directory {
Some(working_directory)
} else {
let working_directory_strategy =
TerminalSettings::get_global(cx).working_directory.clone();
crate::get_working_directory(workspace, cx, working_directory_strategy)
};
let window = cx.window_handle();
let terminal = workspace.project().update(cx, |project, cx| {
project.create_terminal(working_directory, spawn_task, window, cx)
})?;
let terminal = workspace
.project()
.update(cx, |project, cx| project.create_terminal(kind, window, cx))?;
let terminal_view = Box::new(cx.new_view(|cx| {
TerminalView::new(
terminal.clone(),
@ -655,7 +640,7 @@ impl TerminalPanel {
let window = cx.window_handle();
let new_terminal = project.update(cx, |project, cx| {
project
.create_terminal(spawn_task.cwd.clone(), Some(spawn_task), window, cx)
.create_terminal(TerminalKind::Task(spawn_task), window, cx)
.log_err()
})?;
terminal_to_replace.update(cx, |terminal_to_replace, cx| {
@ -802,10 +787,19 @@ impl Panel for TerminalPanel {
}
fn set_active(&mut self, active: bool, cx: &mut ViewContext<Self>) {
if active && self.has_no_terminals(cx) {
self.add_terminal(None, None, RevealStrategy::Never, cx)
.detach_and_log_err(cx)
if !active || !self.has_no_terminals(cx) {
return;
}
cx.defer(|this, cx| {
let Ok(kind) = this.workspace.update(cx, |workspace, cx| {
TerminalKind::Shell(default_working_directory(workspace, cx))
}) else {
return;
};
this.add_terminal(kind, RevealStrategy::Never, cx)
.detach_and_log_err(cx)
})
}
fn icon_label(&self, cx: &WindowContext) -> Option<String> {