windows: Fix extensions couldn't start if the path contained spaces (#15489)

张小白 created

Closes #15441 .

Fixed the issue where extensions couldn't start if the path contained
spaces. Additionally, this PR introduces the `node_environment_path`
function to obtain the PATH environment variable which includes the node
path.

Release Notes:

- N/A

Change summary

crates/languages/src/tailwind.rs        | 21 +++++----------
crates/node_runtime/src/node_runtime.rs | 36 +++++++++++++++++---------
2 files changed, 30 insertions(+), 27 deletions(-)

Detailed changes

crates/languages/src/tailwind.rs 🔗

@@ -23,10 +23,16 @@ const SERVER_PATH: &str = "node_modules/.bin/tailwindcss-language-server.ps1";
 #[cfg(not(target_os = "windows"))]
 const SERVER_PATH: &str = "node_modules/.bin/tailwindcss-language-server";
 
+#[cfg(not(target_os = "windows"))]
 fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
     vec![server_path.into(), "--stdio".into()]
 }
 
+#[cfg(target_os = "windows")]
+fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
+    vec!["-File".into(), server_path.into(), "--stdio".into()]
+}
+
 pub struct TailwindLspAdapter {
     node: Arc<dyn NodeRuntime>,
 }
@@ -113,20 +119,7 @@ impl LspAdapter for TailwindLspAdapter {
 
         #[cfg(target_os = "windows")]
         {
-            let mut env_path = vec![self
-                .node
-                .binary_path()
-                .await?
-                .parent()
-                .expect("invalid node binary path")
-                .to_path_buf()];
-
-            if let Some(existing_path) = std::env::var_os("PATH") {
-                let mut paths = std::env::split_paths(&existing_path).collect::<Vec<_>>();
-                env_path.append(&mut paths);
-            }
-
-            let env_path = std::env::join_paths(env_path)?;
+            let env_path = self.node.node_environment_path().await?;
             let mut env = HashMap::default();
             env.insert("PATH".to_string(), env_path.to_string_lossy().to_string());
 

crates/node_runtime/src/node_runtime.rs 🔗

@@ -10,6 +10,7 @@ use semver::Version;
 use serde::Deserialize;
 use smol::io::BufReader;
 use smol::{fs, lock::Mutex, process::Command};
+use std::ffi::OsString;
 use std::io;
 use std::process::{Output, Stdio};
 use std::{
@@ -55,6 +56,7 @@ pub struct NpmInfoDistTags {
 #[async_trait::async_trait]
 pub trait NodeRuntime: Send + Sync {
     async fn binary_path(&self) -> Result<PathBuf>;
+    async fn node_environment_path(&self) -> Result<OsString>;
 
     async fn run_npm_subcommand(
         &self,
@@ -216,6 +218,22 @@ impl NodeRuntime for RealNodeRuntime {
         Ok(installation_path.join(NODE_PATH))
     }
 
+    async fn node_environment_path(&self) -> Result<OsString> {
+        let installation_path = self.install_if_needed().await?;
+        let node_binary = installation_path.join(NODE_PATH);
+        let mut env_path = vec![node_binary
+            .parent()
+            .expect("invalid node binary path")
+            .to_path_buf()];
+
+        if let Some(existing_path) = std::env::var_os("PATH") {
+            let mut paths = std::env::split_paths(&existing_path).collect::<Vec<_>>();
+            env_path.append(&mut paths);
+        }
+
+        Ok(std::env::join_paths(env_path).context("failed to create PATH env variable")?)
+    }
+
     async fn run_npm_subcommand(
         &self,
         directory: Option<&Path>,
@@ -224,21 +242,9 @@ impl NodeRuntime for RealNodeRuntime {
     ) -> Result<Output> {
         let attempt = || async move {
             let installation_path = self.install_if_needed().await?;
-
             let node_binary = installation_path.join(NODE_PATH);
             let npm_file = installation_path.join(NPM_PATH);
-            let mut env_path = vec![node_binary
-                .parent()
-                .expect("invalid node binary path")
-                .to_path_buf()];
-
-            if let Some(existing_path) = std::env::var_os("PATH") {
-                let mut paths = std::env::split_paths(&existing_path).collect::<Vec<_>>();
-                env_path.append(&mut paths);
-            }
-
-            let env_path =
-                std::env::join_paths(env_path).context("failed to create PATH env variable")?;
+            let env_path = self.node_environment_path().await?;
 
             if smol::fs::metadata(&node_binary).await.is_err() {
                 return Err(anyhow!("missing node binary file"));
@@ -423,6 +429,10 @@ impl NodeRuntime for FakeNodeRuntime {
         unreachable!()
     }
 
+    async fn node_environment_path(&self) -> anyhow::Result<OsString> {
+        unreachable!()
+    }
+
     async fn run_npm_subcommand(
         &self,
         _: Option<&Path>,