mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-16 17:07:14 +03:00
JSON: Show package.json dependency tooltips on hover (#13481)
Fixes https://github.com/zed-industries/zed/issues/13303 Release Notes: - Added package version tooltips when hovering over package.json dependency entries.
This commit is contained in:
parent
6c0cb9eaa3
commit
55511d1591
@ -1,25 +1,32 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
|
use async_tar::Archive;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use feature_flags::FeatureFlagAppExt;
|
use feature_flags::FeatureFlagAppExt;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{AppContext, AsyncAppContext};
|
use gpui::{AppContext, AsyncAppContext};
|
||||||
|
use http::github::{latest_github_release, GitHubLspBinaryVersion};
|
||||||
use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use project::ContextProviderWithTasks;
|
use project::ContextProviderWithTasks;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
|
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
|
||||||
use smol::fs;
|
use smol::{
|
||||||
|
fs::{self},
|
||||||
|
io::BufReader,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
|
env::consts,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
};
|
};
|
||||||
use task::{TaskTemplate, TaskTemplates, VariableName};
|
use task::{TaskTemplate, TaskTemplates, VariableName};
|
||||||
use util::{maybe, ResultExt};
|
use util::{fs::remove_matching, maybe, ResultExt};
|
||||||
|
|
||||||
const SERVER_PATH: &str =
|
const SERVER_PATH: &str =
|
||||||
"node_modules/vscode-langservers-extracted/bin/vscode-json-language-server";
|
"node_modules/vscode-langservers-extracted/bin/vscode-json-language-server";
|
||||||
@ -251,3 +258,137 @@ fn schema_file_match(path: &Path) -> String {
|
|||||||
.to_string()
|
.to_string()
|
||||||
.replace('\\', "/")
|
.replace('\\', "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) struct NodeVersionAdapter;
|
||||||
|
|
||||||
|
#[async_trait(?Send)]
|
||||||
|
impl LspAdapter for NodeVersionAdapter {
|
||||||
|
fn name(&self) -> LanguageServerName {
|
||||||
|
LanguageServerName("package-version-server".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_latest_server_version(
|
||||||
|
&self,
|
||||||
|
delegate: &dyn LspAdapterDelegate,
|
||||||
|
) -> Result<Box<dyn 'static + Send + Any>> {
|
||||||
|
let release = latest_github_release(
|
||||||
|
"zed-industries/package-version-server",
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
delegate.http_client(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let os = match consts::OS {
|
||||||
|
"macos" => "apple-darwin",
|
||||||
|
"linux" => "unknown-linux-gnu",
|
||||||
|
"windows" => "pc-windows-msvc",
|
||||||
|
other => bail!("Running on unsupported os: {other}"),
|
||||||
|
};
|
||||||
|
let suffix = if consts::OS == "windows" {
|
||||||
|
".zip"
|
||||||
|
} else {
|
||||||
|
".tar.gz"
|
||||||
|
};
|
||||||
|
let asset_name = format!("package-version-server-{}-{os}{suffix}", consts::ARCH);
|
||||||
|
let asset = release
|
||||||
|
.assets
|
||||||
|
.iter()
|
||||||
|
.find(|asset| asset.name == asset_name)
|
||||||
|
.with_context(|| format!("no asset found matching `{asset_name:?}`"))?;
|
||||||
|
Ok(Box::new(GitHubLspBinaryVersion {
|
||||||
|
name: release.tag_name,
|
||||||
|
url: asset.browser_download_url.clone(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_server_binary(
|
||||||
|
&self,
|
||||||
|
latest_version: Box<dyn 'static + Send + Any>,
|
||||||
|
container_dir: PathBuf,
|
||||||
|
delegate: &dyn LspAdapterDelegate,
|
||||||
|
) -> Result<LanguageServerBinary> {
|
||||||
|
let version = latest_version.downcast::<GitHubLspBinaryVersion>().unwrap();
|
||||||
|
let destination_path =
|
||||||
|
container_dir.join(format!("package-version-server-{}", version.name));
|
||||||
|
let destination_container_path =
|
||||||
|
container_dir.join(format!("package-version-server-{}-tmp", version.name));
|
||||||
|
if fs::metadata(&destination_path).await.is_err() {
|
||||||
|
let mut response = delegate
|
||||||
|
.http_client()
|
||||||
|
.get(&version.url, Default::default(), true)
|
||||||
|
.await
|
||||||
|
.map_err(|err| anyhow!("error downloading release: {}", err))?;
|
||||||
|
if version.url.ends_with(".zip") {
|
||||||
|
node_runtime::extract_zip(
|
||||||
|
&destination_container_path,
|
||||||
|
BufReader::new(response.body_mut()),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
} else if version.url.ends_with(".tar.gz") {
|
||||||
|
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
|
||||||
|
let archive = Archive::new(decompressed_bytes);
|
||||||
|
archive.unpack(&destination_container_path).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::copy(
|
||||||
|
destination_container_path.join("package-version-server"),
|
||||||
|
&destination_path,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
// todo("windows")
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
{
|
||||||
|
fs::set_permissions(
|
||||||
|
&destination_path,
|
||||||
|
<fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
remove_matching(&container_dir, |entry| entry != destination_path).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(LanguageServerBinary {
|
||||||
|
path: destination_path.join("package-version-server"),
|
||||||
|
env: None,
|
||||||
|
arguments: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cached_server_binary(
|
||||||
|
&self,
|
||||||
|
container_dir: PathBuf,
|
||||||
|
_delegate: &dyn LspAdapterDelegate,
|
||||||
|
) -> Option<LanguageServerBinary> {
|
||||||
|
get_cached_version_server_binary(container_dir).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn installation_test_binary(
|
||||||
|
&self,
|
||||||
|
container_dir: PathBuf,
|
||||||
|
) -> Option<LanguageServerBinary> {
|
||||||
|
get_cached_version_server_binary(container_dir)
|
||||||
|
.await
|
||||||
|
.map(|mut binary| {
|
||||||
|
binary.arguments = vec!["--version".into()];
|
||||||
|
binary
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_cached_version_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
|
||||||
|
maybe!(async {
|
||||||
|
let mut last = None;
|
||||||
|
let mut entries = fs::read_dir(&container_dir).await?;
|
||||||
|
while let Some(entry) = entries.next().await {
|
||||||
|
last = Some(entry?.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
anyhow::Ok(LanguageServerBinary {
|
||||||
|
path: last.ok_or_else(|| anyhow!("no cached binary"))?,
|
||||||
|
env: None,
|
||||||
|
arguments: Default::default(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.log_err()
|
||||||
|
}
|
||||||
|
@ -117,10 +117,13 @@ pub fn init(
|
|||||||
|
|
||||||
language!(
|
language!(
|
||||||
"json",
|
"json",
|
||||||
vec![Arc::new(json::JsonLspAdapter::new(
|
vec![
|
||||||
node_runtime.clone(),
|
Arc::new(json::JsonLspAdapter::new(
|
||||||
languages.clone(),
|
node_runtime.clone(),
|
||||||
))],
|
languages.clone(),
|
||||||
|
)),
|
||||||
|
Arc::new(json::NodeVersionAdapter)
|
||||||
|
],
|
||||||
json_task_context()
|
json_task_context()
|
||||||
);
|
);
|
||||||
language!("markdown");
|
language!("markdown");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
mod archive;
|
mod archive;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
|
pub use archive::extract_zip;
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
use futures::AsyncReadExt;
|
use futures::AsyncReadExt;
|
||||||
|
Loading…
Reference in New Issue
Block a user