Move lsp configuration into language crate
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
de8218314c
commit
7d5425e142
8 changed files with 79 additions and 47 deletions
6
crates/language/build.rs
Normal file
6
crates/language/build.rs
Normal file
|
@ -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 crate::HighlightMap;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use gpui::AppContext;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{path::Path, str, sync::Arc};
|
use std::{path::Path, str, sync::Arc};
|
||||||
|
@ -12,6 +13,13 @@ pub struct LanguageConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub path_suffixes: Vec<String>,
|
pub path_suffixes: Vec<String>,
|
||||||
pub brackets: Vec<BracketPair>,
|
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)]
|
#[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>> {
|
pub fn select_language(&self, path: impl AsRef<Path>) -> Option<&Arc<Language>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let filename = path.file_name().and_then(|name| name.to_str());
|
let filename = path.file_name().and_then(|name| name.to_str());
|
||||||
|
@ -97,6 +111,32 @@ impl Language {
|
||||||
self.config.name.as_str()
|
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] {
|
pub fn brackets(&self) -> &[BracketPair] {
|
||||||
&self.config.brackets
|
&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 anyhow::{anyhow, Context, Result};
|
||||||
use futures::{io::BufWriter, AsyncRead, AsyncWrite};
|
use futures::{io::BufWriter, AsyncRead, AsyncWrite};
|
||||||
use gpui::{executor, AppContext, Task};
|
use gpui::{executor, Task};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use postage::{barrier, oneshot, prelude::Stream, sink::Sink};
|
use postage::{barrier, oneshot, prelude::Stream, sink::Sink};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -86,47 +86,25 @@ struct Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LanguageServer {
|
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(
|
pub fn new(
|
||||||
|
binary_path: &Path,
|
||||||
root_path: &Path,
|
root_path: &Path,
|
||||||
server_path: &Path,
|
|
||||||
server_args: &[&str],
|
|
||||||
background: &executor::Background,
|
background: &executor::Background,
|
||||||
) -> Result<Arc<Self>> {
|
) -> Result<Arc<Self>> {
|
||||||
let mut server = Command::new(server_path)
|
let mut server = Command::new(binary_path)
|
||||||
.args(server_args)
|
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
let stdin = server.stdin.take().unwrap();
|
let stdin = server.stdin.take().unwrap();
|
||||||
let stdout = server.stdout.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>(
|
fn new_internal<Stdin, Stdout>(
|
||||||
root_path: &Path,
|
|
||||||
stdin: Stdin,
|
stdin: Stdin,
|
||||||
stdout: Stdout,
|
stdout: Stdout,
|
||||||
|
root_path: &Path,
|
||||||
background: &executor::Background,
|
background: &executor::Background,
|
||||||
) -> Result<Arc<Self>>
|
) -> Result<Arc<Self>>
|
||||||
where
|
where
|
||||||
|
@ -410,7 +388,7 @@ impl LanguageServer {
|
||||||
buffer: Vec::new(),
|
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;
|
let (init_id, _) = fake.receive_request::<request::Initialize>().await;
|
||||||
fake.respond(init_id, InitializeResult::default()).await;
|
fake.respond(init_id, InitializeResult::default()).await;
|
||||||
|
@ -535,7 +513,10 @@ mod tests {
|
||||||
let lib_file_uri =
|
let lib_file_uri =
|
||||||
lsp_types::Url::from_file_path(root_dir.path().join("src/lib.rs")).unwrap();
|
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.next_idle_notification().await;
|
||||||
|
|
||||||
server
|
server
|
||||||
|
|
|
@ -8,12 +8,11 @@ use futures::Future;
|
||||||
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
|
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
|
||||||
use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
|
use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
use lsp::LanguageServer;
|
|
||||||
use std::{
|
use std::{
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::{atomic::AtomicBool, Arc},
|
sync::{atomic::AtomicBool, Arc},
|
||||||
};
|
};
|
||||||
use util::TryFutureExt as _;
|
use util::{ResultExt, TryFutureExt as _};
|
||||||
|
|
||||||
pub use fs::*;
|
pub use fs::*;
|
||||||
pub use worktree::*;
|
pub use worktree::*;
|
||||||
|
@ -74,11 +73,20 @@ impl Project {
|
||||||
let rpc = self.client.clone();
|
let rpc = self.client.clone();
|
||||||
let languages = self.languages.clone();
|
let languages = self.languages.clone();
|
||||||
let path = Arc::from(abs_path);
|
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 {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let worktree =
|
let worktree = Worktree::open_local(
|
||||||
Worktree::open_local(rpc, path, fs, languages, Some(language_server?), &mut cx)
|
rpc,
|
||||||
.await?;
|
path,
|
||||||
|
fs,
|
||||||
|
languages,
|
||||||
|
language_server.log_err().flatten(),
|
||||||
|
&mut cx,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.add_worktree(worktree.clone(), 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 {
|
match self {
|
||||||
Worktree::Local(worktree) => worktree.language_server.as_ref(),
|
Worktree::Local(worktree) => worktree.language_server.as_ref(),
|
||||||
Worktree::Remote(_) => None,
|
Worktree::Remote(_) => None,
|
||||||
|
@ -2872,7 +2872,6 @@ mod tests {
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use client::test::FakeServer;
|
use client::test::FakeServer;
|
||||||
use fs::RealFs;
|
use fs::RealFs;
|
||||||
use language::Point;
|
|
||||||
use lsp::Url;
|
use lsp::Url;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
|
@ -8,3 +8,7 @@ brackets = [
|
||||||
{ start = "\"", end = "\"", close = true, newline = false },
|
{ start = "\"", end = "\"", close = true, newline = false },
|
||||||
{ 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
|
mkdir -p vendor/bin
|
||||||
download "x86_64-apple-darwin"
|
download "x86_64-apple-darwin"
|
||||||
download "aarch64-apple-darwin"
|
download "aarch64-apple-darwin"
|
||||||
|
|
||||||
|
cd vendor/bin
|
||||||
|
lipo -create rust-analyzer-* -output rust-analyzer
|
||||||
|
rm rust-analyzer-*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue