//! Utilities for LSP-related boilerplate code.
use std::{error::Error, ops::Range, sync::Arc};
-use ide_db::base_db::Canceled;
+use ide_db::base_db::Cancelled;
use lsp_server::Notification;
use crate::{
from_proto,
global_state::GlobalState,
line_index::{LineEndings, LineIndex, OffsetEncoding},
+ LspError,
};
-pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool {
- e.downcast_ref::<Canceled>().is_some()
+pub(crate) fn invalid_params_error(message: String) -> LspError {
+ LspError { code: lsp_server::ErrorCode::InvalidParams as i32, message }
+}
+
+pub(crate) fn is_cancelled(e: &(dyn Error + 'static)) -> bool {
+ e.downcast_ref::<Cancelled>().is_some()
}
pub(crate) fn notification_is<N: lsp_types::notification::Notification>(
)
}
+ /// rust-analyzer is resilient -- if it fails, this doesn't usually affect
+ /// the user experience. Part of that is that we deliberately hide panics
+ /// from the user.
+ ///
+ /// We do however want to pester rust-analyzer developers with panics and
+ /// other "you really gotta fix that" messages. The current strategy is to
+ /// be noisy for "from source" builds or when profiling is enabled.
+ ///
+ /// It's unclear if making from source `cargo xtask install` builds more
+ /// panicky is a good idea, let's see if we can keep our awesome bleeding
+ /// edge users from being upset!
+ pub(crate) fn poke_rust_analyzer_developer(&mut self, message: String) {
+ let from_source_build = env!("REV").contains("dev");
+ let profiling_enabled = std::env::var("RA_PROFILE").is_ok();
+ if from_source_build || profiling_enabled {
+ self.show_message(lsp_types::MessageType::ERROR, message)
+ }
+ }
+
pub(crate) fn report_progress(
&mut self,
title: &str,
return;
}
let percentage = fraction.map(|f| {
- assert!(0.0 <= f && f <= 1.0);
+ assert!((0.0..=1.0).contains(&f));
(f * 100.0) as u32
});
let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title));
match change.range {
Some(range) => {
if !index_valid.covers(range.end.line) {
- line_index.index = Arc::new(ide::LineIndex::new(&old_text));
+ line_index.index = Arc::new(ide::LineIndex::new(old_text));
}
index_valid = IndexValid::UpToLineExclusive(range.start.line);
- let range = from_proto::text_range(&line_index, range);
- old_text.replace_range(Range::<usize>::from(range), &change.text);
+ if let Ok(range) = from_proto::text_range(&line_index, range) {
+ old_text.replace_range(Range::<usize>::from(range), &change.text);
+ }
}
None => {
*old_text = change.text;