Many steps toward validating and reinstalling server after failure
This commit is contained in:
parent
ec0409a3d1
commit
bca625a197
19 changed files with 347 additions and 155 deletions
|
@ -203,20 +203,17 @@ impl ActivityIndicator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show any language server installation info.
|
// Show any language server installation info.
|
||||||
|
let mut validating = SmallVec::<[_; 3]>::new();
|
||||||
let mut downloading = SmallVec::<[_; 3]>::new();
|
let mut downloading = SmallVec::<[_; 3]>::new();
|
||||||
let mut checking_for_update = SmallVec::<[_; 3]>::new();
|
let mut checking_for_update = SmallVec::<[_; 3]>::new();
|
||||||
let mut failed = SmallVec::<[_; 3]>::new();
|
let mut failed = SmallVec::<[_; 3]>::new();
|
||||||
for status in &self.statuses {
|
for status in &self.statuses {
|
||||||
|
let name = status.name.clone();
|
||||||
match status.status {
|
match status.status {
|
||||||
LanguageServerBinaryStatus::CheckingForUpdate => {
|
LanguageServerBinaryStatus::Validating => validating.push(name),
|
||||||
checking_for_update.push(status.name.clone());
|
LanguageServerBinaryStatus::CheckingForUpdate => checking_for_update.push(name),
|
||||||
}
|
LanguageServerBinaryStatus::Downloading => downloading.push(name),
|
||||||
LanguageServerBinaryStatus::Downloading => {
|
LanguageServerBinaryStatus::Failed { .. } => failed.push(name),
|
||||||
downloading.push(status.name.clone());
|
|
||||||
}
|
|
||||||
LanguageServerBinaryStatus::Failed { .. } => {
|
|
||||||
failed.push(status.name.clone());
|
|
||||||
}
|
|
||||||
LanguageServerBinaryStatus::Downloaded | LanguageServerBinaryStatus::Cached => {}
|
LanguageServerBinaryStatus::Downloaded | LanguageServerBinaryStatus::Cached => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +242,7 @@ impl ActivityIndicator {
|
||||||
),
|
),
|
||||||
on_click: None,
|
on_click: None,
|
||||||
};
|
};
|
||||||
} else if !failed.is_empty() {
|
} else if !failed.is_empty() || !validating.is_empty() {
|
||||||
return Content {
|
return Content {
|
||||||
icon: Some(WARNING_ICON),
|
icon: Some(WARNING_ICON),
|
||||||
message: format!(
|
message: format!(
|
||||||
|
|
|
@ -15,7 +15,7 @@ use language::{
|
||||||
ToPointUtf16,
|
ToPointUtf16,
|
||||||
};
|
};
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use lsp::{LanguageServer, LanguageServerId};
|
use lsp::{LanguageServer, LanguageServerBinaries, LanguageServerBinary, LanguageServerId};
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use request::{LogMessage, StatusNotification};
|
use request::{LogMessage, StatusNotification};
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
|
@ -361,11 +361,18 @@ impl Copilot {
|
||||||
let start_language_server = async {
|
let start_language_server = async {
|
||||||
let server_path = get_copilot_lsp(http).await?;
|
let server_path = get_copilot_lsp(http).await?;
|
||||||
let node_path = node_runtime.binary_path().await?;
|
let node_path = node_runtime.binary_path().await?;
|
||||||
let arguments: &[OsString] = &[server_path.into(), "--stdio".into()];
|
let arguments: Vec<OsString> = vec![server_path.into(), "--stdio".into()];
|
||||||
|
let binary = LanguageServerBinary {
|
||||||
|
path: node_path,
|
||||||
|
arguments,
|
||||||
|
};
|
||||||
|
let binaries = LanguageServerBinaries {
|
||||||
|
binary: binary.clone(),
|
||||||
|
installation_test_binary: binary,
|
||||||
|
};
|
||||||
let server = LanguageServer::new(
|
let server = LanguageServer::new(
|
||||||
LanguageServerId(0),
|
LanguageServerId(0),
|
||||||
&node_path,
|
binaries,
|
||||||
arguments,
|
|
||||||
Path::new("/"),
|
Path::new("/"),
|
||||||
None,
|
None,
|
||||||
cx.clone(),
|
cx.clone(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ use futures::{
|
||||||
use gpui::{executor::Background, AppContext, Task};
|
use gpui::{executor::Background, AppContext, Task};
|
||||||
use highlight_map::HighlightMap;
|
use highlight_map::HighlightMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use lsp::CodeActionKind;
|
use lsp::{CodeActionKind, LanguageServer, LanguageServerBinaries, LanguageServerBinary};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -30,17 +30,18 @@ use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
ffi::OsString,
|
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
mem,
|
mem,
|
||||||
ops::{Not, Range},
|
ops::{Not, Range},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
process::Stdio,
|
||||||
str,
|
str,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
use syntax_map::SyntaxSnapshot;
|
use syntax_map::SyntaxSnapshot;
|
||||||
use theme::{SyntaxTheme, Theme};
|
use theme::{SyntaxTheme, Theme};
|
||||||
|
@ -86,12 +87,6 @@ pub trait ToLspPosition {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct LanguageServerName(pub Arc<str>);
|
pub struct LanguageServerName(pub Arc<str>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
|
||||||
pub struct LanguageServerBinary {
|
|
||||||
pub path: PathBuf,
|
|
||||||
pub arguments: Vec<OsString>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a Language Server, with certain cached sync properties.
|
/// Represents a Language Server, with certain cached sync properties.
|
||||||
/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
|
/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
|
||||||
/// once at startup, and caches the results.
|
/// once at startup, and caches the results.
|
||||||
|
@ -148,6 +143,10 @@ impl CachedLspAdapter {
|
||||||
self.adapter.cached_server_binary(container_dir).await
|
self.adapter.cached_server_binary(container_dir).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn installation_test_binary(&self, container_dir: PathBuf) -> LanguageServerBinary {
|
||||||
|
self.adapter.installation_test_binary(container_dir)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
||||||
self.adapter.code_action_kinds()
|
self.adapter.code_action_kinds()
|
||||||
}
|
}
|
||||||
|
@ -205,6 +204,10 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
|
|
||||||
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary>;
|
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary>;
|
||||||
|
|
||||||
|
fn installation_test_binary(&self, _container_dir: PathBuf) -> LanguageServerBinary {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
|
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
|
||||||
|
|
||||||
async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
|
async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
|
||||||
|
@ -485,6 +488,7 @@ struct BracketConfig {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum LanguageServerBinaryStatus {
|
pub enum LanguageServerBinaryStatus {
|
||||||
|
Validating,
|
||||||
CheckingForUpdate,
|
CheckingForUpdate,
|
||||||
Downloading,
|
Downloading,
|
||||||
Downloaded,
|
Downloaded,
|
||||||
|
@ -515,7 +519,7 @@ pub struct LanguageRegistry {
|
||||||
lsp_binary_paths: Mutex<
|
lsp_binary_paths: Mutex<
|
||||||
HashMap<
|
HashMap<
|
||||||
LanguageServerName,
|
LanguageServerName,
|
||||||
Shared<BoxFuture<'static, Result<LanguageServerBinary, Arc<anyhow::Error>>>>,
|
Shared<BoxFuture<'static, Result<LanguageServerBinaries, Arc<anyhow::Error>>>>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
executor: Option<Arc<Background>>,
|
executor: Option<Arc<Background>>,
|
||||||
|
@ -891,8 +895,7 @@ impl LanguageRegistry {
|
||||||
let binary = entry.clone().map_err(|e| anyhow!(e)).await?;
|
let binary = entry.clone().map_err(|e| anyhow!(e)).await?;
|
||||||
let server = lsp::LanguageServer::new(
|
let server = lsp::LanguageServer::new(
|
||||||
server_id,
|
server_id,
|
||||||
&binary.path,
|
binary,
|
||||||
&binary.arguments,
|
|
||||||
&root_path,
|
&root_path,
|
||||||
adapter.code_action_kinds(),
|
adapter.code_action_kinds(),
|
||||||
cx,
|
cx,
|
||||||
|
@ -909,6 +912,56 @@ impl LanguageRegistry {
|
||||||
) -> async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)> {
|
) -> async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)> {
|
||||||
self.lsp_binary_statuses_rx.clone()
|
self.lsp_binary_statuses_rx.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn check_errored_lsp_installation(
|
||||||
|
&self,
|
||||||
|
language_server: Arc<LanguageServer>,
|
||||||
|
cx: &mut AppContext,
|
||||||
|
) {
|
||||||
|
// Check if child process is running
|
||||||
|
if !language_server.is_dead() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not, get check binary
|
||||||
|
let test_binary = match language_server.test_installation_binary() {
|
||||||
|
Some(test_binary) => test_binary.clone(),
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run
|
||||||
|
const PROCESS_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
|
let mut timeout = cx.background().timer(PROCESS_TIMEOUT).fuse();
|
||||||
|
|
||||||
|
let mut errored = false;
|
||||||
|
let result = smol::process::Command::new(&test_binary.path)
|
||||||
|
.current_dir(&test_binary.path)
|
||||||
|
.args(test_binary.arguments)
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.kill_on_drop(true)
|
||||||
|
.spawn();
|
||||||
|
|
||||||
|
if let Ok(mut process) = result {
|
||||||
|
futures::select! {
|
||||||
|
_ = process.status().fuse() => {}
|
||||||
|
_ = timeout => errored = true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errored = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(errored);
|
||||||
|
|
||||||
|
// If failure clear container dir
|
||||||
|
|
||||||
|
// Prompt binary retrieval
|
||||||
|
|
||||||
|
// Start language server
|
||||||
|
|
||||||
|
// Update project server state
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LanguageRegistryState {
|
impl LanguageRegistryState {
|
||||||
|
@ -961,7 +1014,7 @@ async fn get_binary(
|
||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
download_dir: Arc<Path>,
|
download_dir: Arc<Path>,
|
||||||
statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
||||||
) -> Result<LanguageServerBinary> {
|
) -> Result<LanguageServerBinaries> {
|
||||||
let container_dir = download_dir.join(adapter.name.0.as_ref());
|
let container_dir = download_dir.join(adapter.name.0.as_ref());
|
||||||
if !container_dir.exists() {
|
if !container_dir.exists() {
|
||||||
smol::fs::create_dir_all(&container_dir)
|
smol::fs::create_dir_all(&container_dir)
|
||||||
|
@ -979,11 +1032,15 @@ async fn get_binary(
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Err(error) = binary.as_ref() {
|
if let Err(error) = binary.as_ref() {
|
||||||
if let Some(cached) = adapter.cached_server_binary(container_dir).await {
|
if let Some(binary) = adapter.cached_server_binary(container_dir.clone()).await {
|
||||||
statuses
|
statuses
|
||||||
.broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
|
.broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(cached);
|
let installation_test_binary = adapter.installation_test_binary(container_dir).await;
|
||||||
|
return Ok(LanguageServerBinaries {
|
||||||
|
binary,
|
||||||
|
installation_test_binary,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
statuses
|
statuses
|
||||||
.broadcast((
|
.broadcast((
|
||||||
|
@ -995,6 +1052,7 @@ async fn get_binary(
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binary
|
binary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,7 +1062,7 @@ async fn fetch_latest_binary(
|
||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
container_dir: &Path,
|
container_dir: &Path,
|
||||||
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
|
||||||
) -> Result<LanguageServerBinary> {
|
) -> Result<LanguageServerBinaries> {
|
||||||
let container_dir: Arc<Path> = container_dir.into();
|
let container_dir: Arc<Path> = container_dir.into();
|
||||||
lsp_binary_statuses_tx
|
lsp_binary_statuses_tx
|
||||||
.broadcast((
|
.broadcast((
|
||||||
|
@ -1012,19 +1070,28 @@ async fn fetch_latest_binary(
|
||||||
LanguageServerBinaryStatus::CheckingForUpdate,
|
LanguageServerBinaryStatus::CheckingForUpdate,
|
||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let version_info = adapter
|
let version_info = adapter
|
||||||
.fetch_latest_server_version(http_client.clone())
|
.fetch_latest_server_version(http_client.clone())
|
||||||
.await?;
|
.await?;
|
||||||
lsp_binary_statuses_tx
|
lsp_binary_statuses_tx
|
||||||
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloading))
|
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloading))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let binary = adapter
|
let binary = adapter
|
||||||
.fetch_server_binary(version_info, http_client, container_dir.to_path_buf())
|
.fetch_server_binary(version_info, http_client, container_dir.to_path_buf())
|
||||||
.await?;
|
.await?;
|
||||||
|
let installation_test_binary = adapter
|
||||||
|
.installation_test_binary(container_dir.to_path_buf())
|
||||||
|
.await;
|
||||||
lsp_binary_statuses_tx
|
lsp_binary_statuses_tx
|
||||||
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded))
|
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded))
|
||||||
.await?;
|
.await?;
|
||||||
Ok(binary)
|
|
||||||
|
Ok(LanguageServerBinaries {
|
||||||
|
binary,
|
||||||
|
installation_test_binary,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Language {
|
impl Language {
|
||||||
|
|
|
@ -16,6 +16,7 @@ use smol::{
|
||||||
process::{self, Child},
|
process::{self, Child},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
ffi::OsString,
|
||||||
fmt,
|
fmt,
|
||||||
future::Future,
|
future::Future,
|
||||||
io::Write,
|
io::Write,
|
||||||
|
@ -36,6 +37,18 @@ type NotificationHandler = Box<dyn Send + FnMut(Option<usize>, &str, AsyncAppCon
|
||||||
type ResponseHandler = Box<dyn Send + FnOnce(Result<&str, Error>)>;
|
type ResponseHandler = Box<dyn Send + FnOnce(Result<&str, Error>)>;
|
||||||
type IoHandler = Box<dyn Send + FnMut(bool, &str)>;
|
type IoHandler = Box<dyn Send + FnMut(bool, &str)>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct LanguageServerBinary {
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub arguments: Vec<OsString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct LanguageServerBinaries {
|
||||||
|
pub binary: LanguageServerBinary,
|
||||||
|
pub installation_test_binary: LanguageServerBinary,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct LanguageServer {
|
pub struct LanguageServer {
|
||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
next_id: AtomicUsize,
|
next_id: AtomicUsize,
|
||||||
|
@ -51,7 +64,8 @@ pub struct LanguageServer {
|
||||||
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
|
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
|
||||||
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
||||||
root_path: PathBuf,
|
root_path: PathBuf,
|
||||||
_server: Option<Child>,
|
server: Option<Mutex<Child>>,
|
||||||
|
test_installation_binary: Option<LanguageServerBinary>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -119,10 +133,9 @@ struct Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LanguageServer {
|
impl LanguageServer {
|
||||||
pub fn new<T: AsRef<std::ffi::OsStr>>(
|
pub fn new(
|
||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
binary_path: &Path,
|
binaries: LanguageServerBinaries,
|
||||||
arguments: &[T],
|
|
||||||
root_path: &Path,
|
root_path: &Path,
|
||||||
code_action_kinds: Option<Vec<CodeActionKind>>,
|
code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
|
@ -133,9 +146,9 @@ impl LanguageServer {
|
||||||
root_path.parent().unwrap_or_else(|| Path::new("/"))
|
root_path.parent().unwrap_or_else(|| Path::new("/"))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut server = process::Command::new(binary_path)
|
let mut server = process::Command::new(&binaries.binary.path)
|
||||||
.current_dir(working_dir)
|
.current_dir(working_dir)
|
||||||
.args(arguments)
|
.args(binaries.binary.arguments)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
|
@ -149,6 +162,7 @@ impl LanguageServer {
|
||||||
stdin,
|
stdin,
|
||||||
stout,
|
stout,
|
||||||
Some(server),
|
Some(server),
|
||||||
|
Some(binaries.installation_test_binary),
|
||||||
root_path,
|
root_path,
|
||||||
code_action_kinds,
|
code_action_kinds,
|
||||||
cx,
|
cx,
|
||||||
|
@ -164,7 +178,7 @@ impl LanguageServer {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(name) = binary_path.file_name() {
|
if let Some(name) = binaries.binary.path.file_name() {
|
||||||
server.name = name.to_string_lossy().to_string();
|
server.name = name.to_string_lossy().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +190,7 @@ impl LanguageServer {
|
||||||
stdin: Stdin,
|
stdin: Stdin,
|
||||||
stdout: Stdout,
|
stdout: Stdout,
|
||||||
server: Option<Child>,
|
server: Option<Child>,
|
||||||
|
test_installation_binary: Option<LanguageServerBinary>,
|
||||||
root_path: &Path,
|
root_path: &Path,
|
||||||
code_action_kinds: Option<Vec<CodeActionKind>>,
|
code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
|
@ -229,10 +244,28 @@ impl LanguageServer {
|
||||||
io_tasks: Mutex::new(Some((input_task, output_task))),
|
io_tasks: Mutex::new(Some((input_task, output_task))),
|
||||||
output_done_rx: Mutex::new(Some(output_done_rx)),
|
output_done_rx: Mutex::new(Some(output_done_rx)),
|
||||||
root_path: root_path.to_path_buf(),
|
root_path: root_path.to_path_buf(),
|
||||||
_server: server,
|
server: server.map(|server| Mutex::new(server)),
|
||||||
|
test_installation_binary,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_dead(&self) -> bool {
|
||||||
|
let server = match self.server.as_ref() {
|
||||||
|
Some(server) => server,
|
||||||
|
None => return false, // Fake server for tests
|
||||||
|
};
|
||||||
|
|
||||||
|
match server.lock().try_status() {
|
||||||
|
Ok(Some(_)) => true,
|
||||||
|
Ok(None) => false,
|
||||||
|
Err(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test_installation_binary(&self) -> &Option<LanguageServerBinary> {
|
||||||
|
&self.test_installation_binary
|
||||||
|
}
|
||||||
|
|
||||||
pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
|
||||||
self.code_action_kinds.clone()
|
self.code_action_kinds.clone()
|
||||||
}
|
}
|
||||||
|
@ -813,6 +846,7 @@ impl LanguageServer {
|
||||||
stdin_writer,
|
stdin_writer,
|
||||||
stdout_reader,
|
stdout_reader,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
Path::new("/"),
|
Path::new("/"),
|
||||||
None,
|
None,
|
||||||
cx.clone(),
|
cx.clone(),
|
||||||
|
@ -824,6 +858,7 @@ impl LanguageServer {
|
||||||
stdout_writer,
|
stdout_writer,
|
||||||
stdin_reader,
|
stdin_reader,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
Path::new("/"),
|
Path::new("/"),
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -45,7 +45,7 @@ use language::{
|
||||||
use log::error;
|
use log::error;
|
||||||
use lsp::{
|
use lsp::{
|
||||||
DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
|
DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
|
||||||
DocumentHighlightKind, LanguageServer, LanguageServerId,
|
DocumentHighlightKind, LanguageServer, LanguageServerId, OneOf,
|
||||||
};
|
};
|
||||||
use lsp_command::*;
|
use lsp_command::*;
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
|
@ -65,6 +65,7 @@ use std::{
|
||||||
num::NonZeroU32,
|
num::NonZeroU32,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
path::{Component, Path, PathBuf},
|
path::{Component, Path, PathBuf},
|
||||||
|
process::Stdio,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
str,
|
str,
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -277,6 +278,7 @@ pub enum Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LanguageServerState {
|
pub enum LanguageServerState {
|
||||||
|
Validating(Task<Option<Arc<LanguageServer>>>),
|
||||||
Starting(Task<Option<Arc<LanguageServer>>>),
|
Starting(Task<Option<Arc<LanguageServer>>>),
|
||||||
Running {
|
Running {
|
||||||
language: Arc<Language>,
|
language: Arc<Language>,
|
||||||
|
@ -2447,7 +2449,7 @@ impl Project {
|
||||||
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("Error starting language server {:?}: {}", server_name, err);
|
log::warn!("Error starting language server {:?}: {}", server_name, err);
|
||||||
// TODO: Prompt installation validity check
|
// TODO: Prompt installation validity check LSP ERROR
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2831,10 +2833,8 @@ impl Project {
|
||||||
let mut root_path = None;
|
let mut root_path = None;
|
||||||
|
|
||||||
let server = match server_state {
|
let server = match server_state {
|
||||||
Some(LanguageServerState::Starting(started_language_server)) => {
|
Some(LanguageServerState::Validating(task)) => task.await,
|
||||||
started_language_server.await
|
Some(LanguageServerState::Starting(task)) => task.await,
|
||||||
}
|
|
||||||
|
|
||||||
Some(LanguageServerState::Running { server, .. }) => Some(server),
|
Some(LanguageServerState::Running { server, .. }) => Some(server),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
@ -2945,6 +2945,15 @@ impl Project {
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_errored_lsp_installation(
|
||||||
|
&self,
|
||||||
|
language_server: Arc<LanguageServer>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
self.languages
|
||||||
|
.check_errored_lsp_installation(language_server, cx);
|
||||||
|
}
|
||||||
|
|
||||||
fn on_lsp_progress(
|
fn on_lsp_progress(
|
||||||
&mut self,
|
&mut self,
|
||||||
progress: lsp::ProgressParams,
|
progress: lsp::ProgressParams,
|
||||||
|
@ -3716,29 +3725,26 @@ impl Project {
|
||||||
tab_size: NonZeroU32,
|
tab_size: NonZeroU32,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<Vec<(Range<Anchor>, String)>> {
|
) -> Result<Vec<(Range<Anchor>, String)>> {
|
||||||
let text_document =
|
let uri = lsp::Url::from_file_path(abs_path)
|
||||||
lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(abs_path).unwrap());
|
.map_err(|_| anyhow!("failed to convert abs path to uri"))?;
|
||||||
|
let text_document = lsp::TextDocumentIdentifier::new(uri);
|
||||||
let capabilities = &language_server.capabilities();
|
let capabilities = &language_server.capabilities();
|
||||||
let lsp_edits = if capabilities
|
|
||||||
.document_formatting_provider
|
let formatting_provider = capabilities.document_formatting_provider.as_ref();
|
||||||
.as_ref()
|
let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
|
||||||
.map_or(false, |provider| *provider != lsp::OneOf::Left(false))
|
|
||||||
{
|
let result = if !matches!(formatting_provider, Some(OneOf::Left(false))) {
|
||||||
language_server
|
language_server
|
||||||
.request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
|
.request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
|
||||||
text_document,
|
text_document,
|
||||||
options: lsp_command::lsp_formatting_options(tab_size.get()),
|
options: lsp_command::lsp_formatting_options(tab_size.get()),
|
||||||
work_done_progress_params: Default::default(),
|
work_done_progress_params: Default::default(),
|
||||||
})
|
})
|
||||||
.await?
|
.await
|
||||||
} else if capabilities
|
} else if !matches!(range_formatting_provider, Some(OneOf::Left(false))) {
|
||||||
.document_range_formatting_provider
|
|
||||||
.as_ref()
|
|
||||||
.map_or(false, |provider| *provider != lsp::OneOf::Left(false))
|
|
||||||
{
|
|
||||||
let buffer_start = lsp::Position::new(0, 0);
|
let buffer_start = lsp::Position::new(0, 0);
|
||||||
let buffer_end =
|
let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
|
||||||
buffer.read_with(cx, |buffer, _| point_to_lsp(buffer.max_point_utf16()));
|
|
||||||
language_server
|
language_server
|
||||||
.request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
|
.request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
|
||||||
text_document,
|
text_document,
|
||||||
|
@ -3746,9 +3752,27 @@ impl Project {
|
||||||
options: lsp_command::lsp_formatting_options(tab_size.get()),
|
options: lsp_command::lsp_formatting_options(tab_size.get()),
|
||||||
work_done_progress_params: Default::default(),
|
work_done_progress_params: Default::default(),
|
||||||
})
|
})
|
||||||
.await?
|
.await
|
||||||
} else {
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let lsp_edits = match result {
|
||||||
|
Ok(lsp_edits) => lsp_edits,
|
||||||
|
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!(
|
||||||
|
"Error firing format request to {}: {}",
|
||||||
|
language_server.name(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.check_errored_lsp_installation(language_server.clone(), cx);
|
||||||
|
});
|
||||||
|
|
||||||
None
|
None
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(lsp_edits) = lsp_edits {
|
if let Some(lsp_edits) = lsp_edits {
|
||||||
|
@ -3757,7 +3781,7 @@ impl Project {
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
Ok(Default::default())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3865,20 +3889,24 @@ impl Project {
|
||||||
let mut requests = Vec::new();
|
let mut requests = Vec::new();
|
||||||
for ((worktree_id, _), server_id) in self.language_server_ids.iter() {
|
for ((worktree_id, _), server_id) in self.language_server_ids.iter() {
|
||||||
let worktree_id = *worktree_id;
|
let worktree_id = *worktree_id;
|
||||||
if let Some(worktree) = self
|
let worktree_handle = self.worktree_for_id(worktree_id, cx);
|
||||||
.worktree_for_id(worktree_id, cx)
|
let worktree = match worktree_handle.and_then(|tree| tree.read(cx).as_local()) {
|
||||||
.and_then(|worktree| worktree.read(cx).as_local())
|
Some(worktree) => worktree,
|
||||||
{
|
None => continue,
|
||||||
if let Some(LanguageServerState::Running {
|
};
|
||||||
|
let worktree_abs_path = worktree.abs_path().clone();
|
||||||
|
|
||||||
|
let (adapter, language, server) = match self.language_servers.get(server_id) {
|
||||||
|
Some(LanguageServerState::Running {
|
||||||
adapter,
|
adapter,
|
||||||
language,
|
language,
|
||||||
server,
|
server,
|
||||||
..
|
..
|
||||||
}) = self.language_servers.get(server_id)
|
}) => (adapter.clone(), language.clone(), server),
|
||||||
{
|
|
||||||
let adapter = adapter.clone();
|
_ => continue,
|
||||||
let language = language.clone();
|
};
|
||||||
let worktree_abs_path = worktree.abs_path().clone();
|
|
||||||
requests.push(
|
requests.push(
|
||||||
server
|
server
|
||||||
.request::<lsp::request::WorkspaceSymbolRequest>(
|
.request::<lsp::request::WorkspaceSymbolRequest>(
|
||||||
|
@ -3887,9 +3915,8 @@ impl Project {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.log_err()
|
.map_ok(move |response| {
|
||||||
.map(move |response| {
|
let lsp_symbols = response.map(|symbol_response| match symbol_response {
|
||||||
let lsp_symbols = response.flatten().map(|symbol_response| match symbol_response {
|
|
||||||
lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
|
lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
|
||||||
flat_responses.into_iter().map(|lsp_symbol| {
|
flat_responses.into_iter().map(|lsp_symbol| {
|
||||||
(lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
|
(lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
|
||||||
|
@ -3898,8 +3925,8 @@ impl Project {
|
||||||
lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
|
lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
|
||||||
nested_responses.into_iter().filter_map(|lsp_symbol| {
|
nested_responses.into_iter().filter_map(|lsp_symbol| {
|
||||||
let location = match lsp_symbol.location {
|
let location = match lsp_symbol.location {
|
||||||
lsp::OneOf::Left(location) => location,
|
OneOf::Left(location) => location,
|
||||||
lsp::OneOf::Right(_) => {
|
OneOf::Right(_) => {
|
||||||
error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
|
error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
|
@ -3919,26 +3946,32 @@ impl Project {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.spawn_weak(|this, cx| async move {
|
cx.spawn_weak(|this, cx| async move {
|
||||||
let responses = futures::future::join_all(requests).await;
|
let responses = futures::future::join_all(requests).await;
|
||||||
let this = if let Some(this) = this.upgrade(&cx) {
|
let this = match this.upgrade(&cx) {
|
||||||
this
|
Some(this) => this,
|
||||||
} else {
|
None => return Ok(Vec::new()),
|
||||||
return Ok(Default::default());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let symbols = this.read_with(&cx, |this, cx| {
|
let symbols = this.read_with(&cx, |this, cx| {
|
||||||
let mut symbols = Vec::new();
|
let mut symbols = Vec::new();
|
||||||
for (
|
for response in responses {
|
||||||
|
let (
|
||||||
adapter,
|
adapter,
|
||||||
adapter_language,
|
adapter_language,
|
||||||
source_worktree_id,
|
source_worktree_id,
|
||||||
worktree_abs_path,
|
worktree_abs_path,
|
||||||
lsp_symbols,
|
lsp_symbols,
|
||||||
) in responses
|
) = match response {
|
||||||
{
|
Ok(response) => response,
|
||||||
|
|
||||||
|
Err(err) => {
|
||||||
|
// TODO: Prompt installation validity check LSP ERROR
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
symbols.extend(lsp_symbols.into_iter().filter_map(
|
symbols.extend(lsp_symbols.into_iter().filter_map(
|
||||||
|(symbol_name, symbol_kind, symbol_location)| {
|
|(symbol_name, symbol_kind, symbol_location)| {
|
||||||
let abs_path = symbol_location.uri.to_file_path().ok()?;
|
let abs_path = symbol_location.uri.to_file_path().ok()?;
|
||||||
|
@ -3985,8 +4018,10 @@ impl Project {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
symbols
|
symbols
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(futures::future::join_all(symbols).await)
|
Ok(futures::future::join_all(symbols).await)
|
||||||
})
|
})
|
||||||
} else if let Some(project_id) = self.remote_id() {
|
} else if let Some(project_id) = self.remote_id() {
|
||||||
|
@ -4111,9 +4146,17 @@ impl Project {
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let resolved_completion = lang_server
|
let resolved_completion = match lang_server
|
||||||
.request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
|
.request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
|
||||||
.await?;
|
.await
|
||||||
|
{
|
||||||
|
Ok(resolved_completion) => resolved_completion,
|
||||||
|
|
||||||
|
Err(err) => {
|
||||||
|
// TODO: LSP ERROR
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(edits) = resolved_completion.additional_text_edits {
|
if let Some(edits) = resolved_completion.additional_text_edits {
|
||||||
let edits = this
|
let edits = this
|
||||||
|
@ -4232,9 +4275,17 @@ impl Project {
|
||||||
.and_then(|d| d.get_mut("range"))
|
.and_then(|d| d.get_mut("range"))
|
||||||
{
|
{
|
||||||
*lsp_range = serde_json::to_value(&range_to_lsp(range)).unwrap();
|
*lsp_range = serde_json::to_value(&range_to_lsp(range)).unwrap();
|
||||||
action.lsp_action = lang_server
|
action.lsp_action = match lang_server
|
||||||
.request::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
|
.request::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
|
||||||
.await?;
|
.await
|
||||||
|
{
|
||||||
|
Ok(lsp_action) => lsp_action,
|
||||||
|
|
||||||
|
Err(err) => {
|
||||||
|
// LSP ERROR
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
let actions = this
|
let actions = this
|
||||||
.update(&mut cx, |this, cx| {
|
.update(&mut cx, |this, cx| {
|
||||||
|
@ -4267,13 +4318,20 @@ impl Project {
|
||||||
this.last_workspace_edits_by_language_server
|
this.last_workspace_edits_by_language_server
|
||||||
.remove(&lang_server.server_id());
|
.remove(&lang_server.server_id());
|
||||||
});
|
});
|
||||||
lang_server
|
|
||||||
|
let result = lang_server
|
||||||
.request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
|
.request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
|
||||||
command: command.command,
|
command: command.command,
|
||||||
arguments: command.arguments.unwrap_or_default(),
|
arguments: command.arguments.unwrap_or_default(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await?;
|
.await;
|
||||||
|
|
||||||
|
if let Err(err) = result {
|
||||||
|
// TODO: LSP ERROR
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(this.update(&mut cx, |this, _| {
|
return Ok(this.update(&mut cx, |this, _| {
|
||||||
this.last_workspace_edits_by_language_server
|
this.last_workspace_edits_by_language_server
|
||||||
.remove(&lang_server.server_id())
|
.remove(&lang_server.server_id())
|
||||||
|
@ -4433,7 +4491,7 @@ impl Project {
|
||||||
uri,
|
uri,
|
||||||
version: None,
|
version: None,
|
||||||
},
|
},
|
||||||
edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
|
edits: edits.into_iter().map(OneOf::Left).collect(),
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -4503,8 +4561,8 @@ impl Project {
|
||||||
let edits = this
|
let edits = this
|
||||||
.update(cx, |this, cx| {
|
.update(cx, |this, cx| {
|
||||||
let edits = op.edits.into_iter().map(|edit| match edit {
|
let edits = op.edits.into_iter().map(|edit| match edit {
|
||||||
lsp::OneOf::Left(edit) => edit,
|
OneOf::Left(edit) => edit,
|
||||||
lsp::OneOf::Right(edit) => edit.text_edit,
|
OneOf::Right(edit) => edit.text_edit,
|
||||||
});
|
});
|
||||||
this.edits_from_lsp(
|
this.edits_from_lsp(
|
||||||
&buffer_to_edit,
|
&buffer_to_edit,
|
||||||
|
@ -4841,10 +4899,20 @@ impl Project {
|
||||||
return Ok(Default::default());
|
return Ok(Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = language_server
|
let result = language_server.request::<R::LspRequest>(lsp_params).await;
|
||||||
.request::<R::LspRequest>(lsp_params)
|
let response = match result {
|
||||||
.await
|
Ok(response) => response,
|
||||||
.context("lsp request failed")?;
|
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!(
|
||||||
|
"Generic lsp request to {} failed: {}",
|
||||||
|
language_server.name(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
request
|
request
|
||||||
.response_from_lsp(
|
.response_from_lsp(
|
||||||
response,
|
response,
|
||||||
|
@ -7211,11 +7279,10 @@ impl Entity for Project {
|
||||||
.language_servers
|
.language_servers
|
||||||
.drain()
|
.drain()
|
||||||
.map(|(_, server_state)| async {
|
.map(|(_, server_state)| async {
|
||||||
|
use LanguageServerState::*;
|
||||||
match server_state {
|
match server_state {
|
||||||
LanguageServerState::Running { server, .. } => server.shutdown()?.await,
|
Running { server, .. } => server.shutdown()?.await,
|
||||||
LanguageServerState::Starting(starting_server) => {
|
Starting(task) | Validating(task) => task.await?.shutdown()?.await,
|
||||||
starting_server.await?.shutdown()?.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
|
@ -118,14 +118,15 @@ pub fn merge_non_null_json_value_into(source: serde_json::Value, target: &mut se
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ResultExt {
|
pub trait ResultExt<E> {
|
||||||
type Ok;
|
type Ok;
|
||||||
|
|
||||||
fn log_err(self) -> Option<Self::Ok>;
|
fn log_err(self) -> Option<Self::Ok>;
|
||||||
fn warn_on_err(self) -> Option<Self::Ok>;
|
fn warn_on_err(self) -> Option<Self::Ok>;
|
||||||
|
fn inspect_error(self, func: impl FnOnce(&E)) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E> ResultExt for Result<T, E>
|
impl<T, E> ResultExt<E> for Result<T, E>
|
||||||
where
|
where
|
||||||
E: std::fmt::Debug,
|
E: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
|
@ -152,6 +153,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect_err
|
||||||
|
fn inspect_error(self, func: impl FnOnce(&E)) -> Self {
|
||||||
|
if let Err(err) = &self {
|
||||||
|
func(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TryFutureExt {
|
pub trait TryFutureExt {
|
||||||
|
|
|
@ -2,6 +2,7 @@ use anyhow::{anyhow, Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
pub use language::*;
|
pub use language::*;
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use smol::fs::{self, File};
|
use smol::fs::{self, File};
|
||||||
use std::{any::Any, path::PathBuf, sync::Arc};
|
use std::{any::Any, path::PathBuf, sync::Arc};
|
||||||
use util::fs::remove_matching;
|
use util::fs::remove_matching;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{anyhow, Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
pub use language::*;
|
pub use language::*;
|
||||||
use lsp::{CompletionItemKind, SymbolKind};
|
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
|
||||||
use smol::fs::{self, File};
|
use smol::fs::{self, File};
|
||||||
use std::{any::Any, path::PathBuf, sync::Arc};
|
use std::{any::Any, path::PathBuf, sync::Arc};
|
||||||
use util::fs::remove_matching;
|
use util::fs::remove_matching;
|
||||||
|
|
|
@ -3,6 +3,7 @@ use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
pub use language::*;
|
pub use language::*;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use smol::{fs, process};
|
use smol::{fs, process};
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
|
use language::{LanguageServerName, LspAdapter};
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use smol::fs;
|
use smol::fs;
|
||||||
|
|
|
@ -3,7 +3,8 @@ use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::{future::BoxFuture, FutureExt, StreamExt};
|
use futures::{future::BoxFuture, FutureExt, StreamExt};
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use language::{LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter};
|
use language::{LanguageRegistry, LanguageServerName, LspAdapter};
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
|
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
|
||||||
|
|
|
@ -3,7 +3,8 @@ use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use gpui::executor::Background;
|
use gpui::executor::Background;
|
||||||
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
|
use language::{LanguageServerName, LspAdapter};
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn};
|
use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn};
|
||||||
use std::{any::Any, path::PathBuf, sync::Arc};
|
use std::{any::Any, path::PathBuf, sync::Arc};
|
||||||
use util::http::HttpClient;
|
use util::http::HttpClient;
|
||||||
|
|
|
@ -3,7 +3,8 @@ use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{io::BufReader, StreamExt};
|
use futures::{io::BufReader, StreamExt};
|
||||||
use language::{LanguageServerBinary, LanguageServerName};
|
use language::LanguageServerName;
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use smol::fs;
|
use smol::fs;
|
||||||
use std::{any::Any, env::consts, ffi::OsString, path::PathBuf, sync::Arc};
|
use std::{any::Any, env::consts, ffi::OsString, path::PathBuf, sync::Arc};
|
||||||
use util::{async_iife, github::latest_github_release, http::HttpClient, ResultExt};
|
use util::{async_iife, github::latest_github_release, http::HttpClient, ResultExt};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
|
use language::{LanguageServerName, LspAdapter};
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use smol::fs;
|
use smol::fs;
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
|
use language::{LanguageServerName, LspAdapter};
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use std::{any::Any, path::PathBuf, sync::Arc};
|
use std::{any::Any, path::PathBuf, sync::Arc};
|
||||||
use util::http::HttpClient;
|
use util::http::HttpClient;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use async_trait::async_trait;
|
||||||
use futures::{io::BufReader, StreamExt};
|
use futures::{io::BufReader, StreamExt};
|
||||||
pub use language::*;
|
pub use language::*;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use lsp::LanguageServerBinary;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use smol::fs::{self, File};
|
use smol::fs::{self, File};
|
||||||
use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, str, sync::Arc};
|
use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, str, sync::Arc};
|
||||||
|
|
|
@ -4,8 +4,8 @@ use async_tar::Archive;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{future::BoxFuture, FutureExt};
|
use futures::{future::BoxFuture, FutureExt};
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
|
use language::{LanguageServerName, LspAdapter};
|
||||||
use lsp::CodeActionKind;
|
use lsp::{CodeActionKind, LanguageServerBinary};
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use smol::{fs, io::BufReader, stream::StreamExt};
|
use smol::{fs, io::BufReader, stream::StreamExt};
|
||||||
|
|
|
@ -2,9 +2,8 @@ use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{future::BoxFuture, FutureExt, StreamExt};
|
use futures::{future::BoxFuture, FutureExt, StreamExt};
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use language::{
|
use language::{language_settings::all_language_settings, LanguageServerName, LspAdapter};
|
||||||
language_settings::all_language_settings, LanguageServerBinary, LanguageServerName, LspAdapter,
|
use lsp::LanguageServerBinary;
|
||||||
};
|
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use smol::fs;
|
use smol::fs;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
// "noErrorTruncation": true,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2015",
|
"target": "es2015",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue