crates/language/build.rs 🔗
@@ -0,0 +1,6 @@
+fn main() {
+ if let Ok(bundled) = std::env::var("ZED_BUNDLE") {
+ println!("cargo:rustc-env=ZED_BUNDLE={}", bundled);
+ }
+}
+
Max Brunsfeld and Nathan Sobo created
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
crates/language/build.rs | 6 ++++
crates/language/src/language.rs | 40 ++++++++++++++++++++++++++++
crates/lsp/build.rs | 10 -------
crates/lsp/src/lib.rs | 39 +++++++---------------------
crates/project/src/lib.rs | 20 ++++++++++----
crates/project/src/worktree.rs | 3 -
crates/zed/languages/rust/config.toml | 4 ++
script/download-rust-analyzer | 4 ++
8 files changed, 79 insertions(+), 47 deletions(-)
@@ -0,0 +1,6 @@
+fn main() {
+ if let Ok(bundled) = std::env::var("ZED_BUNDLE") {
+ println!("cargo:rustc-env=ZED_BUNDLE={}", bundled);
+ }
+}
+
@@ -1,5 +1,6 @@
use crate::HighlightMap;
use anyhow::Result;
+use gpui::AppContext;
use parking_lot::Mutex;
use serde::Deserialize;
use std::{path::Path, str, sync::Arc};
@@ -12,6 +13,13 @@ pub struct LanguageConfig {
pub name: String,
pub path_suffixes: Vec<String>,
pub brackets: Vec<BracketPair>,
+ pub language_server: Option<LanguageServerConfig>,
+}
+
+#[derive(Deserialize)]
+pub struct LanguageServerConfig {
+ pub binary: String,
+ pub disk_based_diagnostic_sources: Vec<String>,
}
#[derive(Clone, Debug, Deserialize)]
@@ -51,6 +59,12 @@ impl LanguageRegistry {
}
}
+ pub fn get_language(&self, name: &str) -> Option<&Arc<Language>> {
+ self.languages
+ .iter()
+ .find(|language| language.name() == name)
+ }
+
pub fn select_language(&self, path: impl AsRef<Path>) -> Option<&Arc<Language>> {
let path = path.as_ref();
let filename = path.file_name().and_then(|name| name.to_str());
@@ -97,6 +111,32 @@ impl Language {
self.config.name.as_str()
}
+ pub fn start_server(
+ &self,
+ root_path: &Path,
+ cx: &AppContext,
+ ) -> Result<Option<Arc<lsp::LanguageServer>>> {
+ if let Some(config) = &self.config.language_server {
+ const ZED_BUNDLE: Option<&'static str> = option_env!("ZED_BUNDLE");
+ let binary_path = if ZED_BUNDLE.map_or(Ok(false), |b| b.parse())? {
+ cx.platform()
+ .path_for_resource(Some(&config.binary), None)?
+ } else {
+ Path::new(&config.binary).to_path_buf()
+ };
+ lsp::LanguageServer::new(&binary_path, root_path, cx.background()).map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn disk_based_diagnostic_sources(&self) -> &[String] {
+ self.config
+ .language_server
+ .as_ref()
+ .map_or(&[], |config| &config.disk_based_diagnostic_sources)
+ }
+
pub fn brackets(&self) -> &[BracketPair] {
&self.config.brackets
}
@@ -1,10 +0,0 @@
-use std::env;
-
-fn main() {
- let target = env::var("TARGET").unwrap();
- println!("cargo:rustc-env=ZED_TARGET={}", target);
-
- if let Ok(bundled) = env::var("ZED_BUNDLE") {
- println!("cargo:rustc-env=ZED_BUNDLE={}", bundled);
- }
-}
@@ -1,6 +1,6 @@
use anyhow::{anyhow, Context, Result};
use futures::{io::BufWriter, AsyncRead, AsyncWrite};
-use gpui::{executor, AppContext, Task};
+use gpui::{executor, Task};
use parking_lot::{Mutex, RwLock};
use postage::{barrier, oneshot, prelude::Stream, sink::Sink};
use serde::{Deserialize, Serialize};
@@ -86,47 +86,25 @@ struct Error {
}
impl LanguageServer {
- pub fn rust(root_path: &Path, cx: &AppContext) -> Result<Arc<Self>> {
- const ZED_BUNDLE: Option<&'static str> = option_env!("ZED_BUNDLE");
- const ZED_TARGET: &'static str = env!("ZED_TARGET");
-
- let rust_analyzer_name = format!("rust-analyzer-{}", ZED_TARGET);
- if ZED_BUNDLE.map_or(Ok(false), |b| b.parse())? {
- let rust_analyzer_path = cx
- .platform()
- .path_for_resource(Some(&rust_analyzer_name), None)?;
- Self::new(root_path, &rust_analyzer_path, &[], cx.background())
- } else {
- Self::new(
- root_path,
- Path::new(&rust_analyzer_name),
- &[],
- cx.background(),
- )
- }
- }
-
pub fn new(
+ binary_path: &Path,
root_path: &Path,
- server_path: &Path,
- server_args: &[&str],
background: &executor::Background,
) -> Result<Arc<Self>> {
- let mut server = Command::new(server_path)
- .args(server_args)
+ let mut server = Command::new(binary_path)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()?;
let stdin = server.stdin.take().unwrap();
let stdout = server.stdout.take().unwrap();
- Self::new_internal(root_path, stdin, stdout, background)
+ Self::new_internal(stdin, stdout, root_path, background)
}
fn new_internal<Stdin, Stdout>(
- root_path: &Path,
stdin: Stdin,
stdout: Stdout,
+ root_path: &Path,
background: &executor::Background,
) -> Result<Arc<Self>>
where
@@ -410,7 +388,7 @@ impl LanguageServer {
buffer: Vec::new(),
};
- let server = Self::new_internal(Path::new("/"), stdin.0, stdout.1, executor).unwrap();
+ let server = Self::new_internal(stdin.0, stdout.1, Path::new("/"), executor).unwrap();
let (init_id, _) = fake.receive_request::<request::Initialize>().await;
fake.respond(init_id, InitializeResult::default()).await;
@@ -535,7 +513,10 @@ mod tests {
let lib_file_uri =
lsp_types::Url::from_file_path(root_dir.path().join("src/lib.rs")).unwrap();
- let server = cx.read(|cx| LanguageServer::rust(root_dir.path(), cx).unwrap());
+ let server = cx.read(|cx| {
+ LanguageServer::new(Path::new("rust-analyzer"), root_dir.path(), cx.background())
+ .unwrap()
+ });
server.next_idle_notification().await;
server
@@ -8,12 +8,11 @@ use futures::Future;
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
use language::LanguageRegistry;
-use lsp::LanguageServer;
use std::{
path::Path,
sync::{atomic::AtomicBool, Arc},
};
-use util::TryFutureExt as _;
+use util::{ResultExt, TryFutureExt as _};
pub use fs::*;
pub use worktree::*;
@@ -74,11 +73,20 @@ impl Project {
let rpc = self.client.clone();
let languages = self.languages.clone();
let path = Arc::from(abs_path);
- let language_server = LanguageServer::rust(&path, cx);
+ let language_server = languages
+ .get_language("Rust")
+ .unwrap()
+ .start_server(&path, cx);
cx.spawn(|this, mut cx| async move {
- let worktree =
- Worktree::open_local(rpc, path, fs, languages, Some(language_server?), &mut cx)
- .await?;
+ let worktree = Worktree::open_local(
+ rpc,
+ path,
+ fs,
+ languages,
+ language_server.log_err().flatten(),
+ &mut cx,
+ )
+ .await?;
this.update(&mut cx, |this, cx| {
this.add_worktree(worktree.clone(), cx);
});
@@ -295,7 +295,7 @@ impl Worktree {
}
}
- pub fn language_server(&self) -> Option<&Arc<lsp::LanguageServer>> {
+ pub fn language_server(&self) -> Option<&Arc<LanguageServer>> {
match self {
Worktree::Local(worktree) => worktree.language_server.as_ref(),
Worktree::Remote(_) => None,
@@ -2872,7 +2872,6 @@ mod tests {
use anyhow::Result;
use client::test::FakeServer;
use fs::RealFs;
- use language::Point;
use lsp::Url;
use rand::prelude::*;
use serde_json::json;
@@ -8,3 +8,7 @@ brackets = [
{ start = "\"", end = "\"", close = true, newline = false },
{ start = "/*", end = " */", close = true, newline = false },
]
+
+[language_server]
+binary = "rust-analyzer"
+disk_based_diagnostic_sources = ["rustc"]
@@ -13,3 +13,7 @@ function download {
mkdir -p vendor/bin
download "x86_64-apple-darwin"
download "aarch64-apple-darwin"
+
+cd vendor/bin
+lipo -create rust-analyzer-* -output rust-analyzer
+rm rust-analyzer-*