aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_db/Cargo.toml1
-rw-r--r--crates/ra_db/src/cancelation.rs85
-rw-r--r--crates/ra_db/src/lib.rs18
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs2
5 files changed, 92 insertions, 15 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 51cf1825d..69134b434 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -668,6 +668,7 @@ dependencies = [
668name = "ra_db" 668name = "ra_db"
669version = "0.1.0" 669version = "0.1.0"
670dependencies = [ 670dependencies = [
671 "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
671 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", 672 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
672 "ra_editor 0.1.0", 673 "ra_editor 0.1.0",
673 "ra_syntax 0.1.0", 674 "ra_syntax 0.1.0",
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index f316c0ab2..4be32b5f3 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -5,6 +5,7 @@ version = "0.1.0"
5authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
6 6
7[dependencies] 7[dependencies]
8backtrace = "0.3.1"
8relative-path = "0.4.0" 9relative-path = "0.4.0"
9salsa = "0.8.0" 10salsa = "0.8.0"
10rustc-hash = "1.0" 11rustc-hash = "1.0"
diff --git a/crates/ra_db/src/cancelation.rs b/crates/ra_db/src/cancelation.rs
new file mode 100644
index 000000000..73444b015
--- /dev/null
+++ b/crates/ra_db/src/cancelation.rs
@@ -0,0 +1,85 @@
1//! Utility types to support cancellation.
2//!
3//! In a typical IDE use-case, requests and modification happen concurrently, as
4//! in the following scenario:
5//!
6//! * user types a character,
7//! * a syntax highlighting process is started
8//! * user types next character, while syntax highlighting *is still in
9//! progress*.
10//!
11//! In this situation, we want to react to modification as quckly as possible.
12//! At the same time, in-progress results are not very interesting, because they
13//! are invalidated by the edit anyway. So, we first cancel all in-flight
14//! requests, and then apply modification knowing that it won't intrfere with
15//! any background processing (this bit is handled by salsa, see
16//! `BaseDatabase::check_canceled` method).
17
18use std::{
19 cmp,
20 hash::{Hash, Hasher},
21 sync::Arc,
22};
23
24use backtrace::Backtrace;
25use parking_lot::Mutex;
26
27/// An "error" signifing that the operation was canceled.
28#[derive(Clone)]
29pub struct Canceled {
30 backtrace: Arc<Mutex<Backtrace>>,
31}
32
33pub type Cancelable<T> = Result<T, Canceled>;
34
35impl Canceled {
36 pub(crate) fn new() -> Canceled {
37 let bt = Backtrace::new_unresolved();
38 Canceled {
39 backtrace: Arc::new(Mutex::new(bt)),
40 }
41 }
42}
43
44impl std::fmt::Display for Canceled {
45 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 fmt.write_str("canceled")
47 }
48}
49
50impl std::fmt::Debug for Canceled {
51 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 let mut bt = self.backtrace.lock();
53 let bt: &mut Backtrace = &mut *bt;
54 bt.resolve();
55 write!(fmt, "canceled at:\n{:?}", bt)
56 }
57}
58
59impl std::error::Error for Canceled {}
60
61impl PartialEq for Canceled {
62 fn eq(&self, _: &Canceled) -> bool {
63 true
64 }
65}
66
67impl Eq for Canceled {}
68
69impl Hash for Canceled {
70 fn hash<H: Hasher>(&self, hasher: &mut H) {
71 ().hash(hasher)
72 }
73}
74
75impl cmp::Ord for Canceled {
76 fn cmp(&self, _: &Canceled) -> cmp::Ordering {
77 cmp::Ordering::Equal
78 }
79}
80
81impl cmp::PartialOrd for Canceled {
82 fn partial_cmp(&self, other: &Canceled) -> Option<cmp::Ordering> {
83 Some(self.cmp(other))
84 }
85}
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 78f2cbf12..1f7c9187b 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -1,27 +1,17 @@
1//! ra_db defines basic database traits. Concrete DB is defined by ra_analysis. 1//! ra_db defines basic database traits. Concrete DB is defined by ra_analysis.
2mod cancelation;
2mod syntax_ptr; 3mod syntax_ptr;
3mod input; 4mod input;
4mod loc2id; 5mod loc2id;
5pub mod mock; 6pub mod mock;
6 7
7use std::sync::Arc; 8use std::sync::Arc;
9
8use ra_editor::LineIndex; 10use ra_editor::LineIndex;
9use ra_syntax::{TextUnit, SourceFileNode}; 11use ra_syntax::{TextUnit, SourceFileNode};
10 12
11#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
12pub struct Canceled;
13
14pub type Cancelable<T> = Result<T, Canceled>;
15
16impl std::fmt::Display for Canceled {
17 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 fmt.write_str("canceled")
19 }
20}
21
22impl std::error::Error for Canceled {}
23
24pub use crate::{ 13pub use crate::{
14 cancelation::{Canceled, Cancelable},
25 syntax_ptr::LocalSyntaxPtr, 15 syntax_ptr::LocalSyntaxPtr,
26 input::{ 16 input::{
27 FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, 17 FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph,
@@ -48,7 +38,7 @@ macro_rules! impl_numeric_id {
48pub trait BaseDatabase: salsa::Database { 38pub trait BaseDatabase: salsa::Database {
49 fn check_canceled(&self) -> Cancelable<()> { 39 fn check_canceled(&self) -> Cancelable<()> {
50 if self.salsa_runtime().is_current_revision_canceled() { 40 if self.salsa_runtime().is_current_revision_canceled() {
51 Err(Canceled) 41 Err(Canceled::new())
52 } else { 42 } else {
53 Ok(()) 43 Ok(())
54 } 44 }
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 60f13267c..1edb9fae4 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -427,7 +427,7 @@ impl<'a> PoolDispatcher<'a> {
427 RawResponse::err( 427 RawResponse::err(
428 id, 428 id,
429 ErrorCode::ContentModified as i32, 429 ErrorCode::ContentModified as i32,
430 format!("content modified: {}", e), 430 format!("content modified: {:?}", e),
431 ) 431 )
432 } else { 432 } else {
433 RawResponse::err( 433 RawResponse::err(