Many steps toward validating and reinstalling server after failure

This commit is contained in:
Julia 2023-06-12 14:25:45 -04:00
parent ec0409a3d1
commit bca625a197
19 changed files with 347 additions and 155 deletions

View file

@ -203,20 +203,17 @@ impl ActivityIndicator {
}
// Show any language server installation info.
let mut validating = SmallVec::<[_; 3]>::new();
let mut downloading = SmallVec::<[_; 3]>::new();
let mut checking_for_update = SmallVec::<[_; 3]>::new();
let mut failed = SmallVec::<[_; 3]>::new();
for status in &self.statuses {
let name = status.name.clone();
match status.status {
LanguageServerBinaryStatus::CheckingForUpdate => {
checking_for_update.push(status.name.clone());
}
LanguageServerBinaryStatus::Downloading => {
downloading.push(status.name.clone());
}
LanguageServerBinaryStatus::Failed { .. } => {
failed.push(status.name.clone());
}
LanguageServerBinaryStatus::Validating => validating.push(name),
LanguageServerBinaryStatus::CheckingForUpdate => checking_for_update.push(name),
LanguageServerBinaryStatus::Downloading => downloading.push(name),
LanguageServerBinaryStatus::Failed { .. } => failed.push(name),
LanguageServerBinaryStatus::Downloaded | LanguageServerBinaryStatus::Cached => {}
}
}
@ -245,7 +242,7 @@ impl ActivityIndicator {
),
on_click: None,
};
} else if !failed.is_empty() {
} else if !failed.is_empty() || !validating.is_empty() {
return Content {
icon: Some(WARNING_ICON),
message: format!(

View file

@ -15,7 +15,7 @@ use language::{
ToPointUtf16,
};
use log::{debug, error};
use lsp::{LanguageServer, LanguageServerId};
use lsp::{LanguageServer, LanguageServerBinaries, LanguageServerBinary, LanguageServerId};
use node_runtime::NodeRuntime;
use request::{LogMessage, StatusNotification};
use settings::SettingsStore;
@ -361,11 +361,18 @@ impl Copilot {
let start_language_server = async {
let server_path = get_copilot_lsp(http).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(
LanguageServerId(0),
&node_path,
arguments,
binaries,
Path::new("/"),
None,
cx.clone(),

View file

@ -20,7 +20,7 @@ use futures::{
use gpui::{executor::Background, AppContext, Task};
use highlight_map::HighlightMap;
use lazy_static::lazy_static;
use lsp::CodeActionKind;
use lsp::{CodeActionKind, LanguageServer, LanguageServerBinaries, LanguageServerBinary};
use parking_lot::{Mutex, RwLock};
use postage::watch;
use regex::Regex;
@ -30,17 +30,18 @@ use std::{
any::Any,
borrow::Cow,
cell::RefCell,
ffi::OsString,
fmt::Debug,
hash::Hash,
mem,
ops::{Not, Range},
path::{Path, PathBuf},
process::Stdio,
str,
sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc,
},
time::Duration,
};
use syntax_map::SyntaxSnapshot;
use theme::{SyntaxTheme, Theme};
@ -86,12 +87,6 @@ pub trait ToLspPosition {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
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.
/// Uses [`LspAdapter`] under the hood, but calls all 'static' methods
/// once at startup, and caches the results.
@ -148,6 +143,10 @@ impl CachedLspAdapter {
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>> {
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>;
fn installation_test_binary(&self, _container_dir: PathBuf) -> LanguageServerBinary {
unimplemented!();
}
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
@ -485,6 +488,7 @@ struct BracketConfig {
#[derive(Clone)]
pub enum LanguageServerBinaryStatus {
Validating,
CheckingForUpdate,
Downloading,
Downloaded,
@ -515,7 +519,7 @@ pub struct LanguageRegistry {
lsp_binary_paths: Mutex<
HashMap<
LanguageServerName,
Shared<BoxFuture<'static, Result<LanguageServerBinary, Arc<anyhow::Error>>>>,
Shared<BoxFuture<'static, Result<LanguageServerBinaries, Arc<anyhow::Error>>>>,
>,
>,
executor: Option<Arc<Background>>,
@ -891,8 +895,7 @@ impl LanguageRegistry {
let binary = entry.clone().map_err(|e| anyhow!(e)).await?;
let server = lsp::LanguageServer::new(
server_id,
&binary.path,
&binary.arguments,
binary,
&root_path,
adapter.code_action_kinds(),
cx,
@ -909,6 +912,56 @@ impl LanguageRegistry {
) -> async_broadcast::Receiver<(Arc<Language>, LanguageServerBinaryStatus)> {
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 {
@ -961,7 +1014,7 @@ async fn get_binary(
http_client: Arc<dyn HttpClient>,
download_dir: Arc<Path>,
statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
) -> Result<LanguageServerBinary> {
) -> Result<LanguageServerBinaries> {
let container_dir = download_dir.join(adapter.name.0.as_ref());
if !container_dir.exists() {
smol::fs::create_dir_all(&container_dir)
@ -979,11 +1032,15 @@ async fn get_binary(
.await;
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
.broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
.await?;
return Ok(cached);
let installation_test_binary = adapter.installation_test_binary(container_dir).await;
return Ok(LanguageServerBinaries {
binary,
installation_test_binary,
});
} else {
statuses
.broadcast((
@ -995,6 +1052,7 @@ async fn get_binary(
.await?;
}
}
binary
}
@ -1004,7 +1062,7 @@ async fn fetch_latest_binary(
http_client: Arc<dyn HttpClient>,
container_dir: &Path,
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
) -> Result<LanguageServerBinary> {
) -> Result<LanguageServerBinaries> {
let container_dir: Arc<Path> = container_dir.into();
lsp_binary_statuses_tx
.broadcast((
@ -1012,19 +1070,28 @@ async fn fetch_latest_binary(
LanguageServerBinaryStatus::CheckingForUpdate,
))
.await?;
let version_info = adapter
.fetch_latest_server_version(http_client.clone())
.await?;
lsp_binary_statuses_tx
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloading))
.await?;
let binary = adapter
.fetch_server_binary(version_info, http_client, container_dir.to_path_buf())
.await?;
let installation_test_binary = adapter
.installation_test_binary(container_dir.to_path_buf())
.await;
lsp_binary_statuses_tx
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded))
.await?;
Ok(binary)
Ok(LanguageServerBinaries {
binary,
installation_test_binary,
})
}
impl Language {

View file

@ -16,6 +16,7 @@ use smol::{
process::{self, Child},
};
use std::{
ffi::OsString,
fmt,
future::Future,
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 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 {
server_id: LanguageServerId,
next_id: AtomicUsize,
@ -51,7 +64,8 @@ pub struct LanguageServer {
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
output_done_rx: Mutex<Option<barrier::Receiver>>,
root_path: PathBuf,
_server: Option<Child>,
server: Option<Mutex<Child>>,
test_installation_binary: Option<LanguageServerBinary>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -119,10 +133,9 @@ struct Error {
}
impl LanguageServer {
pub fn new<T: AsRef<std::ffi::OsStr>>(
pub fn new(
server_id: LanguageServerId,
binary_path: &Path,
arguments: &[T],
binaries: LanguageServerBinaries,
root_path: &Path,
code_action_kinds: Option<Vec<CodeActionKind>>,
cx: AsyncAppContext,
@ -133,9 +146,9 @@ impl LanguageServer {
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)
.args(arguments)
.args(binaries.binary.arguments)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
@ -149,6 +162,7 @@ impl LanguageServer {
stdin,
stout,
Some(server),
Some(binaries.installation_test_binary),
root_path,
code_action_kinds,
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();
}
@ -176,6 +190,7 @@ impl LanguageServer {
stdin: Stdin,
stdout: Stdout,
server: Option<Child>,
test_installation_binary: Option<LanguageServerBinary>,
root_path: &Path,
code_action_kinds: Option<Vec<CodeActionKind>>,
cx: AsyncAppContext,
@ -229,10 +244,28 @@ impl LanguageServer {
io_tasks: Mutex::new(Some((input_task, output_task))),
output_done_rx: Mutex::new(Some(output_done_rx)),
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>> {
self.code_action_kinds.clone()
}
@ -813,6 +846,7 @@ impl LanguageServer {
stdin_writer,
stdout_reader,
None,
None,
Path::new("/"),
None,
cx.clone(),
@ -824,6 +858,7 @@ impl LanguageServer {
stdout_writer,
stdin_reader,
None,
None,
Path::new("/"),
None,
cx,

View file

@ -45,7 +45,7 @@ use language::{
use log::error;
use lsp::{
DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
DocumentHighlightKind, LanguageServer, LanguageServerId,
DocumentHighlightKind, LanguageServer, LanguageServerId, OneOf,
};
use lsp_command::*;
use postage::watch;
@ -65,6 +65,7 @@ use std::{
num::NonZeroU32,
ops::Range,
path::{Component, Path, PathBuf},
process::Stdio,
rc::Rc,
str,
sync::{
@ -277,6 +278,7 @@ pub enum Event {
}
pub enum LanguageServerState {
Validating(Task<Option<Arc<LanguageServer>>>),
Starting(Task<Option<Arc<LanguageServer>>>),
Running {
language: Arc<Language>,
@ -2447,7 +2449,7 @@ impl Project {
Err(err) => {
log::warn!("Error starting language server {:?}: {}", server_name, err);
// TODO: Prompt installation validity check
// TODO: Prompt installation validity check LSP ERROR
None
}
}
@ -2831,10 +2833,8 @@ impl Project {
let mut root_path = None;
let server = match server_state {
Some(LanguageServerState::Starting(started_language_server)) => {
started_language_server.await
}
Some(LanguageServerState::Validating(task)) => task.await,
Some(LanguageServerState::Starting(task)) => task.await,
Some(LanguageServerState::Running { server, .. }) => Some(server),
None => None,
};
@ -2945,6 +2945,15 @@ impl Project {
.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(
&mut self,
progress: lsp::ProgressParams,
@ -3716,29 +3725,26 @@ impl Project {
tab_size: NonZeroU32,
cx: &mut AsyncAppContext,
) -> Result<Vec<(Range<Anchor>, String)>> {
let text_document =
lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(abs_path).unwrap());
let uri = lsp::Url::from_file_path(abs_path)
.map_err(|_| anyhow!("failed to convert abs path to uri"))?;
let text_document = lsp::TextDocumentIdentifier::new(uri);
let capabilities = &language_server.capabilities();
let lsp_edits = if capabilities
.document_formatting_provider
.as_ref()
.map_or(false, |provider| *provider != lsp::OneOf::Left(false))
{
let formatting_provider = capabilities.document_formatting_provider.as_ref();
let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
let result = if !matches!(formatting_provider, Some(OneOf::Left(false))) {
language_server
.request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
text_document,
options: lsp_command::lsp_formatting_options(tab_size.get()),
work_done_progress_params: Default::default(),
})
.await?
} else if capabilities
.document_range_formatting_provider
.as_ref()
.map_or(false, |provider| *provider != lsp::OneOf::Left(false))
{
.await
} else if !matches!(range_formatting_provider, Some(OneOf::Left(false))) {
let buffer_start = lsp::Position::new(0, 0);
let buffer_end =
buffer.read_with(cx, |buffer, _| point_to_lsp(buffer.max_point_utf16()));
let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
language_server
.request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
text_document,
@ -3746,9 +3752,27 @@ impl Project {
options: lsp_command::lsp_formatting_options(tab_size.get()),
work_done_progress_params: Default::default(),
})
.await?
.await
} else {
None
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
}
};
if let Some(lsp_edits) = lsp_edits {
@ -3757,7 +3781,7 @@ impl Project {
})
.await
} else {
Ok(Default::default())
Ok(Vec::new())
}
}
@ -3865,80 +3889,89 @@ impl Project {
let mut requests = Vec::new();
for ((worktree_id, _), server_id) in self.language_server_ids.iter() {
let worktree_id = *worktree_id;
if let Some(worktree) = self
.worktree_for_id(worktree_id, cx)
.and_then(|worktree| worktree.read(cx).as_local())
{
if let Some(LanguageServerState::Running {
let worktree_handle = self.worktree_for_id(worktree_id, cx);
let worktree = match worktree_handle.and_then(|tree| tree.read(cx).as_local()) {
Some(worktree) => worktree,
None => continue,
};
let worktree_abs_path = worktree.abs_path().clone();
let (adapter, language, server) = match self.language_servers.get(server_id) {
Some(LanguageServerState::Running {
adapter,
language,
server,
..
}) = self.language_servers.get(server_id)
{
let adapter = adapter.clone();
let language = language.clone();
let worktree_abs_path = worktree.abs_path().clone();
requests.push(
server
.request::<lsp::request::WorkspaceSymbolRequest>(
lsp::WorkspaceSymbolParams {
query: query.to_string(),
..Default::default()
},
)
.log_err()
.map(move |response| {
let lsp_symbols = response.flatten().map(|symbol_response| match symbol_response {
lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
flat_responses.into_iter().map(|lsp_symbol| {
(lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
}).collect::<Vec<_>>()
}
lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
nested_responses.into_iter().filter_map(|lsp_symbol| {
let location = match lsp_symbol.location {
lsp::OneOf::Left(location) => location,
lsp::OneOf::Right(_) => {
error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
return None
}
};
Some((lsp_symbol.name, lsp_symbol.kind, location))
}).collect::<Vec<_>>()
}
}).unwrap_or_default();
}) => (adapter.clone(), language.clone(), server),
(
adapter,
language,
worktree_id,
worktree_abs_path,
lsp_symbols,
)
}),
);
}
}
_ => continue,
};
requests.push(
server
.request::<lsp::request::WorkspaceSymbolRequest>(
lsp::WorkspaceSymbolParams {
query: query.to_string(),
..Default::default()
},
)
.map_ok(move |response| {
let lsp_symbols = response.map(|symbol_response| match symbol_response {
lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
flat_responses.into_iter().map(|lsp_symbol| {
(lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
}).collect::<Vec<_>>()
}
lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
nested_responses.into_iter().filter_map(|lsp_symbol| {
let location = match lsp_symbol.location {
OneOf::Left(location) => location,
OneOf::Right(_) => {
error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
return None
}
};
Some((lsp_symbol.name, lsp_symbol.kind, location))
}).collect::<Vec<_>>()
}
}).unwrap_or_default();
(
adapter,
language,
worktree_id,
worktree_abs_path,
lsp_symbols,
)
}),
);
}
cx.spawn_weak(|this, cx| async move {
let responses = futures::future::join_all(requests).await;
let this = if let Some(this) = this.upgrade(&cx) {
this
} else {
return Ok(Default::default());
let this = match this.upgrade(&cx) {
Some(this) => this,
None => return Ok(Vec::new()),
};
let symbols = this.read_with(&cx, |this, cx| {
let mut symbols = Vec::new();
for (
adapter,
adapter_language,
source_worktree_id,
worktree_abs_path,
lsp_symbols,
) in responses
{
for response in responses {
let (
adapter,
adapter_language,
source_worktree_id,
worktree_abs_path,
lsp_symbols,
) = 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(
|(symbol_name, symbol_kind, symbol_location)| {
let abs_path = symbol_location.uri.to_file_path().ok()?;
@ -3985,8 +4018,10 @@ impl Project {
},
));
}
symbols
});
Ok(futures::future::join_all(symbols).await)
})
} else if let Some(project_id) = self.remote_id() {
@ -4111,9 +4146,17 @@ impl Project {
};
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)
.await?;
.await
{
Ok(resolved_completion) => resolved_completion,
Err(err) => {
// TODO: LSP ERROR
return Ok(None);
}
};
if let Some(edits) = resolved_completion.additional_text_edits {
let edits = this
@ -4232,9 +4275,17 @@ impl Project {
.and_then(|d| d.get_mut("range"))
{
*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)
.await?;
.await
{
Ok(lsp_action) => lsp_action,
Err(err) => {
// LSP ERROR
return Err(err);
}
};
} else {
let actions = this
.update(&mut cx, |this, cx| {
@ -4267,13 +4318,20 @@ impl Project {
this.last_workspace_edits_by_language_server
.remove(&lang_server.server_id());
});
lang_server
let result = lang_server
.request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
command: command.command,
arguments: command.arguments.unwrap_or_default(),
..Default::default()
})
.await?;
.await;
if let Err(err) = result {
// TODO: LSP ERROR
return Err(err);
}
return Ok(this.update(&mut cx, |this, _| {
this.last_workspace_edits_by_language_server
.remove(&lang_server.server_id())
@ -4433,7 +4491,7 @@ impl Project {
uri,
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
.update(cx, |this, cx| {
let edits = op.edits.into_iter().map(|edit| match edit {
lsp::OneOf::Left(edit) => edit,
lsp::OneOf::Right(edit) => edit.text_edit,
OneOf::Left(edit) => edit,
OneOf::Right(edit) => edit.text_edit,
});
this.edits_from_lsp(
&buffer_to_edit,
@ -4841,10 +4899,20 @@ impl Project {
return Ok(Default::default());
}
let response = language_server
.request::<R::LspRequest>(lsp_params)
.await
.context("lsp request failed")?;
let result = language_server.request::<R::LspRequest>(lsp_params).await;
let response = match result {
Ok(response) => response,
Err(err) => {
log::warn!(
"Generic lsp request to {} failed: {}",
language_server.name(),
err
);
return Err(err);
}
};
request
.response_from_lsp(
response,
@ -7211,11 +7279,10 @@ impl Entity for Project {
.language_servers
.drain()
.map(|(_, server_state)| async {
use LanguageServerState::*;
match server_state {
LanguageServerState::Running { server, .. } => server.shutdown()?.await,
LanguageServerState::Starting(starting_server) => {
starting_server.await?.shutdown()?.await
}
Running { server, .. } => server.shutdown()?.await,
Starting(task) | Validating(task) => task.await?.shutdown()?.await,
}
})
.collect::<Vec<_>>();

View file

@ -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;
fn log_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
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 {

View file

@ -2,6 +2,7 @@ use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use futures::StreamExt;
pub use language::*;
use lsp::LanguageServerBinary;
use smol::fs::{self, File};
use std::{any::Any, path::PathBuf, sync::Arc};
use util::fs::remove_matching;

View file

@ -2,7 +2,7 @@ use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use futures::StreamExt;
pub use language::*;
use lsp::{CompletionItemKind, SymbolKind};
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
use smol::fs::{self, File};
use std::{any::Any, path::PathBuf, sync::Arc};
use util::fs::remove_matching;

View file

@ -3,6 +3,7 @@ use async_trait::async_trait;
use futures::StreamExt;
pub use language::*;
use lazy_static::lazy_static;
use lsp::LanguageServerBinary;
use regex::Regex;
use smol::{fs, process};
use std::ffi::{OsStr, OsString};

View file

@ -1,7 +1,8 @@
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use futures::StreamExt;
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
use language::{LanguageServerName, LspAdapter};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime;
use serde_json::json;
use smol::fs;

View file

@ -3,7 +3,8 @@ use async_trait::async_trait;
use collections::HashMap;
use futures::{future::BoxFuture, FutureExt, StreamExt};
use gpui::AppContext;
use language::{LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter};
use language::{LanguageRegistry, LanguageServerName, LspAdapter};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime;
use serde_json::json;
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};

View file

@ -3,7 +3,8 @@ use async_trait::async_trait;
use collections::HashMap;
use futures::lock::Mutex;
use gpui::executor::Background;
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
use language::{LanguageServerName, LspAdapter};
use lsp::LanguageServerBinary;
use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn};
use std::{any::Any, path::PathBuf, sync::Arc};
use util::http::HttpClient;

View file

@ -3,7 +3,8 @@ use async_compression::futures::bufread::GzipDecoder;
use async_tar::Archive;
use async_trait::async_trait;
use futures::{io::BufReader, StreamExt};
use language::{LanguageServerBinary, LanguageServerName};
use language::LanguageServerName;
use lsp::LanguageServerBinary;
use smol::fs;
use std::{any::Any, env::consts, ffi::OsString, path::PathBuf, sync::Arc};
use util::{async_iife, github::latest_github_release, http::HttpClient, ResultExt};

View file

@ -1,7 +1,8 @@
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use futures::StreamExt;
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
use language::{LanguageServerName, LspAdapter};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime;
use smol::fs;
use std::{

View file

@ -1,6 +1,7 @@
use anyhow::{anyhow, Result};
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 util::http::HttpClient;

View file

@ -4,6 +4,7 @@ use async_trait::async_trait;
use futures::{io::BufReader, StreamExt};
pub use language::*;
use lazy_static::lazy_static;
use lsp::LanguageServerBinary;
use regex::Regex;
use smol::fs::{self, File};
use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, str, sync::Arc};

View file

@ -4,8 +4,8 @@ use async_tar::Archive;
use async_trait::async_trait;
use futures::{future::BoxFuture, FutureExt};
use gpui::AppContext;
use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
use lsp::CodeActionKind;
use language::{LanguageServerName, LspAdapter};
use lsp::{CodeActionKind, LanguageServerBinary};
use node_runtime::NodeRuntime;
use serde_json::{json, Value};
use smol::{fs, io::BufReader, stream::StreamExt};

View file

@ -2,9 +2,8 @@ use anyhow::{anyhow, Result};
use async_trait::async_trait;
use futures::{future::BoxFuture, FutureExt, StreamExt};
use gpui::AppContext;
use language::{
language_settings::all_language_settings, LanguageServerBinary, LanguageServerName, LspAdapter,
};
use language::{language_settings::all_language_settings, LanguageServerName, LspAdapter};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime;
use serde_json::Value;
use smol::fs;

View file

@ -1,4 +1,5 @@
{
// "noErrorTruncation": true,
"compilerOptions": {
"target": "es2015",
"module": "commonjs",