diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/gen_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/lang_item.rs | 102 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 22 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_path.rs | 25 | ||||
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/caps.rs | 3 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 47 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/req.rs | 22 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 14 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 2 |
18 files changed, 269 insertions, 23 deletions
diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml index 9e0d819d0..34343e2f2 100644 --- a/crates/gen_lsp_server/Cargo.toml +++ b/crates/gen_lsp_server/Cargo.toml | |||
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" | |||
8 | description = "Generic LSP server scaffold." | 8 | description = "Generic LSP server scaffold." |
9 | 9 | ||
10 | [dependencies] | 10 | [dependencies] |
11 | lsp-types = "0.56.0" | 11 | lsp-types = "0.57.0" |
12 | log = "0.4.3" | 12 | log = "0.4.3" |
13 | failure = "0.1.4" | 13 | failure = "0.1.4" |
14 | serde_json = "1.0.34" | 14 | serde_json = "1.0.34" |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 18627bbc2..8af0a3176 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile, ast}; | 3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile, SmolStr, ast}; |
4 | use ra_db::{SourceDatabase, salsa}; | 4 | use ra_db::{SourceDatabase, salsa}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
@@ -16,6 +16,7 @@ use crate::{ | |||
16 | generics::{GenericParams, GenericDef}, | 16 | generics::{GenericParams, GenericDef}, |
17 | type_ref::TypeRef, | 17 | type_ref::TypeRef, |
18 | traits::TraitData, Trait, ty::TraitRef, | 18 | traits::TraitData, Trait, ty::TraitRef, |
19 | lang_item::{LangItems, LangItemTarget}, | ||
19 | ids | 20 | ids |
20 | }; | 21 | }; |
21 | 22 | ||
@@ -100,6 +101,12 @@ pub trait DefDatabase: SourceDatabase { | |||
100 | 101 | ||
101 | #[salsa::invoke(crate::ConstSignature::static_signature_query)] | 102 | #[salsa::invoke(crate::ConstSignature::static_signature_query)] |
102 | fn static_signature(&self, konst: Static) -> Arc<ConstSignature>; | 103 | fn static_signature(&self, konst: Static) -> Arc<ConstSignature>; |
104 | |||
105 | #[salsa::invoke(crate::lang_item::LangItems::lang_items_query)] | ||
106 | fn lang_items(&self, krate: Crate) -> Arc<LangItems>; | ||
107 | |||
108 | #[salsa::invoke(crate::lang_item::LangItems::lang_item_query)] | ||
109 | fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>; | ||
103 | } | 110 | } |
104 | 111 | ||
105 | #[salsa::query_group(HirDatabaseStorage)] | 112 | #[salsa::query_group(HirDatabaseStorage)] |
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs new file mode 100644 index 000000000..5f3f91cba --- /dev/null +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -0,0 +1,102 @@ | |||
1 | use std::sync::Arc; | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use ra_syntax::{SmolStr, ast::AttrsOwner}; | ||
5 | |||
6 | use crate::{ | ||
7 | Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, Static, Struct, Trait | ||
8 | }; | ||
9 | |||
10 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
11 | pub enum LangItemTarget { | ||
12 | Enum(Enum), | ||
13 | Function(Function), | ||
14 | ImplBlock(ImplBlock), | ||
15 | Static(Static), | ||
16 | Struct(Struct), | ||
17 | Trait(Trait), | ||
18 | } | ||
19 | |||
20 | impl LangItemTarget { | ||
21 | pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | ||
22 | match self { | ||
23 | LangItemTarget::Enum(e) => e.module(db).krate(db), | ||
24 | LangItemTarget::Function(f) => f.module(db).krate(db), | ||
25 | LangItemTarget::ImplBlock(i) => i.module().krate(db), | ||
26 | LangItemTarget::Static(s) => s.module(db).krate(db), | ||
27 | LangItemTarget::Struct(s) => s.module(db).krate(db), | ||
28 | LangItemTarget::Trait(t) => t.module(db).krate(db), | ||
29 | } | ||
30 | } | ||
31 | } | ||
32 | |||
33 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
34 | pub struct LangItems { | ||
35 | items: FxHashMap<SmolStr, LangItemTarget>, | ||
36 | } | ||
37 | |||
38 | impl LangItems { | ||
39 | pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> { | ||
40 | self.items.get(item) | ||
41 | } | ||
42 | |||
43 | /// Salsa query. This will look for lang items in a specific crate. | ||
44 | pub(crate) fn lang_items_query(db: &impl DefDatabase, krate: Crate) -> Arc<LangItems> { | ||
45 | let mut lang_items = LangItems { items: FxHashMap::default() }; | ||
46 | |||
47 | if let Some(module) = krate.root_module(db) { | ||
48 | lang_items.collect_lang_items_recursive(db, &module); | ||
49 | } | ||
50 | |||
51 | Arc::new(lang_items) | ||
52 | } | ||
53 | |||
54 | /// Salsa query. Look for a lang item, starting from the specified crate and recursively | ||
55 | /// traversing its dependencies. | ||
56 | pub(crate) fn lang_item_query( | ||
57 | db: &impl DefDatabase, | ||
58 | start_crate: Crate, | ||
59 | item: SmolStr, | ||
60 | ) -> Option<LangItemTarget> { | ||
61 | let lang_items = db.lang_items(start_crate); | ||
62 | let start_crate_target = lang_items.items.get(&item); | ||
63 | if let Some(target) = start_crate_target { | ||
64 | Some(*target) | ||
65 | } else { | ||
66 | for dep in start_crate.dependencies(db) { | ||
67 | let dep_crate = dep.krate; | ||
68 | let dep_target = db.lang_item(dep_crate, item.clone()); | ||
69 | if dep_target.is_some() { | ||
70 | return dep_target; | ||
71 | } | ||
72 | } | ||
73 | None | ||
74 | } | ||
75 | } | ||
76 | |||
77 | fn collect_lang_items_recursive(&mut self, db: &impl DefDatabase, module: &Module) { | ||
78 | // Look for impl targets | ||
79 | let (impl_blocks, source_map) = db.impls_in_module_with_source_map(module.clone()); | ||
80 | let source = module.definition_source(db).1; | ||
81 | for (impl_id, _) in impl_blocks.impls.iter() { | ||
82 | let impl_block = source_map.get(&source, impl_id); | ||
83 | let lang_item_name = impl_block | ||
84 | .attrs() | ||
85 | .filter_map(|a| a.as_key_value()) | ||
86 | .filter(|(key, _)| key == "lang") | ||
87 | .map(|(_, val)| val) | ||
88 | .nth(0); | ||
89 | if let Some(lang_item_name) = lang_item_name { | ||
90 | let imp = ImplBlock::from_id(*module, impl_id); | ||
91 | self.items.entry(lang_item_name).or_insert(LangItemTarget::ImplBlock(imp)); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // FIXME we should look for the other lang item targets (traits, structs, ...) | ||
96 | |||
97 | // Look for lang items in the children | ||
98 | for child in module.children(db) { | ||
99 | self.collect_lang_items_recursive(db, &child); | ||
100 | } | ||
101 | } | ||
102 | } | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 9292de1b5..4411715de 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -36,6 +36,7 @@ mod type_ref; | |||
36 | mod ty; | 36 | mod ty; |
37 | mod impl_block; | 37 | mod impl_block; |
38 | mod expr; | 38 | mod expr; |
39 | mod lang_item; | ||
39 | mod generics; | 40 | mod generics; |
40 | mod docs; | 41 | mod docs; |
41 | mod resolve; | 42 | mod resolve; |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 0eddfab12..39152360c 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -202,6 +202,10 @@ impl CrateDefMap { | |||
202 | Arc::new(def_map) | 202 | Arc::new(def_map) |
203 | } | 203 | } |
204 | 204 | ||
205 | pub(crate) fn krate(&self) -> Crate { | ||
206 | self.krate | ||
207 | } | ||
208 | |||
205 | pub(crate) fn root(&self) -> CrateModuleId { | 209 | pub(crate) fn root(&self) -> CrateModuleId { |
206 | self.root | 210 | self.root |
207 | } | 211 | } |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 685f4b8b1..f2c85eb66 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -5,13 +5,15 @@ use rustc_hash::FxHashMap; | |||
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | ModuleDef, | 7 | ModuleDef, |
8 | code_model_api::Crate, | ||
8 | db::HirDatabase, | 9 | db::HirDatabase, |
9 | name::{Name, KnownName}, | 10 | name::{Name, KnownName}, |
10 | nameres::{PerNs, CrateDefMap, CrateModuleId}, | 11 | nameres::{PerNs, CrateDefMap, CrateModuleId}, |
11 | generics::GenericParams, | 12 | generics::GenericParams, |
12 | expr::{scope::{ExprScopes, ScopeId}, PatId}, | 13 | expr::{scope::{ExprScopes, ScopeId}, PatId}, |
13 | impl_block::ImplBlock, | 14 | impl_block::ImplBlock, |
14 | path::Path, Trait | 15 | path::Path, |
16 | Trait | ||
15 | }; | 17 | }; |
16 | 18 | ||
17 | #[derive(Debug, Clone, Default)] | 19 | #[derive(Debug, Clone, Default)] |
@@ -197,6 +199,10 @@ impl Resolver { | |||
197 | _ => None, | 199 | _ => None, |
198 | }) | 200 | }) |
199 | } | 201 | } |
202 | |||
203 | pub(crate) fn krate(&self) -> Option<Crate> { | ||
204 | self.module().map(|t| t.0.krate()) | ||
205 | } | ||
200 | } | 206 | } |
201 | 207 | ||
202 | impl Resolver { | 208 | impl Resolver { |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 7ca1ff595..c7772a7f6 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -462,6 +462,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
462 | let remaining_index = remaining_index.unwrap_or(path.segments.len()); | 462 | let remaining_index = remaining_index.unwrap_or(path.segments.len()); |
463 | let mut actual_def_ty: Option<Ty> = None; | 463 | let mut actual_def_ty: Option<Ty> = None; |
464 | 464 | ||
465 | let krate = resolver.krate()?; | ||
465 | // resolve intermediate segments | 466 | // resolve intermediate segments |
466 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { | 467 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { |
467 | let ty = match resolved { | 468 | let ty = match resolved { |
@@ -500,9 +501,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
500 | // Attempt to find an impl_item for the type which has a name matching | 501 | // Attempt to find an impl_item for the type which has a name matching |
501 | // the current segment | 502 | // the current segment |
502 | log::debug!("looking for path segment: {:?}", segment); | 503 | log::debug!("looking for path segment: {:?}", segment); |
504 | |||
503 | actual_def_ty = Some(ty.clone()); | 505 | actual_def_ty = Some(ty.clone()); |
504 | 506 | ||
505 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { | 507 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, krate, |item| { |
506 | let matching_def: Option<crate::ModuleDef> = match item { | 508 | let matching_def: Option<crate::ModuleDef> = match item { |
507 | crate::ImplItem::Method(func) => { | 509 | crate::ImplItem::Method(func) => { |
508 | let sig = func.signature(self.db); | 510 | let sig = func.signature(self.db); |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 667b66095..ea6e0dc0f 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -14,6 +14,7 @@ use crate::{ | |||
14 | resolve::Resolver, | 14 | resolve::Resolver, |
15 | traits::TraitItem, | 15 | traits::TraitItem, |
16 | generics::HasGenericParams, | 16 | generics::HasGenericParams, |
17 | ty::primitive::{UncertainIntTy, UncertainFloatTy} | ||
17 | }; | 18 | }; |
18 | use super::{TraitRef, Substs}; | 19 | use super::{TraitRef, Substs}; |
19 | 20 | ||
@@ -110,10 +111,19 @@ impl CrateImplBlocks { | |||
110 | } | 111 | } |
111 | } | 112 | } |
112 | 113 | ||
113 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | 114 | fn def_crate(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<Crate> { |
114 | match ty { | 115 | match ty { |
115 | Ty::Apply(a_ty) => match a_ty.ctor { | 116 | Ty::Apply(a_ty) => match a_ty.ctor { |
116 | TypeCtor::Adt(def_id) => def_id.krate(db), | 117 | TypeCtor::Adt(def_id) => def_id.krate(db), |
118 | TypeCtor::Bool => db.lang_item(cur_crate, "bool".into())?.krate(db), | ||
119 | TypeCtor::Char => db.lang_item(cur_crate, "char".into())?.krate(db), | ||
120 | TypeCtor::Float(UncertainFloatTy::Known(f)) => { | ||
121 | db.lang_item(cur_crate, f.ty_to_string().into())?.krate(db) | ||
122 | } | ||
123 | TypeCtor::Int(UncertainIntTy::Known(i)) => { | ||
124 | db.lang_item(cur_crate, i.ty_to_string().into())?.krate(db) | ||
125 | } | ||
126 | TypeCtor::Str => db.lang_item(cur_crate, "str".into())?.krate(db), | ||
117 | _ => None, | 127 | _ => None, |
118 | }, | 128 | }, |
119 | _ => None, | 129 | _ => None, |
@@ -150,8 +160,11 @@ impl Ty { | |||
150 | // find in the end takes &self, we still do the autoderef step (just as | 160 | // find in the end takes &self, we still do the autoderef step (just as |
151 | // rustc does an autoderef and then autoref again). | 161 | // rustc does an autoderef and then autoref again). |
152 | 162 | ||
163 | let krate = resolver.krate()?; | ||
153 | for derefed_ty in self.autoderef(db) { | 164 | for derefed_ty in self.autoderef(db) { |
154 | if let Some(result) = derefed_ty.iterate_inherent_methods(db, name, &mut callback) { | 165 | if let Some(result) = |
166 | derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback) | ||
167 | { | ||
155 | return Some(result); | 168 | return Some(result); |
156 | } | 169 | } |
157 | if let Some(result) = | 170 | if let Some(result) = |
@@ -208,9 +221,10 @@ impl Ty { | |||
208 | &self, | 221 | &self, |
209 | db: &impl HirDatabase, | 222 | db: &impl HirDatabase, |
210 | name: Option<&Name>, | 223 | name: Option<&Name>, |
224 | krate: Crate, | ||
211 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 225 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
212 | ) -> Option<T> { | 226 | ) -> Option<T> { |
213 | let krate = match def_crate(db, self) { | 227 | let krate = match def_crate(db, krate, self) { |
214 | Some(krate) => krate, | 228 | Some(krate) => krate, |
215 | None => return None, | 229 | None => return None, |
216 | }; | 230 | }; |
@@ -239,9 +253,10 @@ impl Ty { | |||
239 | pub fn iterate_impl_items<T>( | 253 | pub fn iterate_impl_items<T>( |
240 | self, | 254 | self, |
241 | db: &impl HirDatabase, | 255 | db: &impl HirDatabase, |
256 | krate: Crate, | ||
242 | mut callback: impl FnMut(ImplItem) -> Option<T>, | 257 | mut callback: impl FnMut(ImplItem) -> Option<T>, |
243 | ) -> Option<T> { | 258 | ) -> Option<T> { |
244 | let krate = def_crate(db, &self)?; | 259 | let krate = def_crate(db, krate, &self)?; |
245 | let impls = db.impls_in_crate(krate); | 260 | let impls = db.impls_in_crate(krate); |
246 | 261 | ||
247 | for impl_block in impls.lookup_impl_blocks(&self) { | 262 | for impl_block in impls.lookup_impl_blocks(&self) { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 8d8a0eaaa..86f18b487 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -627,6 +627,28 @@ fn test(a: A) { | |||
627 | } | 627 | } |
628 | 628 | ||
629 | #[test] | 629 | #[test] |
630 | fn infer_inherent_method_str() { | ||
631 | assert_snapshot_matches!( | ||
632 | infer(r#" | ||
633 | #[lang = "str"] | ||
634 | impl str { | ||
635 | fn foo(&self) -> i32 {} | ||
636 | } | ||
637 | |||
638 | fn test() { | ||
639 | "foo".foo(); | ||
640 | } | ||
641 | "#), | ||
642 | @r###" | ||
643 | [40; 44) 'self': &str | ||
644 | [53; 55) '{}': () | ||
645 | [69; 89) '{ ...o(); }': () | ||
646 | [75; 80) '"foo"': &str | ||
647 | [75; 86) '"foo".foo()': i32"### | ||
648 | ); | ||
649 | } | ||
650 | |||
651 | #[test] | ||
630 | fn infer_tuple() { | 652 | fn infer_tuple() { |
631 | assert_snapshot_matches!( | 653 | assert_snapshot_matches!( |
632 | infer(r#" | 654 | infer(r#" |
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index bc03a7095..c41752ae7 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
@@ -38,19 +38,22 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
38 | } | 38 | } |
39 | hir::ModuleDef::Struct(s) => { | 39 | hir::ModuleDef::Struct(s) => { |
40 | let ty = s.ty(ctx.db); | 40 | let ty = s.ty(ctx.db); |
41 | ty.iterate_impl_items(ctx.db, |item| { | 41 | let krate = ctx.module.and_then(|m| m.krate(ctx.db)); |
42 | match item { | 42 | if let Some(krate) = krate { |
43 | hir::ImplItem::Method(func) => { | 43 | ty.iterate_impl_items(ctx.db, krate, |item| { |
44 | let sig = func.signature(ctx.db); | 44 | match item { |
45 | if !sig.has_self_param() { | 45 | hir::ImplItem::Method(func) => { |
46 | acc.add_function(ctx, func); | 46 | let sig = func.signature(ctx.db); |
47 | if !sig.has_self_param() { | ||
48 | acc.add_function(ctx, func); | ||
49 | } | ||
47 | } | 50 | } |
51 | hir::ImplItem::Const(ct) => acc.add_const(ctx, ct), | ||
52 | hir::ImplItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
48 | } | 53 | } |
49 | hir::ImplItem::Const(ct) => acc.add_const(ctx, ct), | 54 | None::<()> |
50 | hir::ImplItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | 55 | }); |
51 | } | 56 | } |
52 | None::<()> | ||
53 | }); | ||
54 | } | 57 | } |
55 | _ => return, | 58 | _ => return, |
56 | }; | 59 | }; |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index bc181e4eb..c855d6f68 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -15,7 +15,7 @@ crossbeam-channel = "0.3.5" | |||
15 | flexi_logger = "0.11.0" | 15 | flexi_logger = "0.11.0" |
16 | log = "0.4.3" | 16 | log = "0.4.3" |
17 | url_serde = "0.2.0" | 17 | url_serde = "0.2.0" |
18 | lsp-types = "0.56.0" | 18 | lsp-types = "0.57.0" |
19 | rustc-hash = "1.0" | 19 | rustc-hash = "1.0" |
20 | parking_lot = "0.7.0" | 20 | parking_lot = "0.7.0" |
21 | 21 | ||
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index 2af2b89fe..f6d2b75e7 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs | |||
@@ -2,7 +2,7 @@ use lsp_types::{ | |||
2 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, | 2 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, |
3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, | 3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, |
4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, | 4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, |
5 | TextDocumentSyncOptions, ImplementationProviderCapability, | 5 | TextDocumentSyncOptions, ImplementationProviderCapability, GenericCapability, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | pub fn server_capabilities() -> ServerCapabilities { | 8 | pub fn server_capabilities() -> ServerCapabilities { |
@@ -37,6 +37,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
37 | first_trigger_character: "=".to_string(), | 37 | first_trigger_character: "=".to_string(), |
38 | more_trigger_character: Some(vec![".".to_string()]), | 38 | more_trigger_character: Some(vec![".".to_string()]), |
39 | }), | 39 | }), |
40 | selection_range_provider: Some(GenericCapability::default()), | ||
40 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), | 41 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), |
41 | rename_provider: Some(RenameProviderCapability::Options(RenameOptions { | 42 | rename_provider: Some(RenameProviderCapability::Options(RenameOptions { |
42 | prepare_provider: Some(true), | 43 | prepare_provider: Some(true), |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 07ac4917a..dc1f8f3f7 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -297,6 +297,7 @@ fn on_request( | |||
297 | .on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)? | 297 | .on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)? |
298 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? | 298 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? |
299 | .on::<req::ExtendSelection>(handlers::handle_extend_selection)? | 299 | .on::<req::ExtendSelection>(handlers::handle_extend_selection)? |
300 | .on::<req::SelectionRangeRequest>(handlers::handle_selection_range)? | ||
300 | .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)? | 301 | .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)? |
301 | .on::<req::JoinLines>(handlers::handle_join_lines)? | 302 | .on::<req::JoinLines>(handlers::handle_join_lines)? |
302 | .on::<req::OnEnter>(handlers::handle_on_enter)? | 303 | .on::<req::OnEnter>(handlers::handle_on_enter)? |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index eb8a53545..530081494 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -11,7 +11,7 @@ use ra_ide_api::{ | |||
11 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable, | 11 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable, |
12 | AssistId, | 12 | AssistId, |
13 | }; | 13 | }; |
14 | use ra_syntax::{AstNode, SyntaxKind, TextUnit}; | 14 | use ra_syntax::{AstNode, SyntaxKind, TextUnit, TextRange}; |
15 | use ra_prof::profile; | 15 | use ra_prof::profile; |
16 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
17 | use serde::{Serialize, Deserialize}; | 17 | use serde::{Serialize, Deserialize}; |
@@ -39,10 +39,15 @@ pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> | |||
39 | Ok(res) | 39 | Ok(res) |
40 | } | 40 | } |
41 | 41 | ||
42 | // FIXME: drop this API | ||
42 | pub fn handle_extend_selection( | 43 | pub fn handle_extend_selection( |
43 | world: ServerWorld, | 44 | world: ServerWorld, |
44 | params: req::ExtendSelectionParams, | 45 | params: req::ExtendSelectionParams, |
45 | ) -> Result<req::ExtendSelectionResult> { | 46 | ) -> Result<req::ExtendSelectionResult> { |
47 | log::error!( | ||
48 | "extend selection is deprecated and will be removed soon, | ||
49 | use the new selection range API in LSP", | ||
50 | ); | ||
46 | let file_id = params.text_document.try_conv_with(&world)?; | 51 | let file_id = params.text_document.try_conv_with(&world)?; |
47 | let line_index = world.analysis().file_line_index(file_id); | 52 | let line_index = world.analysis().file_line_index(file_id); |
48 | let selections = params | 53 | let selections = params |
@@ -55,6 +60,46 @@ pub fn handle_extend_selection( | |||
55 | Ok(req::ExtendSelectionResult { selections }) | 60 | Ok(req::ExtendSelectionResult { selections }) |
56 | } | 61 | } |
57 | 62 | ||
63 | pub fn handle_selection_range( | ||
64 | world: ServerWorld, | ||
65 | params: req::SelectionRangeParams, | ||
66 | ) -> Result<Vec<req::SelectionRange>> { | ||
67 | let file_id = params.text_document.try_conv_with(&world)?; | ||
68 | let line_index = world.analysis().file_line_index(file_id); | ||
69 | params | ||
70 | .positions | ||
71 | .into_iter() | ||
72 | .map_conv_with(&line_index) | ||
73 | .map(|position| { | ||
74 | let mut ranges = Vec::new(); | ||
75 | { | ||
76 | let mut range = TextRange::from_to(position, position); | ||
77 | loop { | ||
78 | ranges.push(range); | ||
79 | let frange = FileRange { file_id, range }; | ||
80 | let next = world.analysis().extend_selection(frange)?; | ||
81 | if next == range { | ||
82 | break; | ||
83 | } else { | ||
84 | range = next | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | let mut range = req::SelectionRange { | ||
89 | range: ranges.last().unwrap().conv_with(&line_index), | ||
90 | parent: None, | ||
91 | }; | ||
92 | for r in ranges.iter().rev().skip(1) { | ||
93 | range = req::SelectionRange { | ||
94 | range: r.conv_with(&line_index), | ||
95 | parent: Some(Box::new(range)), | ||
96 | } | ||
97 | } | ||
98 | Ok(range) | ||
99 | }) | ||
100 | .collect() | ||
101 | } | ||
102 | |||
58 | pub fn handle_find_matching_brace( | 103 | pub fn handle_find_matching_brace( |
59 | world: ServerWorld, | 104 | world: ServerWorld, |
60 | params: req::FindMatchingBraceParams, | 105 | params: req::FindMatchingBraceParams, |
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index 4f35ab9b5..6090eb7b9 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs | |||
@@ -64,6 +64,28 @@ pub struct ExtendSelectionResult { | |||
64 | pub selections: Vec<Range>, | 64 | pub selections: Vec<Range>, |
65 | } | 65 | } |
66 | 66 | ||
67 | pub enum SelectionRangeRequest {} | ||
68 | |||
69 | impl Request for SelectionRangeRequest { | ||
70 | type Params = SelectionRangeParams; | ||
71 | type Result = Vec<SelectionRange>; | ||
72 | const METHOD: &'static str = "textDocument/selectionRange"; | ||
73 | } | ||
74 | |||
75 | #[derive(Deserialize, Debug)] | ||
76 | #[serde(rename_all = "camelCase")] | ||
77 | pub struct SelectionRangeParams { | ||
78 | pub text_document: TextDocumentIdentifier, | ||
79 | pub positions: Vec<Position>, | ||
80 | } | ||
81 | |||
82 | #[derive(Serialize, Debug)] | ||
83 | #[serde(rename_all = "camelCase")] | ||
84 | pub struct SelectionRange { | ||
85 | pub range: Range, | ||
86 | pub parent: Option<Box<SelectionRange>>, | ||
87 | } | ||
88 | |||
67 | pub enum FindMatchingBrace {} | 89 | pub enum FindMatchingBrace {} |
68 | 90 | ||
69 | impl Request for FindMatchingBrace { | 91 | impl Request for FindMatchingBrace { |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index ca33b43e7..5c4c0ffc1 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -65,6 +65,20 @@ impl ast::Attr { | |||
65 | None | 65 | None |
66 | } | 66 | } |
67 | } | 67 | } |
68 | |||
69 | pub fn as_key_value(&self) -> Option<(SmolStr, SmolStr)> { | ||
70 | let tt = self.value()?; | ||
71 | let tt_node = tt.syntax(); | ||
72 | let attr = tt_node.children_with_tokens().nth(1)?; | ||
73 | if attr.kind() == IDENT { | ||
74 | let key = attr.as_token()?.text().clone(); | ||
75 | let val_node = tt_node.children_with_tokens().find(|t| t.kind() == STRING)?; | ||
76 | let val = val_node.as_token()?.text().trim_start_matches("\"").trim_end_matches("\""); | ||
77 | Some((key, SmolStr::new(val))) | ||
78 | } else { | ||
79 | None | ||
80 | } | ||
81 | } | ||
68 | } | 82 | } |
69 | 83 | ||
70 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 84 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 17de4f058..fae371509 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1325,6 +1325,7 @@ impl ToOwned for ImplBlock { | |||
1325 | 1325 | ||
1326 | 1326 | ||
1327 | impl ast::TypeParamsOwner for ImplBlock {} | 1327 | impl ast::TypeParamsOwner for ImplBlock {} |
1328 | impl ast::AttrsOwner for ImplBlock {} | ||
1328 | impl ImplBlock { | 1329 | impl ImplBlock { |
1329 | pub fn item_list(&self) -> Option<&ItemList> { | 1330 | pub fn item_list(&self) -> Option<&ItemList> { |
1330 | super::child_opt(self) | 1331 | super::child_opt(self) |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 663e3a2f9..5bdcf9c84 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -345,7 +345,7 @@ Grammar( | |||
345 | ], | 345 | ], |
346 | options: ["TypeRef"] | 346 | options: ["TypeRef"] |
347 | ), | 347 | ), |
348 | "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner"]), | 348 | "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner", "AttrsOwner"]), |
349 | 349 | ||
350 | "ParenType": (options: ["TypeRef"]), | 350 | "ParenType": (options: ["TypeRef"]), |
351 | "TupleType": ( collections: [["fields", "TypeRef"]] ), | 351 | "TupleType": ( collections: [["fields", "TypeRef"]] ), |