Cargo.lock 🔗
@@ -9301,6 +9301,7 @@ dependencies = [
"serde_json_lenient",
"settings",
"sha2",
+ "shlex",
"smol",
"snippet_provider",
"task",
Lukas Wirth created
Tasks are still disabled as there seem to be more issues with it
Release Notes:
- N/A
Cargo.lock | 1
crates/agent_ui/src/acp/thread_view.rs | 2
crates/languages/Cargo.toml | 1
crates/languages/src/python.rs | 9 +++-
crates/project/src/terminals.rs | 22 ++++++++++++-
crates/terminal/src/terminal.rs | 8 +++-
crates/terminal_view/src/terminal_panel.rs | 38 +----------------------
7 files changed, 38 insertions(+), 43 deletions(-)
@@ -9301,6 +9301,7 @@ dependencies = [
"serde_json_lenient",
"settings",
"sha2",
+ "shlex",
"smol",
"snippet_provider",
"task",
@@ -1607,7 +1607,7 @@ impl AcpThreadView {
task.shell = shell;
let terminal = terminal_panel.update_in(cx, |terminal_panel, window, cx| {
- terminal_panel.spawn_task(&login, window, cx)
+ terminal_panel.spawn_task(login.clone(), window, cx)
})?;
let terminal = terminal.await?;
@@ -92,6 +92,7 @@ tree-sitter-typescript = { workspace = true, optional = true }
tree-sitter-yaml = { workspace = true, optional = true }
util.workspace = true
workspace-hack.workspace = true
+shlex.workspace = true
[dev-dependencies]
pretty_assertions.workspace = true
@@ -918,9 +918,12 @@ impl ToolchainLister for PythonToolchainProvider {
ShellKind::Cmd => "activate.bat",
};
let path = prefix.join(BINARY_DIR).join(activate_script_name);
- if fs.is_file(&path).await {
- activation_script
- .push(format!("{activate_keyword} \"{}\"", path.display()));
+
+ if let Ok(quoted) =
+ shlex::try_quote(&path.to_string_lossy()).map(Cow::into_owned)
+ && fs.is_file(&path).await
+ {
+ activation_script.push(format!("{activate_keyword} {quoted}"));
}
}
}
@@ -197,7 +197,7 @@ impl Project {
)?,
},
None => match activation_script.clone() {
- #[cfg(not(target_os = "windows"))]
+ #[cfg(not(windows))]
activation_script if !activation_script.is_empty() => {
let activation_script = activation_script.join("; ");
let to_run = if let Some(command) = spawn_task.command {
@@ -214,7 +214,25 @@ impl Project {
program: shell,
args: vec![
"-c".to_owned(),
- format!("{activation_script}; {to_run}",),
+ // alacritty formats all args into a single string literally without extra quoting before handing it off to powershell
+ // so we work around this here
+ if cfg!(windows) {
+ println!(
+ "{}",
+ shlex::try_quote(&format!(
+ "{activation_script}; {to_run}",
+ ))
+ .unwrap()
+ .into_owned()
+ );
+ shlex::try_quote(&format!(
+ "{activation_script}; {to_run}",
+ ))
+ .unwrap()
+ .into_owned()
+ } else {
+ format!("{activation_script}; {to_run}",)
+ },
],
title_override: None,
}
@@ -531,10 +531,14 @@ impl TerminalBuilder {
},
};
- if cfg!(not(target_os = "windows")) && !activation_script.is_empty() && no_task {
+ if !activation_script.is_empty() && no_task {
for activation_script in activation_script {
terminal.input(activation_script.into_bytes());
- terminal.write_to_pty(b"\n");
+ terminal.write_to_pty(if cfg!(windows) {
+ &b"\r\n"[..]
+ } else {
+ &b"\n"[..]
+ });
}
terminal.clear();
}
@@ -19,7 +19,7 @@ use itertools::Itertools;
use project::{Fs, Project, ProjectEntryId};
use search::{BufferSearchBar, buffer_search::DivRegistrar};
use settings::Settings;
-use task::{RevealStrategy, RevealTarget, ShellBuilder, SpawnInTerminal, TaskId};
+use task::{RevealStrategy, RevealTarget, SpawnInTerminal, TaskId};
use terminal::{
Terminal,
terminal_settings::{TerminalDockPosition, TerminalSettings},
@@ -496,42 +496,10 @@ impl TerminalPanel {
pub fn spawn_task(
&mut self,
- task: &SpawnInTerminal,
+ task: SpawnInTerminal,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<WeakEntity<Terminal>>> {
- let remote_client = self
- .workspace
- .update(cx, |workspace, cx| {
- let project = workspace.project().read(cx);
- if project.is_via_collab() {
- Err(anyhow!("cannot spawn tasks as a guest"))
- } else {
- Ok(project.remote_client())
- }
- })
- .flatten();
-
- let remote_client = match remote_client {
- Ok(remote_client) => remote_client,
- Err(e) => return Task::ready(Err(e)),
- };
-
- let remote_shell = remote_client
- .as_ref()
- .and_then(|remote_client| remote_client.read(cx).shell());
-
- let builder = ShellBuilder::new(remote_shell.as_deref(), &task.shell);
- let command_label = builder.command_label(&task.command_label);
- let (command, args) = builder.build(task.command.clone(), &task.args);
-
- let task = SpawnInTerminal {
- command_label,
- command: Some(command),
- args,
- ..task.clone()
- };
-
if task.allow_concurrent_runs && task.use_new_terminal {
return self.spawn_in_new_terminal(task, window, cx);
}
@@ -1565,7 +1533,7 @@ impl workspace::TerminalProvider for TerminalProvider {
window.spawn(cx, async move |cx| {
let terminal = terminal_panel
.update_in(cx, |terminal_panel, window, cx| {
- terminal_panel.spawn_task(&task, window, cx)
+ terminal_panel.spawn_task(task, window, cx)
})
.ok()?
.await;