Detailed changes
@@ -313,6 +313,10 @@ pub trait LspAdapterDelegate: Send + Sync {
fn update_status(&self, language: LanguageServerName, status: LanguageServerBinaryStatus);
async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>>;
+ async fn npm_package_installed_version(
+ &self,
+ package_name: &str,
+ ) -> Result<Option<(PathBuf, String)>>;
async fn which(&self, command: &OsStr) -> Option<PathBuf>;
async fn shell_env(&self) -> HashMap<String, String>;
async fn read_text_file(&self, path: PathBuf) -> Result<String>;
@@ -20,6 +20,7 @@ use task::{TaskTemplate, TaskTemplates, VariableName};
use util::ResultExt;
const SERVER_PATH: &str = "node_modules/pyright/langserver.index.js";
+const NODE_MODULE_RELATIVE_SERVER_PATH: &str = "pyright/langserver.index.js";
fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
vec![server_path.into(), "--stdio".into()]
@@ -43,6 +44,26 @@ impl LspAdapter for PythonLspAdapter {
Self::SERVER_NAME.clone()
}
+ async fn check_if_user_installed(
+ &self,
+ delegate: &dyn LspAdapterDelegate,
+ _: &AsyncAppContext,
+ ) -> Option<LanguageServerBinary> {
+ let node = delegate.which("node".as_ref()).await?;
+ let (node_modules_path, _) = delegate
+ .npm_package_installed_version(Self::SERVER_NAME.as_ref())
+ .await
+ .log_err()??;
+
+ let path = node_modules_path.join(NODE_MODULE_RELATIVE_SERVER_PATH);
+
+ Some(LanguageServerBinary {
+ path: node,
+ env: None,
+ arguments: server_binary_arguments(&path),
+ })
+ }
+
async fn fetch_latest_server_version(
&self,
_: &dyn LspAdapterDelegate,
@@ -177,6 +177,7 @@ impl NodeRuntime {
"5000",
]);
+ // This is also wrong because the directory is wrong.
self.run_npm_subcommand(directory, "install", &arguments)
.await?;
Ok(())
@@ -576,7 +577,7 @@ impl NodeRuntimeTrait for SystemNodeRuntime {
}
}
-async fn read_package_installed_version(
+pub async fn read_package_installed_version(
node_module_directory: PathBuf,
name: &str,
) -> Result<Option<String>> {
@@ -48,6 +48,7 @@ use lsp::{
LspRequestFuture, MessageActionItem, MessageType, OneOf, ServerHealthStatus, ServerStatus,
SymbolKind, TextEdit, Url, WorkDoneProgressCancelParams, WorkspaceFolder,
};
+use node_runtime::read_package_installed_version;
use parking_lot::{Mutex, RwLock};
use postage::watch;
use rand::prelude::*;
@@ -7801,6 +7802,44 @@ impl LspAdapterDelegate for LocalLspAdapterDelegate {
task.await.unwrap_or_default()
}
+ async fn npm_package_installed_version(
+ &self,
+ package_name: &str,
+ ) -> Result<Option<(PathBuf, String)>> {
+ let local_package_directory = self.worktree_root_path();
+ let node_modules_directory = local_package_directory.join("node_modules");
+
+ if let Some(version) =
+ read_package_installed_version(node_modules_directory.clone(), package_name).await?
+ {
+ return Ok(Some((node_modules_directory, version)));
+ }
+ let Some(npm) = self.which("npm".as_ref()).await else {
+ log::warn!(
+ "Failed to find npm executable for {:?}",
+ local_package_directory
+ );
+ return Ok(None);
+ };
+
+ let env = self.shell_env().await;
+ let output = smol::process::Command::new(&npm)
+ .args(["root", "-g"])
+ .envs(env)
+ .current_dir(local_package_directory)
+ .output()
+ .await?;
+ let global_node_modules =
+ PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
+
+ if let Some(version) =
+ read_package_installed_version(global_node_modules.clone(), package_name).await?
+ {
+ return Ok(Some((global_node_modules, version)));
+ }
+ return Ok(None);
+ }
+
#[cfg(not(target_os = "windows"))]
async fn which(&self, command: &OsStr) -> Option<PathBuf> {
let worktree_abs_path = self.worktree.abs_path();
@@ -7883,6 +7922,13 @@ impl LspAdapterDelegate for SshLspAdapterDelegate {
.ok();
}
+ async fn npm_package_installed_version(
+ &self,
+ _package_name: &str,
+ ) -> Result<Option<(PathBuf, String)>> {
+ Ok(None)
+ }
+
fn http_client(&self) -> Arc<dyn HttpClient> {
Arc::new(BlockedHttpClient)
}