Setup activation scripts in python toolchain
This commit is contained in:
parent
c9eb9a9e41
commit
d2f2142127
8 changed files with 109 additions and 249 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -9269,6 +9269,7 @@ dependencies = [
|
||||||
"snippet_provider",
|
"snippet_provider",
|
||||||
"task",
|
"task",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"terminal",
|
||||||
"text",
|
"text",
|
||||||
"theme",
|
"theme",
|
||||||
"toml 0.8.20",
|
"toml 0.8.20",
|
||||||
|
|
|
@ -71,6 +71,7 @@ settings.workspace = true
|
||||||
smol.workspace = true
|
smol.workspace = true
|
||||||
snippet_provider.workspace = true
|
snippet_provider.workspace = true
|
||||||
task.workspace = true
|
task.workspace = true
|
||||||
|
terminal.workspace = true
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
toml.workspace = true
|
toml.workspace = true
|
||||||
tree-sitter = { workspace = true, optional = true }
|
tree-sitter = { workspace = true, optional = true }
|
||||||
|
|
|
@ -2,6 +2,7 @@ use anyhow::{Context as _, ensure};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
use futures::AsyncBufReadExt;
|
||||||
use gpui::{App, Task};
|
use gpui::{App, Task};
|
||||||
use gpui::{AsyncApp, SharedString};
|
use gpui::{AsyncApp, SharedString};
|
||||||
use language::Toolchain;
|
use language::Toolchain;
|
||||||
|
@ -30,8 +31,6 @@ use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
fmt::Write,
|
fmt::Write,
|
||||||
fs,
|
|
||||||
io::{self, BufRead},
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
@ -741,14 +740,16 @@ fn env_priority(kind: Option<PythonEnvironmentKind>) -> usize {
|
||||||
/// Return the name of environment declared in <worktree-root/.venv.
|
/// Return the name of environment declared in <worktree-root/.venv.
|
||||||
///
|
///
|
||||||
/// https://virtualfish.readthedocs.io/en/latest/plugins.html#auto-activation-auto-activation
|
/// https://virtualfish.readthedocs.io/en/latest/plugins.html#auto-activation-auto-activation
|
||||||
fn get_worktree_venv_declaration(worktree_root: &Path) -> Option<String> {
|
async fn get_worktree_venv_declaration(worktree_root: &Path) -> Option<String> {
|
||||||
fs::File::open(worktree_root.join(".venv"))
|
let file = async_fs::File::open(worktree_root.join(".venv"))
|
||||||
.and_then(|file| {
|
.await
|
||||||
let mut venv_name = String::new();
|
.ok()?;
|
||||||
io::BufReader::new(file).read_line(&mut venv_name)?;
|
let mut venv_name = String::new();
|
||||||
Ok(venv_name.trim().to_string())
|
smol::io::BufReader::new(file)
|
||||||
})
|
.read_line(&mut venv_name)
|
||||||
.ok()
|
.await
|
||||||
|
.ok()?;
|
||||||
|
Some(venv_name.trim().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -791,7 +792,7 @@ impl ToolchainLister for PythonToolchainProvider {
|
||||||
.map_or(Vec::new(), |mut guard| std::mem::take(&mut guard));
|
.map_or(Vec::new(), |mut guard| std::mem::take(&mut guard));
|
||||||
|
|
||||||
let wr = worktree_root;
|
let wr = worktree_root;
|
||||||
let wr_venv = get_worktree_venv_declaration(&wr);
|
let wr_venv = get_worktree_venv_declaration(&wr).await;
|
||||||
// Sort detected environments by:
|
// Sort detected environments by:
|
||||||
// environment name matching activation file (<workdir>/.venv)
|
// environment name matching activation file (<workdir>/.venv)
|
||||||
// environment project dir matching worktree_root
|
// environment project dir matching worktree_root
|
||||||
|
@ -856,7 +857,7 @@ impl ToolchainLister for PythonToolchainProvider {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|toolchain| {
|
.filter_map(|toolchain| {
|
||||||
let mut name = String::from("Python");
|
let mut name = String::from("Python");
|
||||||
if let Some(ref version) = toolchain.version {
|
if let Some(version) = &toolchain.version {
|
||||||
_ = write!(name, " {version}");
|
_ = write!(name, " {version}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,13 +877,46 @@ impl ToolchainLister for PythonToolchainProvider {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
path: toolchain.executable.as_ref()?.to_str()?.to_owned().into(),
|
path: toolchain.executable.as_ref()?.to_str()?.to_owned().into(),
|
||||||
language_name: LanguageName::new("Python"),
|
language_name: LanguageName::new("Python"),
|
||||||
as_json: serde_json::to_value(toolchain).ok()?,
|
as_json: serde_json::to_value(toolchain.clone()).ok()?,
|
||||||
activation_script: std::iter::once((
|
activation_script: match (toolchain.kind, toolchain.prefix) {
|
||||||
ShellKind::Fish,
|
(Some(PythonEnvironmentKind::Venv), Some(prefix)) => [
|
||||||
"echo python recognized a venv and injected a fish startup command"
|
(
|
||||||
.to_owned(),
|
ShellKind::Fish,
|
||||||
))
|
"source",
|
||||||
.collect(),
|
prefix.join(BINARY_DIR).join("activate.fish"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ShellKind::Powershell,
|
||||||
|
".",
|
||||||
|
prefix.join(BINARY_DIR).join("activate.ps1"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ShellKind::Nushell,
|
||||||
|
"overlay use",
|
||||||
|
prefix.join(BINARY_DIR).join("activate.nu"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ShellKind::Posix,
|
||||||
|
".",
|
||||||
|
prefix.join(BINARY_DIR).join("activate"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ShellKind::Cmd,
|
||||||
|
".",
|
||||||
|
prefix.join(BINARY_DIR).join("activate.bat"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ShellKind::Csh,
|
||||||
|
".",
|
||||||
|
prefix.join(BINARY_DIR).join("activate.csh"),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(_, _, path)| path.exists() && path.is_file())
|
||||||
|
.map(|(kind, cmd, path)| (kind, format!("{cmd} {}", path.display())))
|
||||||
|
.collect(),
|
||||||
|
_ => Default::default(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -1694,180 +1728,3 @@ mod tests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
fn python_venv_directory(
|
|
||||||
abs_path: Arc<Path>,
|
|
||||||
venv_settings: VenvSettings,
|
|
||||||
cx: &Context<Project>,
|
|
||||||
) -> Task<Option<PathBuf>> {
|
|
||||||
cx.spawn(async move |this, cx| {
|
|
||||||
if let Some((worktree, relative_path)) = this
|
|
||||||
.update(cx, |this, cx| this.find_worktree(&abs_path, cx))
|
|
||||||
.ok()?
|
|
||||||
{
|
|
||||||
let toolchain = this
|
|
||||||
.update(cx, |this, cx| {
|
|
||||||
this.active_toolchain(
|
|
||||||
ProjectPath {
|
|
||||||
worktree_id: worktree.read(cx).id(),
|
|
||||||
path: relative_path.into(),
|
|
||||||
},
|
|
||||||
LanguageName::new("Python"),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.ok()?
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let Some(toolchain) = toolchain {
|
|
||||||
let toolchain_path = Path::new(toolchain.path.as_ref());
|
|
||||||
return Some(toolchain_path.parent()?.parent()?.to_path_buf());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let venv_settings = venv_settings.as_option()?;
|
|
||||||
this.update(cx, move |this, cx| {
|
|
||||||
if let Some(path) = this.find_venv_in_worktree(&abs_path, &venv_settings, cx) {
|
|
||||||
return Some(path);
|
|
||||||
}
|
|
||||||
this.find_venv_on_filesystem(&abs_path, &venv_settings, cx)
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_venv_in_worktree(
|
|
||||||
&self,
|
|
||||||
abs_path: &Path,
|
|
||||||
venv_settings: &terminal_settings::VenvSettingsContent,
|
|
||||||
cx: &App,
|
|
||||||
) -> Option<PathBuf> {
|
|
||||||
venv_settings
|
|
||||||
.directories
|
|
||||||
.iter()
|
|
||||||
.map(|name| abs_path.join(name))
|
|
||||||
.find(|venv_path| {
|
|
||||||
let bin_path = venv_path.join(PYTHON_VENV_BIN_DIR);
|
|
||||||
self.find_worktree(&bin_path, cx)
|
|
||||||
.and_then(|(worktree, relative_path)| {
|
|
||||||
worktree.read(cx).entry_for_path(&relative_path)
|
|
||||||
})
|
|
||||||
.is_some_and(|entry| entry.is_dir())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_venv_on_filesystem(
|
|
||||||
&self,
|
|
||||||
abs_path: &Path,
|
|
||||||
venv_settings: &terminal_settings::VenvSettingsContent,
|
|
||||||
cx: &App,
|
|
||||||
) -> Option<PathBuf> {
|
|
||||||
let (worktree, _) = self.find_worktree(abs_path, cx)?;
|
|
||||||
let fs = worktree.read(cx).as_local()?.fs();
|
|
||||||
venv_settings
|
|
||||||
.directories
|
|
||||||
.iter()
|
|
||||||
.map(|name| abs_path.join(name))
|
|
||||||
.find(|venv_path| {
|
|
||||||
let bin_path = venv_path.join(PYTHON_VENV_BIN_DIR);
|
|
||||||
// One-time synchronous check is acceptable for terminal/task initialization
|
|
||||||
smol::block_on(fs.metadata(&bin_path))
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.map_or(false, |meta| meta.is_dir)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate_script_kind(shell: Option<&str>) -> ActivateScript {
|
|
||||||
let shell_env = std::env::var("SHELL").ok();
|
|
||||||
let shell_path = shell.or_else(|| shell_env.as_deref());
|
|
||||||
let shell = std::path::Path::new(shell_path.unwrap_or(""))
|
|
||||||
.file_name()
|
|
||||||
.and_then(|name| name.to_str())
|
|
||||||
.unwrap_or("");
|
|
||||||
match shell {
|
|
||||||
"fish" => ActivateScript::Fish,
|
|
||||||
"tcsh" => ActivateScript::Csh,
|
|
||||||
"nu" => ActivateScript::Nushell,
|
|
||||||
"powershell" | "pwsh" => ActivateScript::PowerShell,
|
|
||||||
_ => ActivateScript::Default,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn python_activate_command(
|
|
||||||
&self,
|
|
||||||
venv_base_directory: &Path,
|
|
||||||
venv_settings: &VenvSettings,
|
|
||||||
shell: &Shell,
|
|
||||||
cx: &mut App,
|
|
||||||
) -> Task<Option<String>> {
|
|
||||||
let Some(venv_settings) = venv_settings.as_option() else {
|
|
||||||
return Task::ready(None);
|
|
||||||
};
|
|
||||||
let activate_keyword = match venv_settings.activate_script {
|
|
||||||
terminal_settings::ActivateScript::Default => match std::env::consts::OS {
|
|
||||||
"windows" => ".",
|
|
||||||
_ => ".",
|
|
||||||
},
|
|
||||||
terminal_settings::ActivateScript::Nushell => "overlay use",
|
|
||||||
terminal_settings::ActivateScript::PowerShell => ".",
|
|
||||||
terminal_settings::ActivateScript::Pyenv => "pyenv",
|
|
||||||
_ => "source",
|
|
||||||
};
|
|
||||||
let script_kind = if venv_settings.activate_script == terminal_settings::ActivateScript::Default
|
|
||||||
{
|
|
||||||
match shell {
|
|
||||||
Shell::Program(program) => Self::activate_script_kind(Some(program)),
|
|
||||||
Shell::WithArguments {
|
|
||||||
program,
|
|
||||||
args: _,
|
|
||||||
title_override: _,
|
|
||||||
} => Self::activate_script_kind(Some(program)),
|
|
||||||
Shell::System => Self::activate_script_kind(None),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
venv_settings.activate_script
|
|
||||||
};
|
|
||||||
|
|
||||||
let activate_script_name = match script_kind {
|
|
||||||
terminal_settings::ActivateScript::Default | terminal_settings::ActivateScript::Pyenv => {
|
|
||||||
"activate"
|
|
||||||
}
|
|
||||||
terminal_settings::ActivateScript::Csh => "activate.csh",
|
|
||||||
terminal_settings::ActivateScript::Fish => "activate.fish",
|
|
||||||
terminal_settings::ActivateScript::Nushell => "activate.nu",
|
|
||||||
terminal_settings::ActivateScript::PowerShell => "activate.ps1",
|
|
||||||
};
|
|
||||||
|
|
||||||
let line_ending = match std::env::consts::OS {
|
|
||||||
"windows" => "\r",
|
|
||||||
_ => "\n",
|
|
||||||
};
|
|
||||||
|
|
||||||
if venv_settings.venv_name.is_empty() {
|
|
||||||
let path = venv_base_directory
|
|
||||||
.join(PYTHON_VENV_BIN_DIR)
|
|
||||||
.join(activate_script_name)
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let is_valid_path = self.resolve_abs_path(path.as_ref(), cx);
|
|
||||||
cx.background_spawn(async move {
|
|
||||||
let quoted = shlex::try_quote(&path).ok()?;
|
|
||||||
if is_valid_path.await.is_some_and(|meta| meta.is_file()) {
|
|
||||||
Some(format!(
|
|
||||||
"{} {} ; clear{}",
|
|
||||||
activate_keyword, quoted, line_ending
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Task::ready(Some(format!(
|
|
||||||
"{activate_keyword} {activate_script_name} {name}; clear{line_ending}",
|
|
||||||
name = venv_settings.venv_name
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use task::{Shell, ShellBuilder, ShellKind, SpawnInTerminal, system_shell};
|
use task::{Shell, ShellBuilder, ShellKind, SpawnInTerminal};
|
||||||
use terminal::{
|
use terminal::{
|
||||||
TaskState, TaskStatus, Terminal, TerminalBuilder, terminal_settings::TerminalSettings,
|
TaskState, TaskStatus, Terminal, TerminalBuilder, terminal_settings::TerminalSettings,
|
||||||
};
|
};
|
||||||
use util::{
|
use util::{
|
||||||
maybe,
|
get_system_shell, maybe,
|
||||||
paths::{PathStyle, RemotePathBuf},
|
paths::{PathStyle, RemotePathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -287,18 +287,17 @@ impl Project {
|
||||||
args: _,
|
args: _,
|
||||||
title_override: _,
|
title_override: _,
|
||||||
} => program.clone(),
|
} => program.clone(),
|
||||||
Shell::System => system_shell(),
|
Shell::System => get_system_shell(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
let shell_kind = ShellKind::new(&shell);
|
||||||
|
|
||||||
let scripts = maybe!(async {
|
let scripts = maybe!(async {
|
||||||
let toolchain = toolchain?.await?;
|
let toolchain = toolchain?.await?;
|
||||||
Some(toolchain.activation_script)
|
Some(toolchain.activation_script)
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
let activation_script = scripts
|
let activation_script = scripts.as_ref().and_then(|it| it.get(&shell_kind));
|
||||||
.as_ref()
|
|
||||||
.and_then(|it| it.get(&ShellKind::new(&shell)));
|
|
||||||
let shell = {
|
let shell = {
|
||||||
match ssh_details {
|
match ssh_details {
|
||||||
Some(SshDetails {
|
Some(SshDetails {
|
||||||
|
@ -336,19 +335,17 @@ impl Project {
|
||||||
title_override: Some(format!("{} — Terminal", host).into()),
|
title_override: Some(format!("{} — Terminal", host).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None if activation_script.is_some() => Shell::WithArguments {
|
None => match activation_script {
|
||||||
program: shell.clone(),
|
Some(activation_script) => Shell::WithArguments {
|
||||||
args: vec![
|
program: shell.clone(),
|
||||||
"-c".to_owned(),
|
args: vec![
|
||||||
format!(
|
"-c".to_owned(),
|
||||||
"{}; exec {} -l",
|
format!("{activation_script}; exec {shell} -l",),
|
||||||
activation_script.unwrap().to_string(),
|
],
|
||||||
shell
|
title_override: None,
|
||||||
),
|
},
|
||||||
],
|
None => settings.shell,
|
||||||
title_override: None,
|
|
||||||
},
|
},
|
||||||
None => settings.shell,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
project.update(cx, move |this, cx| {
|
project.update(cx, move |this, cx| {
|
||||||
|
@ -508,6 +505,7 @@ pub fn wrap_for_ssh(
|
||||||
path_style: PathStyle,
|
path_style: PathStyle,
|
||||||
activation_script: Option<&str>,
|
activation_script: Option<&str>,
|
||||||
) -> (String, Vec<String>) {
|
) -> (String, Vec<String>) {
|
||||||
|
// todo make this shell aware
|
||||||
let to_run = if let Some((command, args)) = command {
|
let to_run = if let Some((command, args)) = command {
|
||||||
let command: Option<Cow<str>> = shlex::try_quote(command).ok();
|
let command: Option<Cow<str>> = shlex::try_quote(command).ok();
|
||||||
let args = args.iter().filter_map(|arg| shlex::try_quote(arg).ok());
|
let args = args.iter().filter_map(|arg| shlex::try_quote(arg).ok());
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use util::get_system_shell;
|
||||||
|
|
||||||
use crate::Shell;
|
use crate::Shell;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
@ -28,7 +30,7 @@ impl fmt::Display for ShellKind {
|
||||||
|
|
||||||
impl ShellKind {
|
impl ShellKind {
|
||||||
pub fn system() -> Self {
|
pub fn system() -> Self {
|
||||||
Self::new(&system_shell())
|
Self::new(&get_system_shell())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(program: &str) -> Self {
|
pub fn new(program: &str) -> Self {
|
||||||
|
@ -37,12 +39,12 @@ impl ShellKind {
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
let (_, program) = program.rsplit_once('/').unwrap_or(("", program));
|
let (_, program) = program.rsplit_once('/').unwrap_or(("", program));
|
||||||
if program == "powershell"
|
if program == "powershell"
|
||||||
|| program == "powershell.exe"
|
|| program.ends_with("powershell.exe")
|
||||||
|| program == "pwsh"
|
|| program == "pwsh"
|
||||||
|| program == "pwsh.exe"
|
|| program.ends_with("pwsh.exe")
|
||||||
{
|
{
|
||||||
ShellKind::Powershell
|
ShellKind::Powershell
|
||||||
} else if program == "cmd" || program == "cmd.exe" {
|
} else if program == "cmd" || program.ends_with("cmd.exe") {
|
||||||
ShellKind::Cmd
|
ShellKind::Cmd
|
||||||
} else if program == "nu" {
|
} else if program == "nu" {
|
||||||
ShellKind::Nushell
|
ShellKind::Nushell
|
||||||
|
@ -193,18 +195,6 @@ impl ShellKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn system_shell() -> String {
|
|
||||||
if cfg!(target_os = "windows") {
|
|
||||||
// `alacritty_terminal` uses this as default on Windows. See:
|
|
||||||
// https://github.com/alacritty/alacritty/blob/0d4ab7bca43213d96ddfe40048fc0f922543c6f8/alacritty_terminal/src/tty/windows/mod.rs#L130
|
|
||||||
// We could use `util::get_windows_system_shell()` here, but we are running tasks here, so leave it to `powershell.exe`
|
|
||||||
// should be okay.
|
|
||||||
"powershell.exe".to_string()
|
|
||||||
} else {
|
|
||||||
std::env::var("SHELL").unwrap_or("/bin/sh".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ShellBuilder is used to turn a user-requested task into a
|
/// ShellBuilder is used to turn a user-requested task into a
|
||||||
/// program that can be executed by the shell.
|
/// program that can be executed by the shell.
|
||||||
pub struct ShellBuilder {
|
pub struct ShellBuilder {
|
||||||
|
@ -221,7 +211,7 @@ impl ShellBuilder {
|
||||||
let (program, args) = match shell {
|
let (program, args) = match shell {
|
||||||
Shell::System => match remote_system_shell {
|
Shell::System => match remote_system_shell {
|
||||||
Some(remote_shell) => (remote_shell.to_string(), Vec::new()),
|
Some(remote_shell) => (remote_shell.to_string(), Vec::new()),
|
||||||
None => (system_shell(), Vec::new()),
|
None => (get_system_shell(), Vec::new()),
|
||||||
},
|
},
|
||||||
Shell::Program(shell) => (shell.clone(), Vec::new()),
|
Shell::Program(shell) => (shell.clone(), Vec::new()),
|
||||||
Shell::WithArguments { program, args, .. } => (program.clone(), args.clone()),
|
Shell::WithArguments { program, args, .. } => (program.clone(), args.clone()),
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub use debug_format::{
|
||||||
AttachRequest, BuildTaskDefinition, DebugRequest, DebugScenario, DebugTaskFile, LaunchRequest,
|
AttachRequest, BuildTaskDefinition, DebugRequest, DebugScenario, DebugTaskFile, LaunchRequest,
|
||||||
Request, TcpArgumentsTemplate, ZedDebugConfig,
|
Request, TcpArgumentsTemplate, ZedDebugConfig,
|
||||||
};
|
};
|
||||||
pub use shell_builder::{ShellBuilder, ShellKind, system_shell};
|
pub use shell_builder::{ShellBuilder, ShellKind};
|
||||||
pub use task_template::{
|
pub use task_template::{
|
||||||
DebugArgsRequest, HideStrategy, RevealStrategy, TaskTemplate, TaskTemplates,
|
DebugArgsRequest, HideStrategy, RevealStrategy, TaskTemplate, TaskTemplates,
|
||||||
substitute_variables_in_map, substitute_variables_in_str,
|
substitute_variables_in_map, substitute_variables_in_str,
|
||||||
|
|
|
@ -3,9 +3,12 @@ use async_recursion::async_recursion;
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
use futures::{StreamExt as _, stream::FuturesUnordered};
|
use futures::{StreamExt as _, stream::FuturesUnordered};
|
||||||
use gpui::{AppContext as _, AsyncWindowContext, Axis, Entity, Task, WeakEntity};
|
use gpui::{AppContext as _, AsyncWindowContext, Axis, Entity, Task, WeakEntity};
|
||||||
use project::Project;
|
use project::{Project, ProjectPath};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
use ui::{App, Context, Pixels, Window};
|
use ui::{App, Context, Pixels, Window};
|
||||||
use util::ResultExt as _;
|
use util::ResultExt as _;
|
||||||
|
|
||||||
|
@ -242,8 +245,19 @@ async fn deserialize_pane_group(
|
||||||
.update(cx, |workspace, cx| default_working_directory(workspace, cx))
|
.update(cx, |workspace, cx| default_working_directory(workspace, cx))
|
||||||
.ok()
|
.ok()
|
||||||
.flatten();
|
.flatten();
|
||||||
|
let p = workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
let worktree = workspace.worktrees(cx).next()?.read(cx);
|
||||||
|
worktree.root_dir()?;
|
||||||
|
Some(ProjectPath {
|
||||||
|
worktree_id: worktree.id(),
|
||||||
|
path: Arc::from(Path::new("")),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten();
|
||||||
let terminal = project.update(cx, |project, cx| {
|
let terminal = project.update(cx, |project, cx| {
|
||||||
project.create_terminal_shell(working_directory, cx, None)
|
project.create_terminal_shell(working_directory, cx, p)
|
||||||
});
|
});
|
||||||
Some(Some(terminal))
|
Some(Some(terminal))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use gpui::{
|
||||||
deferred, div,
|
deferred, div,
|
||||||
};
|
};
|
||||||
use persistence::TERMINAL_DB;
|
use persistence::TERMINAL_DB;
|
||||||
use project::{Project, search::SearchQuery};
|
use project::{Project, ProjectPath, search::SearchQuery};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use task::TaskId;
|
use task::TaskId;
|
||||||
use terminal::{
|
use terminal::{
|
||||||
|
@ -1498,20 +1498,19 @@ impl SerializableItem for TerminalView {
|
||||||
.ok()
|
.ok()
|
||||||
.flatten();
|
.flatten();
|
||||||
|
|
||||||
|
let p = workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
let worktree = workspace.worktrees(cx).next()?.read(cx);
|
||||||
|
worktree.root_dir()?;
|
||||||
|
Some(ProjectPath {
|
||||||
|
worktree_id: worktree.id(),
|
||||||
|
path: Arc::from(Path::new("")),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten();
|
||||||
let terminal = project
|
let terminal = project
|
||||||
.update(cx, |project, cx| {
|
.update(cx, |project, cx| project.create_terminal_shell(cwd, cx, p))?
|
||||||
project.create_terminal_shell(
|
|
||||||
cwd,
|
|
||||||
cx,
|
|
||||||
project
|
|
||||||
.active_entry()
|
|
||||||
.and_then(|entry_id| project.worktree_id_for_entry(entry_id, cx))
|
|
||||||
.map(|worktree_id| project::ProjectPath {
|
|
||||||
worktree_id,
|
|
||||||
path: Arc::from(Path::new("")),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.await?;
|
.await?;
|
||||||
cx.update(|window, cx| {
|
cx.update(|window, cx| {
|
||||||
cx.new(|cx| {
|
cx.new(|cx| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue