aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_db/src/cancellation.rs6
-rw-r--r--crates/ra_db/src/lib.rs22
-rw-r--r--crates/ra_db/src/loc2id.rs11
-rw-r--r--crates/ra_hir/src/mock.rs4
-rw-r--r--crates/ra_ide_api/src/db.rs5
-rw-r--r--crates/ra_ide_api/src/lib.rs51
-rw-r--r--crates/ra_ide_api_light/src/extend_selection.rs131
7 files changed, 199 insertions, 31 deletions
diff --git a/crates/ra_db/src/cancellation.rs b/crates/ra_db/src/cancellation.rs
index 8d38eebfb..32a268553 100644
--- a/crates/ra_db/src/cancellation.rs
+++ b/crates/ra_db/src/cancellation.rs
@@ -27,6 +27,12 @@ impl Canceled {
27 pub(crate) fn new() -> Canceled { 27 pub(crate) fn new() -> Canceled {
28 Canceled { _private: () } 28 Canceled { _private: () }
29 } 29 }
30
31 pub fn throw() -> ! {
32 // We use resume and not panic here to avoid running the panic
33 // hook (that is, to avoid collecting and printing backtrace).
34 std::panic::resume_unwind(Box::new(Canceled::new()))
35 }
30} 36}
31 37
32impl std::fmt::Display for Canceled { 38impl std::fmt::Display for Canceled {
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index fb8ea2496..20e712afe 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -5,6 +5,8 @@ mod input;
5mod loc2id; 5mod loc2id;
6pub mod mock; 6pub mod mock;
7 7
8use std::panic;
9
8use ra_syntax::{TextUnit, TextRange, SourceFile, TreePtr}; 10use ra_syntax::{TextUnit, TextRange, SourceFile, TreePtr};
9 11
10pub use crate::{ 12pub use crate::{
@@ -18,13 +20,21 @@ pub use crate::{
18 loc2id::LocationIntener, 20 loc2id::LocationIntener,
19}; 21};
20 22
21pub trait BaseDatabase: salsa::Database { 23pub trait BaseDatabase: salsa::Database + panic::RefUnwindSafe {
22 fn check_canceled(&self) -> Cancelable<()> { 24 fn check_canceled(&self) -> Cancelable<()> {
23 if self.salsa_runtime().is_current_revision_canceled() { 25 self.salsa_runtime()
24 Err(Canceled::new()) 26 .if_current_revision_is_canceled(Canceled::throw);
25 } else { 27 Ok(())
26 Ok(()) 28 }
27 } 29
30 fn catch_canceled<F: FnOnce(&Self) -> T + panic::UnwindSafe, T>(
31 &self,
32 f: F,
33 ) -> Result<T, Canceled> {
34 panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
35 Ok(canceled) => *canceled,
36 Err(payload) => panic::resume_unwind(payload),
37 })
28 } 38 }
29} 39}
30 40
diff --git a/crates/ra_db/src/loc2id.rs b/crates/ra_db/src/loc2id.rs
index 254c52629..359cd893d 100644
--- a/crates/ra_db/src/loc2id.rs
+++ b/crates/ra_db/src/loc2id.rs
@@ -1,4 +1,4 @@
1use std::hash::Hash; 1use std::{panic, hash::Hash};
2 2
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
@@ -70,6 +70,15 @@ where
70 map: Mutex<Loc2IdMap<LOC, ID>>, 70 map: Mutex<Loc2IdMap<LOC, ID>>,
71} 71}
72 72
73impl<LOC, ID> panic::RefUnwindSafe for LocationIntener<LOC, ID>
74where
75 ID: ArenaId + Clone,
76 LOC: Clone + Eq + Hash,
77 ID: panic::RefUnwindSafe,
78 LOC: panic::RefUnwindSafe,
79{
80}
81
73impl<LOC, ID> Default for LocationIntener<LOC, ID> 82impl<LOC, ID> Default for LocationIntener<LOC, ID>
74where 83where
75 ID: ArenaId + Clone, 84 ID: ArenaId + Clone,
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 0fae7de82..7a0301648 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -1,4 +1,4 @@
1use std::sync::Arc; 1use std::{sync::Arc, panic};
2 2
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use salsa::{self, Database}; 4use salsa::{self, Database};
@@ -18,6 +18,8 @@ pub(crate) struct MockDatabase {
18 file_counter: u32, 18 file_counter: u32,
19} 19}
20 20
21impl panic::RefUnwindSafe for MockDatabase {}
22
21impl MockDatabase { 23impl MockDatabase {
22 pub(crate) fn with_files(fixture: &str) -> (MockDatabase, SourceRoot) { 24 pub(crate) fn with_files(fixture: &str) -> (MockDatabase, SourceRoot) {
23 let (db, source_root, position) = MockDatabase::from_fixture(fixture); 25 let (db, source_root, position) = MockDatabase::from_fixture(fixture);
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index 9d46609ec..a2e06f5db 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -1,7 +1,7 @@
1use std::{fmt, sync::Arc}; 1use std::{fmt, sync::Arc};
2 2
3use salsa::{self, Database}; 3use salsa::{self, Database};
4use ra_db::{LocationIntener, BaseDatabase, FileId}; 4use ra_db::{LocationIntener, BaseDatabase, FileId, Canceled};
5 5
6use crate::{symbol_index, LineIndex}; 6use crate::{symbol_index, LineIndex};
7 7
@@ -29,6 +29,9 @@ impl salsa::Database for RootDatabase {
29 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> { 29 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
30 &self.runtime 30 &self.runtime
31 } 31 }
32 fn on_propagated_panic(&self) -> ! {
33 Canceled::throw()
34 }
32} 35}
33 36
34impl Default for RootDatabase { 37impl Default for RootDatabase {
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index fbe1421a4..f505959ce 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -35,7 +35,7 @@ use std::{fmt, sync::Arc};
35 35
36use ra_syntax::{SmolStr, SourceFile, TreePtr, SyntaxKind, TextRange, TextUnit}; 36use ra_syntax::{SmolStr, SourceFile, TreePtr, SyntaxKind, TextRange, TextUnit};
37use ra_text_edit::TextEdit; 37use ra_text_edit::TextEdit;
38use ra_db::{SyntaxDatabase, FilesDatabase, LocalSyntaxPtr}; 38use ra_db::{SyntaxDatabase, FilesDatabase, LocalSyntaxPtr, BaseDatabase};
39use rayon::prelude::*; 39use rayon::prelude::*;
40use relative_path::RelativePathBuf; 40use relative_path::RelativePathBuf;
41use rustc_hash::FxHashMap; 41use rustc_hash::FxHashMap;
@@ -420,43 +420,47 @@ impl Analysis {
420 420
421 /// Fuzzy searches for a symbol. 421 /// Fuzzy searches for a symbol.
422 pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { 422 pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> {
423 let res = symbol_index::world_symbols(&*self.db, query)? 423 self.with_db(|db| {
424 .into_iter() 424 let res = symbol_index::world_symbols(db, query)?
425 .map(NavigationTarget::from_symbol) 425 .into_iter()
426 .collect(); 426 .map(NavigationTarget::from_symbol)
427 Ok(res) 427 .collect::<Vec<_>>();
428 Ok(res)
429 })?
428 } 430 }
429 431
430 pub fn goto_definition( 432 pub fn goto_definition(
431 &self, 433 &self,
432 position: FilePosition, 434 position: FilePosition,
433 ) -> Cancelable<Option<Vec<NavigationTarget>>> { 435 ) -> Cancelable<Option<Vec<NavigationTarget>>> {
434 goto_definition::goto_definition(&*self.db, position) 436 self.db
437 .catch_canceled(|db| goto_definition::goto_definition(db, position))?
435 } 438 }
436 439
437 /// Finds all usages of the reference at point. 440 /// Finds all usages of the reference at point.
438 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 441 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
439 self.db.find_all_refs(position) 442 self.with_db(|db| db.find_all_refs(position))?
440 } 443 }
441 444
442 /// Returns a short text descrbing element at position. 445 /// Returns a short text descrbing element at position.
443 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { 446 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> {
444 hover::hover(&*self.db, position) 447 self.with_db(|db| hover::hover(db, position))?
445 } 448 }
446 449
447 /// Computes parameter information for the given call expression. 450 /// Computes parameter information for the given call expression.
448 pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> { 451 pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> {
449 call_info::call_info(&*self.db, position) 452 self.db
453 .catch_canceled(|db| call_info::call_info(db, position))?
450 } 454 }
451 455
452 /// Returns a `mod name;` declaration which created the current module. 456 /// Returns a `mod name;` declaration which created the current module.
453 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { 457 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
454 self.db.parent_module(position) 458 self.with_db(|db| db.parent_module(position))?
455 } 459 }
456 460
457 /// Returns crates this file belongs too. 461 /// Returns crates this file belongs too.
458 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 462 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
459 self.db.crate_for(file_id) 463 self.with_db(|db| db.crate_for(file_id))?
460 } 464 }
461 465
462 /// Returns the root file of the given crate. 466 /// Returns the root file of the given crate.
@@ -466,17 +470,21 @@ impl Analysis {
466 470
467 /// Returns the set of possible targets to run for the current file. 471 /// Returns the set of possible targets to run for the current file.
468 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { 472 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
469 runnables::runnables(&*self.db, file_id) 473 self.db
474 .catch_canceled(|db| runnables::runnables(db, file_id))?
470 } 475 }
471 476
472 /// Computes syntax highlighting for the given file. 477 /// Computes syntax highlighting for the given file.
473 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { 478 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> {
474 syntax_highlighting::highlight(&*self.db, file_id) 479 self.db
480 .catch_canceled(|db| syntax_highlighting::highlight(db, file_id))?
475 } 481 }
476 482
477 /// Computes completions at the given position. 483 /// Computes completions at the given position.
478 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { 484 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> {
479 let completions = completion::completions(&self.db, position)?; 485 let completions = self
486 .db
487 .catch_canceled(|db| completion::completions(db, position))??;
480 Ok(completions.map(|it| it.into())) 488 Ok(completions.map(|it| it.into()))
481 } 489 }
482 490
@@ -488,12 +496,12 @@ impl Analysis {
488 496
489 /// Computes the set of diagnostics for the given file. 497 /// Computes the set of diagnostics for the given file.
490 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 498 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
491 self.db.diagnostics(file_id) 499 self.with_db(|db| db.diagnostics(file_id))?
492 } 500 }
493 501
494 /// Computes the type of the expression at the given position. 502 /// Computes the type of the expression at the given position.
495 pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { 503 pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> {
496 hover::type_of(&*self.db, frange) 504 self.with_db(|db| hover::type_of(db, frange))?
497 } 505 }
498 506
499 /// Returns the edit required to rename reference at the position to the new 507 /// Returns the edit required to rename reference at the position to the new
@@ -503,7 +511,14 @@ impl Analysis {
503 position: FilePosition, 511 position: FilePosition,
504 new_name: &str, 512 new_name: &str,
505 ) -> Cancelable<Vec<SourceFileEdit>> { 513 ) -> Cancelable<Vec<SourceFileEdit>> {
506 self.db.rename(position, new_name) 514 self.with_db(|db| db.rename(position, new_name))?
515 }
516
517 fn with_db<F: FnOnce(&db::RootDatabase) -> T + std::panic::UnwindSafe, T>(
518 &self,
519 f: F,
520 ) -> Cancelable<T> {
521 self.db.catch_canceled(f)
507 } 522 }
508} 523}
509 524
diff --git a/crates/ra_ide_api_light/src/extend_selection.rs b/crates/ra_ide_api_light/src/extend_selection.rs
index 08cae5a51..db93db208 100644
--- a/crates/ra_ide_api_light/src/extend_selection.rs
+++ b/crates/ra_ide_api_light/src/extend_selection.rs
@@ -6,6 +6,21 @@ use ra_syntax::{
6 6
7pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange> { 7pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange> {
8 let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING]; 8 let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING];
9 let list_kinds = [
10 FIELD_PAT_LIST,
11 MATCH_ARM_LIST,
12 NAMED_FIELD_LIST,
13 NAMED_FIELD_DEF_LIST,
14 POS_FIELD_LIST,
15 ENUM_VARIANT_LIST,
16 USE_TREE_LIST,
17 TYPE_PARAM_LIST,
18 TYPE_ARG_LIST,
19 PARAM_LIST,
20 ARG_LIST,
21 ARRAY_EXPR,
22 ];
23
9 if range.is_empty() { 24 if range.is_empty() {
10 let offset = range.start(); 25 let offset = range.start();
11 let mut leaves = find_leaf_at_offset(root, offset); 26 let mut leaves = find_leaf_at_offset(root, offset);
@@ -26,9 +41,25 @@ pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
26 return Some(leaf_range); 41 return Some(leaf_range);
27 }; 42 };
28 let node = find_covering_node(root, range); 43 let node = find_covering_node(root, range);
29 if string_kinds.contains(&node.kind()) && range == node.range() { 44
30 if let Some(range) = extend_comments(node) { 45 // Using shallowest node with same range allows us to traverse siblings.
31 return Some(range); 46 let node = node
47 .ancestors()
48 .take_while(|n| n.range() == node.range())
49 .last()
50 .unwrap();
51
52 if range == node.range() {
53 if string_kinds.contains(&node.kind()) {
54 if let Some(range) = extend_comments(node) {
55 return Some(range);
56 }
57 }
58
59 if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
60 if let Some(range) = extend_list_item(node) {
61 return Some(range);
62 }
32 } 63 }
33 } 64 }
34 65
@@ -99,6 +130,45 @@ fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode {
99 } 130 }
100} 131}
101 132
133/// Extend list item selection to include nearby comma and whitespace.
134fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
135 fn is_single_line_ws(node: &SyntaxNode) -> bool {
136 node.kind() == WHITESPACE && !node.leaf_text().unwrap().contains('\n')
137 }
138
139 fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<&SyntaxNode> {
140 node.siblings(dir)
141 .skip(1)
142 .skip_while(|node| is_single_line_ws(node))
143 .next()
144 .filter(|node| node.kind() == COMMA)
145 }
146
147 if let Some(comma_node) = nearby_comma(node, Direction::Prev) {
148 return Some(TextRange::from_to(
149 comma_node.range().start(),
150 node.range().end(),
151 ));
152 }
153
154 if let Some(comma_node) = nearby_comma(node, Direction::Next) {
155 // Include any following whitespace when comma if after list item.
156 let final_node = comma_node
157 .siblings(Direction::Next)
158 .skip(1)
159 .next()
160 .filter(|node| is_single_line_ws(node))
161 .unwrap_or(comma_node);
162
163 return Some(TextRange::from_to(
164 node.range().start(),
165 final_node.range().end(),
166 ));
167 }
168
169 return None;
170}
171
102fn extend_comments(node: &SyntaxNode) -> Option<TextRange> { 172fn extend_comments(node: &SyntaxNode) -> Option<TextRange> {
103 let prev = adj_comments(node, Direction::Prev); 173 let prev = adj_comments(node, Direction::Prev);
104 let next = adj_comments(node, Direction::Next); 174 let next = adj_comments(node, Direction::Next);
@@ -145,7 +215,60 @@ mod tests {
145 } 215 }
146 216
147 #[test] 217 #[test]
148 fn test_extend_selection_start_of_the_lind() { 218 fn test_extend_selection_list() {
219 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]);
220 do_check(
221 r#"fn foo(<|>x: i32, y: i32) {}"#,
222 &["x", "x: i32", "x: i32, "],
223 );
224 do_check(
225 r#"fn foo(<|>x: i32,y: i32) {}"#,
226 &["x", "x: i32", "x: i32,"],
227 );
228 do_check(
229 r#"fn foo(x: i32, <|>y: i32) {}"#,
230 &["y", "y: i32", ", y: i32"],
231 );
232 do_check(
233 r#"fn foo(x: i32, <|>y: i32, ) {}"#,
234 &["y", "y: i32", ", y: i32"],
235 );
236 do_check(
237 r#"fn foo(x: i32,<|>y: i32) {}"#,
238 &["y", "y: i32", ",y: i32"],
239 );
240
241 do_check(
242 r#"const FOO: [usize; 2] = [ 22<|> , 33];"#,
243 &["22", "22 , "],
244 );
245 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]);
246 do_check(
247 r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#,
248 &["33", ", 33"],
249 );
250
251 do_check(
252 r#"
253const FOO: [usize; 2] = [
254 22,
255 <|>33,
256]"#,
257 &["33", "33,"],
258 );
259
260 do_check(
261 r#"
262const FOO: [usize; 2] = [
263 22
264 , 33<|>,
265]"#,
266 &["33", ", 33"],
267 );
268 }
269
270 #[test]
271 fn test_extend_selection_start_of_the_line() {
149 do_check( 272 do_check(
150 r#" 273 r#"
151impl S { 274impl S {