diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-16 14:44:24 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-16 14:44:24 +0100 |
commit | 1216878f7be20dd0e652fb8cdc395009fdcfae07 (patch) | |
tree | 6551967cc8c6e921b66071453ad7888a9121d326 | |
parent | 39cb6c6d3f78b193f5873c3492e530bbd24d5dd2 (diff) | |
parent | 61f3a438d3a729a6be941bca1ff4c6a97a33f221 (diff) |
Merge #134
134: Cargo Format run r=kjeremy a=kjeremy
I'm not sure how appreciated this is but I figured I would run `cargo fmt` and see what came up.
I made sure that `cargo test` still passes.
Co-authored-by: Jeremy A. Kolb <[email protected]>
76 files changed, 1930 insertions, 1524 deletions
diff --git a/crates/gen_lsp_server/src/lib.rs b/crates/gen_lsp_server/src/lib.rs index 645728a57..e45a6b5e2 100644 --- a/crates/gen_lsp_server/src/lib.rs +++ b/crates/gen_lsp_server/src/lib.rs | |||
@@ -59,7 +59,6 @@ | |||
59 | //! } | 59 | //! } |
60 | //! ``` | 60 | //! ``` |
61 | 61 | ||
62 | |||
63 | #[macro_use] | 62 | #[macro_use] |
64 | extern crate failure; | 63 | extern crate failure; |
65 | #[macro_use] | 64 | #[macro_use] |
@@ -74,16 +73,16 @@ extern crate languageserver_types; | |||
74 | mod msg; | 73 | mod msg; |
75 | mod stdio; | 74 | mod stdio; |
76 | 75 | ||
77 | use crossbeam_channel::{Sender, Receiver}; | 76 | use crossbeam_channel::{Receiver, Sender}; |
78 | use languageserver_types::{ | 77 | use languageserver_types::{ |
79 | ServerCapabilities, InitializeResult, InitializeParams, | 78 | notification::{Exit, Initialized}, |
80 | request::{Initialize, Shutdown}, | 79 | request::{Initialize, Shutdown}, |
81 | notification::{Initialized, Exit}, | 80 | InitializeParams, InitializeResult, ServerCapabilities, |
82 | }; | 81 | }; |
83 | 82 | ||
84 | pub type Result<T> = ::std::result::Result<T, failure::Error>; | 83 | pub type Result<T> = ::std::result::Result<T, failure::Error>; |
85 | pub use { | 84 | pub use { |
86 | msg::{RawMessage, RawRequest, RawResponse, RawResponseError, RawNotification, ErrorCode}, | 85 | msg::{ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, RawResponseError}, |
87 | stdio::{stdio_transport, Threads}, | 86 | stdio::{stdio_transport, Threads}, |
88 | }; | 87 | }; |
89 | 88 | ||
@@ -97,11 +96,7 @@ pub fn run_server( | |||
97 | caps: ServerCapabilities, | 96 | caps: ServerCapabilities, |
98 | receiver: Receiver<RawMessage>, | 97 | receiver: Receiver<RawMessage>, |
99 | sender: Sender<RawMessage>, | 98 | sender: Sender<RawMessage>, |
100 | server: impl FnOnce( | 99 | server: impl FnOnce(InitializeParams, &Receiver<RawMessage>, &Sender<RawMessage>) -> Result<()>, |
101 | InitializeParams, | ||
102 | &Receiver<RawMessage>, | ||
103 | &Sender<RawMessage>, | ||
104 | ) -> Result<()>, | ||
105 | ) -> Result<()> { | 100 | ) -> Result<()> { |
106 | info!("lsp server initializes"); | 101 | info!("lsp server initializes"); |
107 | let params = initialize(&receiver, &sender, caps)?; | 102 | let params = initialize(&receiver, &sender, caps)?; |
@@ -109,12 +104,10 @@ pub fn run_server( | |||
109 | server(params, &receiver, &sender)?; | 104 | server(params, &receiver, &sender)?; |
110 | info!("lsp server waiting for exit notification"); | 105 | info!("lsp server waiting for exit notification"); |
111 | match receiver.recv() { | 106 | match receiver.recv() { |
112 | Some(RawMessage::Notification(n)) => { | 107 | Some(RawMessage::Notification(n)) => n |
113 | n.cast::<Exit>().map_err(|n| format_err!( | 108 | .cast::<Exit>() |
114 | "unexpected notification during shutdown: {:?}", n | 109 | .map_err(|n| format_err!("unexpected notification during shutdown: {:?}", n))?, |
115 | ))? | 110 | m => bail!("unexpected message during shutdown: {:?}", m), |
116 | } | ||
117 | m => bail!("unexpected message during shutdown: {:?}", m) | ||
118 | } | 111 | } |
119 | info!("lsp server shutdown complete"); | 112 | info!("lsp server shutdown complete"); |
120 | Ok(()) | 113 | Ok(()) |
@@ -141,17 +134,15 @@ fn initialize( | |||
141 | Some(RawMessage::Request(req)) => match req.cast::<Initialize>() { | 134 | Some(RawMessage::Request(req)) => match req.cast::<Initialize>() { |
142 | Err(req) => bail!("expected initialize request, got {:?}", req), | 135 | Err(req) => bail!("expected initialize request, got {:?}", req), |
143 | Ok(req) => req, | 136 | Ok(req) => req, |
144 | } | 137 | }, |
145 | msg => | 138 | msg => bail!("expected initialize request, got {:?}", msg), |
146 | bail!("expected initialize request, got {:?}", msg), | ||
147 | }; | 139 | }; |
148 | let resp = RawResponse::ok::<Initialize>(id, &InitializeResult { capabilities: caps }); | 140 | let resp = RawResponse::ok::<Initialize>(id, &InitializeResult { capabilities: caps }); |
149 | sender.send(RawMessage::Response(resp)); | 141 | sender.send(RawMessage::Response(resp)); |
150 | match receiver.recv() { | 142 | match receiver.recv() { |
151 | Some(RawMessage::Notification(n)) => { | 143 | Some(RawMessage::Notification(n)) => { |
152 | n.cast::<Initialized>().map_err(|_| format_err!( | 144 | n.cast::<Initialized>() |
153 | "expected initialized notification" | 145 | .map_err(|_| format_err!("expected initialized notification"))?; |
154 | ))?; | ||
155 | } | 146 | } |
156 | _ => bail!("expected initialized notification"), | 147 | _ => bail!("expected initialized notification"), |
157 | } | 148 | } |
diff --git a/crates/gen_lsp_server/src/msg.rs b/crates/gen_lsp_server/src/msg.rs index 7fcac6f6d..e0d0aeab5 100644 --- a/crates/gen_lsp_server/src/msg.rs +++ b/crates/gen_lsp_server/src/msg.rs | |||
@@ -1,11 +1,8 @@ | |||
1 | use std::io::{BufRead, Write}; | 1 | use std::io::{BufRead, Write}; |
2 | 2 | ||
3 | use serde_json::{Value, from_str, to_string, from_value, to_value}; | 3 | use languageserver_types::{notification::Notification, request::Request}; |
4 | use serde::{Serialize, de::DeserializeOwned}; | 4 | use serde::{de::DeserializeOwned, Serialize}; |
5 | use languageserver_types::{ | 5 | use serde_json::{from_str, from_value, to_string, to_value, Value}; |
6 | request::Request, | ||
7 | notification::Notification, | ||
8 | }; | ||
9 | 6 | ||
10 | use Result; | 7 | use Result; |
11 | 8 | ||
@@ -81,7 +78,10 @@ impl RawMessage { | |||
81 | #[serde(flatten)] | 78 | #[serde(flatten)] |
82 | msg: RawMessage, | 79 | msg: RawMessage, |
83 | } | 80 | } |
84 | let text = to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?; | 81 | let text = to_string(&JsonRpc { |
82 | jsonrpc: "2.0", | ||
83 | msg: self, | ||
84 | })?; | ||
85 | write_msg_text(w, &text)?; | 85 | write_msg_text(w, &text)?; |
86 | Ok(()) | 86 | Ok(()) |
87 | } | 87 | } |
@@ -115,8 +115,9 @@ impl RawRequest { | |||
115 | 115 | ||
116 | impl RawResponse { | 116 | impl RawResponse { |
117 | pub fn ok<R>(id: u64, result: &R::Result) -> RawResponse | 117 | pub fn ok<R>(id: u64, result: &R::Result) -> RawResponse |
118 | where R: Request, | 118 | where |
119 | R::Result: Serialize, | 119 | R: Request, |
120 | R::Result: Serialize, | ||
120 | { | 121 | { |
121 | RawResponse { | 122 | RawResponse { |
122 | id, | 123 | id, |
@@ -125,7 +126,11 @@ impl RawResponse { | |||
125 | } | 126 | } |
126 | } | 127 | } |
127 | pub fn err(id: u64, code: i32, message: String) -> RawResponse { | 128 | pub fn err(id: u64, code: i32, message: String) -> RawResponse { |
128 | let error = RawResponseError { code, message, data: None }; | 129 | let error = RawResponseError { |
130 | code, | ||
131 | message, | ||
132 | data: None, | ||
133 | }; | ||
129 | RawResponse { | 134 | RawResponse { |
130 | id, | 135 | id, |
131 | result: None, | 136 | result: None, |
@@ -174,7 +179,9 @@ fn read_msg_text(inp: &mut impl BufRead) -> Result<Option<String>> { | |||
174 | } | 179 | } |
175 | let mut parts = buf.splitn(2, ": "); | 180 | let mut parts = buf.splitn(2, ": "); |
176 | let header_name = parts.next().unwrap(); | 181 | let header_name = parts.next().unwrap(); |
177 | let header_value = parts.next().ok_or_else(|| format_err!("malformed header: {:?}", buf))?; | 182 | let header_value = parts |
183 | .next() | ||
184 | .ok_or_else(|| format_err!("malformed header: {:?}", buf))?; | ||
178 | if header_name == "Content-Length" { | 185 | if header_name == "Content-Length" { |
179 | size = Some(header_value.parse::<usize>()?); | 186 | size = Some(header_value.parse::<usize>()?); |
180 | } | 187 | } |
diff --git a/crates/gen_lsp_server/src/stdio.rs b/crates/gen_lsp_server/src/stdio.rs index 81397bb2a..3d8a1712a 100644 --- a/crates/gen_lsp_server/src/stdio.rs +++ b/crates/gen_lsp_server/src/stdio.rs | |||
@@ -1,11 +1,9 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | io::{stdin, stdout}, | ||
2 | thread, | 3 | thread, |
3 | io::{ | ||
4 | stdout, stdin, | ||
5 | }, | ||
6 | }; | 4 | }; |
7 | 5 | ||
8 | use crossbeam_channel::{Receiver, Sender, bounded}; | 6 | use crossbeam_channel::{bounded, Receiver, Sender}; |
9 | 7 | ||
10 | use {RawMessage, Result}; | 8 | use {RawMessage, Result}; |
11 | 9 | ||
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index c69577233..042dde1ac 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -1,17 +1,18 @@ | |||
1 | use std::{ | ||
2 | fmt, | ||
3 | sync::Arc, | ||
4 | hash::{Hash, Hasher}, | ||
5 | }; | ||
6 | use salsa; | ||
7 | use rustc_hash::FxHashSet; | ||
8 | use ra_syntax::File; | ||
9 | use ra_editor::{LineIndex}; | ||
10 | use crate::{ | 1 | use crate::{ |
2 | module_map::{ModuleDescriptorQuery, ModuleTreeQuery, ModulesDatabase}, | ||
11 | symbol_index::SymbolIndex, | 3 | symbol_index::SymbolIndex, |
12 | module_map::{ModulesDatabase, ModuleTreeQuery, ModuleDescriptorQuery}, | ||
13 | FileId, FileResolverImp, | 4 | FileId, FileResolverImp, |
14 | }; | 5 | }; |
6 | use ra_editor::LineIndex; | ||
7 | use ra_syntax::File; | ||
8 | use rustc_hash::FxHashSet; | ||
9 | use salsa; | ||
10 | |||
11 | use std::{ | ||
12 | fmt, | ||
13 | hash::{Hash, Hasher}, | ||
14 | sync::Arc, | ||
15 | }; | ||
15 | 16 | ||
16 | #[derive(Default)] | 17 | #[derive(Default)] |
17 | pub(crate) struct RootDatabase { | 18 | pub(crate) struct RootDatabase { |
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs index 8d9f38ca5..6f26f9935 100644 --- a/crates/ra_analysis/src/descriptors.rs +++ b/crates/ra_analysis/src/descriptors.rs | |||
@@ -1,41 +1,34 @@ | |||
1 | use std::{ | 1 | use crate::{imp::FileResolverImp, FileId}; |
2 | collections::BTreeMap, | ||
3 | }; | ||
4 | use relative_path::RelativePathBuf; | ||
5 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, AstNode, NameOwner}, | ||
4 | text_utils::is_subrange, | ||
6 | SmolStr, | 5 | SmolStr, |
7 | ast::{self, NameOwner, AstNode}, | ||
8 | text_utils::is_subrange | ||
9 | }; | ||
10 | use crate::{ | ||
11 | FileId, | ||
12 | imp::FileResolverImp, | ||
13 | }; | 6 | }; |
7 | use relative_path::RelativePathBuf; | ||
8 | |||
9 | use std::collections::BTreeMap; | ||
14 | 10 | ||
15 | #[derive(Debug, PartialEq, Eq, Hash)] | 11 | #[derive(Debug, PartialEq, Eq, Hash)] |
16 | pub struct ModuleDescriptor { | 12 | pub struct ModuleDescriptor { |
17 | pub submodules: Vec<Submodule> | 13 | pub submodules: Vec<Submodule>, |
18 | } | 14 | } |
19 | 15 | ||
20 | impl ModuleDescriptor { | 16 | impl ModuleDescriptor { |
21 | pub fn new(root: ast::Root) -> ModuleDescriptor { | 17 | pub fn new(root: ast::Root) -> ModuleDescriptor { |
22 | let submodules = modules(root) | 18 | let submodules = modules(root).map(|(name, _)| Submodule { name }).collect(); |
23 | .map(|(name, _)| Submodule { name }) | ||
24 | .collect(); | ||
25 | 19 | ||
26 | ModuleDescriptor { submodules } } | 20 | ModuleDescriptor { submodules } |
21 | } | ||
27 | } | 22 | } |
28 | 23 | ||
29 | fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item=(SmolStr, ast::Module<'a>)> { | 24 | fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> { |
30 | root | 25 | root.modules().filter_map(|module| { |
31 | .modules() | 26 | let name = module.name()?.text(); |
32 | .filter_map(|module| { | 27 | if !module.has_semi() { |
33 | let name = module.name()?.text(); | 28 | return None; |
34 | if !module.has_semi() { | 29 | } |
35 | return None; | 30 | Some((name, module)) |
36 | } | 31 | }) |
37 | Some((name, module)) | ||
38 | }) | ||
39 | } | 32 | } |
40 | 33 | ||
41 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] | 34 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] |
@@ -56,7 +49,7 @@ struct Node(usize); | |||
56 | struct NodeData { | 49 | struct NodeData { |
57 | file_id: FileId, | 50 | file_id: FileId, |
58 | links: Vec<Link>, | 51 | links: Vec<Link>, |
59 | parents: Vec<Link> | 52 | parents: Vec<Link>, |
60 | } | 53 | } |
61 | 54 | ||
62 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | 55 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
@@ -69,7 +62,6 @@ struct LinkData { | |||
69 | problem: Option<Problem>, | 62 | problem: Option<Problem>, |
70 | } | 63 | } |
71 | 64 | ||
72 | |||
73 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 65 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
74 | pub enum Problem { | 66 | pub enum Problem { |
75 | UnresolvedModule { | 67 | UnresolvedModule { |
@@ -78,16 +70,18 @@ pub enum Problem { | |||
78 | NotDirOwner { | 70 | NotDirOwner { |
79 | move_to: RelativePathBuf, | 71 | move_to: RelativePathBuf, |
80 | candidate: RelativePathBuf, | 72 | candidate: RelativePathBuf, |
81 | } | 73 | }, |
82 | } | 74 | } |
83 | 75 | ||
84 | impl ModuleTreeDescriptor { | 76 | impl ModuleTreeDescriptor { |
85 | pub(crate) fn new<'a>( | 77 | pub(crate) fn new<'a>( |
86 | files: impl Iterator<Item=(FileId, &'a ModuleDescriptor)> + Clone, | 78 | files: impl Iterator<Item = (FileId, &'a ModuleDescriptor)> + Clone, |
87 | file_resolver: &FileResolverImp, | 79 | file_resolver: &FileResolverImp, |
88 | ) -> ModuleTreeDescriptor { | 80 | ) -> ModuleTreeDescriptor { |
89 | let mut file_id2node = BTreeMap::new(); | 81 | let mut file_id2node = BTreeMap::new(); |
90 | let mut nodes: Vec<NodeData> = files.clone().enumerate() | 82 | let mut nodes: Vec<NodeData> = files |
83 | .clone() | ||
84 | .enumerate() | ||
91 | .map(|(idx, (file_id, _))| { | 85 | .map(|(idx, (file_id, _))| { |
92 | file_id2node.insert(file_id, Node(idx)); | 86 | file_id2node.insert(file_id, Node(idx)); |
93 | NodeData { | 87 | NodeData { |
@@ -120,20 +114,19 @@ impl ModuleTreeDescriptor { | |||
120 | points_to, | 114 | points_to, |
121 | problem, | 115 | problem, |
122 | }) | 116 | }) |
123 | |||
124 | } | 117 | } |
125 | } | 118 | } |
126 | 119 | ||
127 | ModuleTreeDescriptor { | 120 | ModuleTreeDescriptor { |
128 | nodes, links, file_id2node | 121 | nodes, |
122 | links, | ||
123 | file_id2node, | ||
129 | } | 124 | } |
130 | } | 125 | } |
131 | 126 | ||
132 | pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> { | 127 | pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> { |
133 | let node = self.file_id2node[&file_id]; | 128 | let node = self.file_id2node[&file_id]; |
134 | self.node(node) | 129 | self.node(node).parents.clone() |
135 | .parents | ||
136 | .clone() | ||
137 | } | 130 | } |
138 | pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> { | 131 | pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> { |
139 | let node = self.file_id2node[&file_id]; | 132 | let node = self.file_id2node[&file_id]; |
@@ -141,10 +134,18 @@ impl ModuleTreeDescriptor { | |||
141 | .links | 134 | .links |
142 | .iter() | 135 | .iter() |
143 | .filter(|it| it.name(self) == name) | 136 | .filter(|it| it.name(self) == name) |
144 | .flat_map(|link| link.points_to(self).iter().map(|&node| self.node(node).file_id)) | 137 | .flat_map(|link| { |
138 | link.points_to(self) | ||
139 | .iter() | ||
140 | .map(|&node| self.node(node).file_id) | ||
141 | }) | ||
145 | .collect() | 142 | .collect() |
146 | } | 143 | } |
147 | pub(crate) fn problems<'a, 'b>(&'b self, file_id: FileId, root: ast::Root<'a>) -> Vec<(ast::Name<'a>, &'b Problem)> { | 144 | pub(crate) fn problems<'a, 'b>( |
145 | &'b self, | ||
146 | file_id: FileId, | ||
147 | root: ast::Root<'a>, | ||
148 | ) -> Vec<(ast::Name<'a>, &'b Problem)> { | ||
148 | let node = self.file_id2node[&file_id]; | 149 | let node = self.file_id2node[&file_id]; |
149 | self.node(node) | 150 | self.node(node) |
150 | .links | 151 | .links |
@@ -176,7 +177,11 @@ impl Link { | |||
176 | fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] { | 177 | fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] { |
177 | &tree.link(self).points_to | 178 | &tree.link(self).points_to |
178 | } | 179 | } |
179 | pub(crate) fn bind_source<'a>(self, tree: &ModuleTreeDescriptor, root: ast::Root<'a>) -> ast::Module<'a> { | 180 | pub(crate) fn bind_source<'a>( |
181 | self, | ||
182 | tree: &ModuleTreeDescriptor, | ||
183 | root: ast::Root<'a>, | ||
184 | ) -> ast::Module<'a> { | ||
180 | modules(root) | 185 | modules(root) |
181 | .filter(|(name, _)| name == &tree.link(self).name) | 186 | .filter(|(name, _)| name == &tree.link(self).name) |
182 | .next() | 187 | .next() |
@@ -185,22 +190,21 @@ impl Link { | |||
185 | } | 190 | } |
186 | } | 191 | } |
187 | 192 | ||
188 | |||
189 | fn resolve_submodule( | 193 | fn resolve_submodule( |
190 | file_id: FileId, | 194 | file_id: FileId, |
191 | name: &SmolStr, | 195 | name: &SmolStr, |
192 | file_resolver: &FileResolverImp | 196 | file_resolver: &FileResolverImp, |
193 | ) -> (Vec<FileId>, Option<Problem>) { | 197 | ) -> (Vec<FileId>, Option<Problem>) { |
194 | let mod_name = file_resolver.file_stem(file_id); | 198 | let mod_name = file_resolver.file_stem(file_id); |
195 | let is_dir_owner = | 199 | let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; |
196 | mod_name == "mod" || mod_name == "lib" || mod_name == "main"; | ||
197 | 200 | ||
198 | let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); | 201 | let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); |
199 | let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); | 202 | let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); |
200 | let points_to: Vec<FileId>; | 203 | let points_to: Vec<FileId>; |
201 | let problem: Option<Problem>; | 204 | let problem: Option<Problem>; |
202 | if is_dir_owner { | 205 | if is_dir_owner { |
203 | points_to = [&file_mod, &dir_mod].iter() | 206 | points_to = [&file_mod, &dir_mod] |
207 | .iter() | ||
204 | .filter_map(|path| file_resolver.resolve(file_id, path)) | 208 | .filter_map(|path| file_resolver.resolve(file_id, path)) |
205 | .collect(); | 209 | .collect(); |
206 | problem = if points_to.is_empty() { | 210 | problem = if points_to.is_empty() { |
@@ -223,7 +227,7 @@ fn resolve_submodule( | |||
223 | #[derive(Debug, Clone)] | 227 | #[derive(Debug, Clone)] |
224 | pub struct FnDescriptor { | 228 | pub struct FnDescriptor { |
225 | pub name: String, | 229 | pub name: String, |
226 | pub label : String, | 230 | pub label: String, |
227 | pub ret_type: Option<String>, | 231 | pub ret_type: Option<String>, |
228 | pub params: Vec<String>, | 232 | pub params: Vec<String>, |
229 | } | 233 | } |
@@ -233,9 +237,11 @@ impl FnDescriptor { | |||
233 | let name = node.name()?.text().to_string(); | 237 | let name = node.name()?.text().to_string(); |
234 | 238 | ||
235 | // Strip the body out for the label. | 239 | // Strip the body out for the label. |
236 | let label : String = if let Some(body) = node.body() { | 240 | let label: String = if let Some(body) = node.body() { |
237 | let body_range = body.syntax().range(); | 241 | let body_range = body.syntax().range(); |
238 | let label : String = node.syntax().children() | 242 | let label: String = node |
243 | .syntax() | ||
244 | .children() | ||
239 | .filter(|child| !is_subrange(body_range, child.range())) | 245 | .filter(|child| !is_subrange(body_range, child.range())) |
240 | .map(|node| node.text().to_string()) | 246 | .map(|node| node.text().to_string()) |
241 | .collect(); | 247 | .collect(); |
@@ -251,7 +257,7 @@ impl FnDescriptor { | |||
251 | name, | 257 | name, |
252 | ret_type, | 258 | ret_type, |
253 | params, | 259 | params, |
254 | label | 260 | label, |
255 | }) | 261 | }) |
256 | } | 262 | } |
257 | 263 | ||
@@ -264,9 +270,11 @@ impl FnDescriptor { | |||
264 | 270 | ||
265 | // Maybe use param.pat here? See if we can just extract the name? | 271 | // Maybe use param.pat here? See if we can just extract the name? |
266 | //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); | 272 | //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); |
267 | res.extend(param_list.params() | 273 | res.extend( |
268 | .filter_map(|p| p.pat()) | 274 | param_list |
269 | .map(|pat| pat.syntax().text().to_string()) | 275 | .params() |
276 | .filter_map(|p| p.pat()) | ||
277 | .map(|pat| pat.syntax().text().to_string()), | ||
270 | ); | 278 | ); |
271 | } | 279 | } |
272 | res | 280 | res |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 5efcaeca0..f1403cb5d 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -1,32 +1,31 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | sync::{ | ||
3 | Arc, | ||
4 | }, | ||
5 | hash::{Hash, Hasher}, | ||
6 | fmt, | ||
7 | collections::VecDeque, | 2 | collections::VecDeque, |
3 | fmt, | ||
4 | hash::{Hash, Hasher}, | ||
8 | iter, | 5 | iter, |
6 | sync::Arc, | ||
9 | }; | 7 | }; |
10 | 8 | ||
11 | use relative_path::RelativePath; | 9 | use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit}; |
12 | use rustc_hash::FxHashSet; | ||
13 | use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name}; | ||
14 | use ra_syntax::{ | 10 | use ra_syntax::{ |
15 | TextUnit, TextRange, SmolStr, File, AstNode, SyntaxNodeRef, | 11 | ast::{self, ArgListOwner, Expr, NameOwner}, |
12 | AstNode, File, SmolStr, | ||
16 | SyntaxKind::*, | 13 | SyntaxKind::*, |
17 | ast::{self, NameOwner, ArgListOwner, Expr}, | 14 | SyntaxNodeRef, TextRange, TextUnit, |
18 | }; | 15 | }; |
16 | use relative_path::RelativePath; | ||
17 | use rustc_hash::FxHashSet; | ||
19 | 18 | ||
20 | use crate::{ | 19 | use crate::{ |
21 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, | ||
22 | JobToken, CrateGraph, CrateId, | ||
23 | roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, | ||
24 | descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem}, | 20 | descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem}, |
21 | roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot}, | ||
22 | CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, JobToken, Position, | ||
23 | Query, SourceChange, SourceFileEdit, | ||
25 | }; | 24 | }; |
26 | 25 | ||
27 | #[derive(Clone, Debug)] | 26 | #[derive(Clone, Debug)] |
28 | pub(crate) struct FileResolverImp { | 27 | pub(crate) struct FileResolverImp { |
29 | inner: Arc<FileResolver> | 28 | inner: Arc<FileResolver>, |
30 | } | 29 | } |
31 | 30 | ||
32 | impl PartialEq for FileResolverImp { | 31 | impl PartialEq for FileResolverImp { |
@@ -35,8 +34,7 @@ impl PartialEq for FileResolverImp { | |||
35 | } | 34 | } |
36 | } | 35 | } |
37 | 36 | ||
38 | impl Eq for FileResolverImp { | 37 | impl Eq for FileResolverImp {} |
39 | } | ||
40 | 38 | ||
41 | impl Hash for FileResolverImp { | 39 | impl Hash for FileResolverImp { |
42 | fn hash<H: Hasher>(&self, hasher: &mut H) { | 40 | fn hash<H: Hasher>(&self, hasher: &mut H) { |
@@ -67,17 +65,23 @@ impl Default for FileResolverImp { | |||
67 | fn file_stem(&self, _file_: FileId) -> String { | 65 | fn file_stem(&self, _file_: FileId) -> String { |
68 | panic!("file resolver not set") | 66 | panic!("file resolver not set") |
69 | } | 67 | } |
70 | fn resolve(&self, _file_id: FileId, _path: &::relative_path::RelativePath) -> Option<FileId> { | 68 | fn resolve( |
69 | &self, | ||
70 | _file_id: FileId, | ||
71 | _path: &::relative_path::RelativePath, | ||
72 | ) -> Option<FileId> { | ||
71 | panic!("file resolver not set") | 73 | panic!("file resolver not set") |
72 | } | 74 | } |
73 | } | 75 | } |
74 | FileResolverImp { inner: Arc::new(DummyResolver) } | 76 | FileResolverImp { |
77 | inner: Arc::new(DummyResolver), | ||
78 | } | ||
75 | } | 79 | } |
76 | } | 80 | } |
77 | 81 | ||
78 | #[derive(Debug)] | 82 | #[derive(Debug)] |
79 | pub(crate) struct AnalysisHostImpl { | 83 | pub(crate) struct AnalysisHostImpl { |
80 | data: WorldData | 84 | data: WorldData, |
81 | } | 85 | } |
82 | 86 | ||
83 | impl AnalysisHostImpl { | 87 | impl AnalysisHostImpl { |
@@ -91,13 +95,13 @@ impl AnalysisHostImpl { | |||
91 | data: self.data.clone(), | 95 | data: self.data.clone(), |
92 | } | 96 | } |
93 | } | 97 | } |
94 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { | 98 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item = (FileId, Option<String>)>) { |
95 | self.data_mut() | 99 | self.data_mut().root.apply_changes(changes, None); |
96 | .root.apply_changes(changes, None); | ||
97 | } | 100 | } |
98 | pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { | 101 | pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { |
99 | self.data_mut() | 102 | self.data_mut() |
100 | .root.apply_changes(&mut iter::empty(), Some(resolver)); | 103 | .root |
104 | .apply_changes(&mut iter::empty(), Some(resolver)); | ||
101 | } | 105 | } |
102 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 106 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
103 | let mut visited = FxHashSet::default(); | 107 | let mut visited = FxHashSet::default(); |
@@ -131,7 +135,12 @@ impl AnalysisImpl { | |||
131 | if self.data.root.contains(file_id) { | 135 | if self.data.root.contains(file_id) { |
132 | return &self.data.root; | 136 | return &self.data.root; |
133 | } | 137 | } |
134 | &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() | 138 | &**self |
139 | .data | ||
140 | .libs | ||
141 | .iter() | ||
142 | .find(|it| it.contains(file_id)) | ||
143 | .unwrap() | ||
135 | } | 144 | } |
136 | pub fn file_syntax(&self, file_id: FileId) -> File { | 145 | pub fn file_syntax(&self, file_id: FileId) -> File { |
137 | self.root(file_id).syntax(file_id) | 146 | self.root(file_id).syntax(file_id) |
@@ -142,18 +151,17 @@ impl AnalysisImpl { | |||
142 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 151 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
143 | let mut buf = Vec::new(); | 152 | let mut buf = Vec::new(); |
144 | if query.libs { | 153 | if query.libs { |
145 | self.data.libs.iter() | 154 | self.data.libs.iter().for_each(|it| it.symbols(&mut buf)); |
146 | .for_each(|it| it.symbols(&mut buf)); | ||
147 | } else { | 155 | } else { |
148 | self.data.root.symbols(&mut buf); | 156 | self.data.root.symbols(&mut buf); |
149 | } | 157 | } |
150 | query.search(&buf, token) | 158 | query.search(&buf, token) |
151 | |||
152 | } | 159 | } |
153 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { | 160 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { |
154 | let root = self.root(file_id); | 161 | let root = self.root(file_id); |
155 | let module_tree = root.module_tree(); | 162 | let module_tree = root.module_tree(); |
156 | module_tree.parent_modules(file_id) | 163 | module_tree |
164 | .parent_modules(file_id) | ||
157 | .iter() | 165 | .iter() |
158 | .map(|link| { | 166 | .map(|link| { |
159 | let file_id = link.owner(&module_tree); | 167 | let file_id = link.owner(&module_tree); |
@@ -203,15 +211,17 @@ impl AnalysisImpl { | |||
203 | let file = root.syntax(file_id); | 211 | let file = root.syntax(file_id); |
204 | let syntax = file.syntax(); | 212 | let syntax = file.syntax(); |
205 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 213 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
206 | |||
207 | // First try to resolve the symbol locally | 214 | // First try to resolve the symbol locally |
208 | if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { | 215 | if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { |
209 | let mut vec = vec![]; | 216 | let mut vec = vec![]; |
210 | vec.push((file_id, FileSymbol { | 217 | vec.push(( |
211 | name, | 218 | file_id, |
212 | node_range: range, | 219 | FileSymbol { |
213 | kind : NAME | 220 | name, |
214 | })); | 221 | node_range: range, |
222 | kind: NAME, | ||
223 | }, | ||
224 | )); | ||
215 | 225 | ||
216 | return vec; | 226 | return vec; |
217 | } else { | 227 | } else { |
@@ -224,17 +234,21 @@ impl AnalysisImpl { | |||
224 | if module.has_semi() { | 234 | if module.has_semi() { |
225 | let file_ids = self.resolve_module(&*module_tree, file_id, module); | 235 | let file_ids = self.resolve_module(&*module_tree, file_id, module); |
226 | 236 | ||
227 | let res = file_ids.into_iter().map(|id| { | 237 | let res = file_ids |
228 | let name = module.name() | 238 | .into_iter() |
229 | .map(|n| n.text()) | 239 | .map(|id| { |
230 | .unwrap_or_else(|| SmolStr::new("")); | 240 | let name = module |
231 | let symbol = FileSymbol { | 241 | .name() |
232 | name, | 242 | .map(|n| n.text()) |
233 | node_range: TextRange::offset_len(0.into(), 0.into()), | 243 | .unwrap_or_else(|| SmolStr::new("")); |
234 | kind: MODULE, | 244 | let symbol = FileSymbol { |
235 | }; | 245 | name, |
236 | (id, symbol) | 246 | node_range: TextRange::offset_len(0.into(), 0.into()), |
237 | }).collect(); | 247 | kind: MODULE, |
248 | }; | ||
249 | (id, symbol) | ||
250 | }) | ||
251 | .collect(); | ||
238 | 252 | ||
239 | return res; | 253 | return res; |
240 | } | 254 | } |
@@ -245,12 +259,16 @@ impl AnalysisImpl { | |||
245 | 259 | ||
246 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { | 260 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { |
247 | let root = self.root(file_id); | 261 | let root = self.root(file_id); |
248 | let module_tree = root.module_tree(); | 262 | let module_tree = root.module_tree(); |
249 | let syntax = root.syntax(file_id); | 263 | let syntax = root.syntax(file_id); |
250 | 264 | ||
251 | let mut res = ra_editor::diagnostics(&syntax) | 265 | let mut res = ra_editor::diagnostics(&syntax) |
252 | .into_iter() | 266 | .into_iter() |
253 | .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) | 267 | .map(|d| Diagnostic { |
268 | range: d.range, | ||
269 | message: d.msg, | ||
270 | fix: None, | ||
271 | }) | ||
254 | .collect::<Vec<_>>(); | 272 | .collect::<Vec<_>>(); |
255 | 273 | ||
256 | for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) { | 274 | for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) { |
@@ -273,8 +291,14 @@ impl AnalysisImpl { | |||
273 | } | 291 | } |
274 | } | 292 | } |
275 | Problem::NotDirOwner { move_to, candidate } => { | 293 | Problem::NotDirOwner { move_to, candidate } => { |
276 | let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() }; | 294 | let move_file = FileSystemEdit::MoveFile { |
277 | let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) }; | 295 | file: file_id, |
296 | path: move_to.clone(), | ||
297 | }; | ||
298 | let create_file = FileSystemEdit::CreateFile { | ||
299 | anchor: file_id, | ||
300 | path: move_to.join(candidate), | ||
301 | }; | ||
278 | let fix = SourceChange { | 302 | let fix = SourceChange { |
279 | label: "move file and create module".to_string(), | 303 | label: "move file and create module".to_string(), |
280 | source_file_edits: Vec::new(), | 304 | source_file_edits: Vec::new(), |
@@ -297,23 +321,34 @@ impl AnalysisImpl { | |||
297 | let file = self.file_syntax(file_id); | 321 | let file = self.file_syntax(file_id); |
298 | let offset = range.start(); | 322 | let offset = range.start(); |
299 | let actions = vec![ | 323 | let actions = vec![ |
300 | ("flip comma", ra_editor::flip_comma(&file, offset).map(|f| f())), | 324 | ( |
301 | ("add `#[derive]`", ra_editor::add_derive(&file, offset).map(|f| f())), | 325 | "flip comma", |
326 | ra_editor::flip_comma(&file, offset).map(|f| f()), | ||
327 | ), | ||
328 | ( | ||
329 | "add `#[derive]`", | ||
330 | ra_editor::add_derive(&file, offset).map(|f| f()), | ||
331 | ), | ||
302 | ("add impl", ra_editor::add_impl(&file, offset).map(|f| f())), | 332 | ("add impl", ra_editor::add_impl(&file, offset).map(|f| f())), |
303 | ("introduce variable", ra_editor::introduce_variable(&file, range).map(|f| f())), | 333 | ( |
334 | "introduce variable", | ||
335 | ra_editor::introduce_variable(&file, range).map(|f| f()), | ||
336 | ), | ||
304 | ]; | 337 | ]; |
305 | actions.into_iter() | 338 | actions |
339 | .into_iter() | ||
306 | .filter_map(|(name, local_edit)| { | 340 | .filter_map(|(name, local_edit)| { |
307 | Some(SourceChange::from_local_edit( | 341 | Some(SourceChange::from_local_edit(file_id, name, local_edit?)) |
308 | file_id, name, local_edit?, | ||
309 | )) | ||
310 | }) | 342 | }) |
311 | .collect() | 343 | .collect() |
312 | } | 344 | } |
313 | 345 | ||
314 | pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken) | 346 | pub fn resolve_callable( |
315 | -> Option<(FnDescriptor, Option<usize>)> { | 347 | &self, |
316 | 348 | file_id: FileId, | |
349 | offset: TextUnit, | ||
350 | token: &JobToken, | ||
351 | ) -> Option<(FnDescriptor, Option<usize>)> { | ||
317 | let root = self.root(file_id); | 352 | let root = self.root(file_id); |
318 | let file = root.syntax(file_id); | 353 | let file = root.syntax(file_id); |
319 | let syntax = file.syntax(); | 354 | let syntax = file.syntax(); |
@@ -332,9 +367,7 @@ impl AnalysisImpl { | |||
332 | let mut current_parameter = None; | 367 | let mut current_parameter = None; |
333 | 368 | ||
334 | let num_params = descriptor.params.len(); | 369 | let num_params = descriptor.params.len(); |
335 | let has_self = fn_def.param_list() | 370 | let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); |
336 | .and_then(|l| l.self_param()) | ||
337 | .is_some(); | ||
338 | 371 | ||
339 | if num_params == 1 { | 372 | if num_params == 1 { |
340 | if !has_self { | 373 | if !has_self { |
@@ -350,8 +383,11 @@ impl AnalysisImpl { | |||
350 | let start = arg_list.syntax().range().start(); | 383 | let start = arg_list.syntax().range().start(); |
351 | 384 | ||
352 | let range_search = TextRange::from_to(start, offset); | 385 | let range_search = TextRange::from_to(start, offset); |
353 | let mut commas: usize = arg_list.syntax().text() | 386 | let mut commas: usize = arg_list |
354 | .slice(range_search).to_string() | 387 | .syntax() |
388 | .text() | ||
389 | .slice(range_search) | ||
390 | .to_string() | ||
355 | .matches(",") | 391 | .matches(",") |
356 | .count(); | 392 | .count(); |
357 | 393 | ||
@@ -381,7 +417,12 @@ impl AnalysisImpl { | |||
381 | self.world_symbols(query, token) | 417 | self.world_symbols(query, token) |
382 | } | 418 | } |
383 | 419 | ||
384 | fn resolve_module(&self, module_tree: &ModuleTreeDescriptor, file_id: FileId, module: ast::Module) -> Vec<FileId> { | 420 | fn resolve_module( |
421 | &self, | ||
422 | module_tree: &ModuleTreeDescriptor, | ||
423 | file_id: FileId, | ||
424 | module: ast::Module, | ||
425 | ) -> Vec<FileId> { | ||
385 | let name = match module.name() { | 426 | let name = match module.name() { |
386 | Some(name) => name.text(), | 427 | Some(name) => name.text(), |
387 | None => return Vec::new(), | 428 | None => return Vec::new(), |
@@ -407,15 +448,17 @@ impl SourceChange { | |||
407 | label: label.to_string(), | 448 | label: label.to_string(), |
408 | source_file_edits: vec![file_edit], | 449 | source_file_edits: vec![file_edit], |
409 | file_system_edits: vec![], | 450 | file_system_edits: vec![], |
410 | cursor_position: edit.cursor_position | 451 | cursor_position: edit |
411 | .map(|offset| Position { offset, file_id }) | 452 | .cursor_position |
453 | .map(|offset| Position { offset, file_id }), | ||
412 | } | 454 | } |
413 | } | 455 | } |
414 | } | 456 | } |
415 | 457 | ||
416 | impl CrateGraph { | 458 | impl CrateGraph { |
417 | fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { | 459 | fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { |
418 | let (&crate_id, _) = self.crate_roots | 460 | let (&crate_id, _) = self |
461 | .crate_roots | ||
419 | .iter() | 462 | .iter() |
420 | .find(|(_crate_id, &root_id)| root_id == file_id)?; | 463 | .find(|(_crate_id, &root_id)| root_id == file_id)?; |
421 | Some(crate_id) | 464 | Some(crate_id) |
@@ -424,7 +467,7 @@ impl CrateGraph { | |||
424 | 467 | ||
425 | enum FnCallNode<'a> { | 468 | enum FnCallNode<'a> { |
426 | CallExpr(ast::CallExpr<'a>), | 469 | CallExpr(ast::CallExpr<'a>), |
427 | MethodCallExpr(ast::MethodCallExpr<'a>) | 470 | MethodCallExpr(ast::MethodCallExpr<'a>), |
428 | } | 471 | } |
429 | 472 | ||
430 | impl<'a> FnCallNode<'a> { | 473 | impl<'a> FnCallNode<'a> { |
@@ -440,27 +483,23 @@ impl<'a> FnCallNode<'a> { | |||
440 | 483 | ||
441 | pub fn name_ref(&self) -> Option<ast::NameRef> { | 484 | pub fn name_ref(&self) -> Option<ast::NameRef> { |
442 | match *self { | 485 | match *self { |
443 | FnCallNode::CallExpr(call_expr) => { | 486 | FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? { |
444 | Some(match call_expr.expr()? { | 487 | Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?, |
445 | Expr::PathExpr(path_expr) => { | 488 | _ => return None, |
446 | path_expr.path()?.segment()?.name_ref()? | 489 | }), |
447 | }, | 490 | |
448 | _ => return None | 491 | FnCallNode::MethodCallExpr(call_expr) => call_expr |
449 | }) | 492 | .syntax() |
450 | }, | 493 | .children() |
451 | 494 | .filter_map(ast::NameRef::cast) | |
452 | FnCallNode::MethodCallExpr(call_expr) => { | 495 | .nth(0), |
453 | call_expr.syntax().children() | ||
454 | .filter_map(ast::NameRef::cast) | ||
455 | .nth(0) | ||
456 | } | ||
457 | } | 496 | } |
458 | } | 497 | } |
459 | 498 | ||
460 | pub fn arg_list(&self) -> Option<ast::ArgList> { | 499 | pub fn arg_list(&self) -> Option<ast::ArgList> { |
461 | match *self { | 500 | match *self { |
462 | FnCallNode::CallExpr(expr) => expr.arg_list(), | 501 | FnCallNode::CallExpr(expr) => expr.arg_list(), |
463 | FnCallNode::MethodCallExpr(expr) => expr.arg_list() | 502 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), |
464 | } | 503 | } |
465 | } | 504 | } |
466 | } | 505 | } |
diff --git a/crates/ra_analysis/src/job.rs b/crates/ra_analysis/src/job.rs index ea1652a26..2871f9839 100644 --- a/crates/ra_analysis/src/job.rs +++ b/crates/ra_analysis/src/job.rs | |||
@@ -14,15 +14,20 @@ impl JobHandle { | |||
14 | pub fn new() -> (JobHandle, JobToken) { | 14 | pub fn new() -> (JobHandle, JobToken) { |
15 | let (sender_alive, receiver_alive) = bounded(0); | 15 | let (sender_alive, receiver_alive) = bounded(0); |
16 | let (sender_canceled, receiver_canceled) = bounded(0); | 16 | let (sender_canceled, receiver_canceled) = bounded(0); |
17 | let token = JobToken { _job_alive: sender_alive, job_canceled: receiver_canceled }; | 17 | let token = JobToken { |
18 | let handle = JobHandle { job_alive: receiver_alive, _job_canceled: sender_canceled }; | 18 | _job_alive: sender_alive, |
19 | job_canceled: receiver_canceled, | ||
20 | }; | ||
21 | let handle = JobHandle { | ||
22 | job_alive: receiver_alive, | ||
23 | _job_canceled: sender_canceled, | ||
24 | }; | ||
19 | (handle, token) | 25 | (handle, token) |
20 | } | 26 | } |
21 | pub fn has_completed(&self) -> bool { | 27 | pub fn has_completed(&self) -> bool { |
22 | is_closed(&self.job_alive) | 28 | is_closed(&self.job_alive) |
23 | } | 29 | } |
24 | pub fn cancel(self) { | 30 | pub fn cancel(self) {} |
25 | } | ||
26 | } | 31 | } |
27 | 32 | ||
28 | impl JobToken { | 33 | impl JobToken { |
@@ -31,7 +36,6 @@ impl JobToken { | |||
31 | } | 36 | } |
32 | } | 37 | } |
33 | 38 | ||
34 | |||
35 | // We don't actually send messages through the channels, | 39 | // We don't actually send messages through the channels, |
36 | // and instead just check if the channel is closed, | 40 | // and instead just check if the channel is closed, |
37 | // so we use uninhabited enum as a message type | 41 | // so we use uninhabited enum as a message type |
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index d8b355a81..2eeacaabe 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -1,44 +1,40 @@ | |||
1 | extern crate parking_lot; | 1 | extern crate parking_lot; |
2 | #[macro_use] | 2 | #[macro_use] |
3 | extern crate log; | 3 | extern crate log; |
4 | extern crate fst; | ||
4 | extern crate once_cell; | 5 | extern crate once_cell; |
5 | extern crate ra_syntax; | ||
6 | extern crate ra_editor; | 6 | extern crate ra_editor; |
7 | extern crate fst; | 7 | extern crate ra_syntax; |
8 | extern crate rayon; | 8 | extern crate rayon; |
9 | extern crate relative_path; | 9 | extern crate relative_path; |
10 | #[macro_use] | 10 | #[macro_use] |
11 | extern crate crossbeam_channel; | 11 | extern crate crossbeam_channel; |
12 | extern crate im; | 12 | extern crate im; |
13 | extern crate salsa; | ||
14 | extern crate rustc_hash; | 13 | extern crate rustc_hash; |
14 | extern crate salsa; | ||
15 | 15 | ||
16 | mod symbol_index; | 16 | mod db; |
17 | mod module_map; | 17 | mod descriptors; |
18 | mod imp; | 18 | mod imp; |
19 | mod job; | 19 | mod job; |
20 | mod module_map; | ||
20 | mod roots; | 21 | mod roots; |
21 | mod db; | 22 | mod symbol_index; |
22 | mod descriptors; | ||
23 | 23 | ||
24 | use std::{ | 24 | use std::{fmt::Debug, sync::Arc}; |
25 | sync::Arc, | ||
26 | fmt::Debug, | ||
27 | }; | ||
28 | 25 | ||
26 | use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}; | ||
27 | use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; | ||
29 | use relative_path::{RelativePath, RelativePathBuf}; | 28 | use relative_path::{RelativePath, RelativePathBuf}; |
30 | use ra_syntax::{File, TextRange, TextUnit, AtomEdit}; | ||
31 | use rustc_hash::FxHashMap; | 29 | use rustc_hash::FxHashMap; |
32 | use crate::imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp}; | ||
33 | 30 | ||
34 | pub use ra_editor::{ | ||
35 | StructureNode, LineIndex, FileSymbol, | ||
36 | Runnable, RunnableKind, HighlightedRange, CompletionItem, | ||
37 | Fold, FoldKind | ||
38 | }; | ||
39 | pub use crate::{ | 31 | pub use crate::{ |
40 | job::{JobToken, JobHandle}, | ||
41 | descriptors::FnDescriptor, | 32 | descriptors::FnDescriptor, |
33 | job::{JobHandle, JobToken}, | ||
34 | }; | ||
35 | pub use ra_editor::{ | ||
36 | CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, | ||
37 | RunnableKind, StructureNode, | ||
42 | }; | 38 | }; |
43 | 39 | ||
44 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 40 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
@@ -59,20 +55,24 @@ pub trait FileResolver: Debug + Send + Sync + 'static { | |||
59 | 55 | ||
60 | #[derive(Debug)] | 56 | #[derive(Debug)] |
61 | pub struct AnalysisHost { | 57 | pub struct AnalysisHost { |
62 | imp: AnalysisHostImpl | 58 | imp: AnalysisHostImpl, |
63 | } | 59 | } |
64 | 60 | ||
65 | impl AnalysisHost { | 61 | impl AnalysisHost { |
66 | pub fn new() -> AnalysisHost { | 62 | pub fn new() -> AnalysisHost { |
67 | AnalysisHost { imp: AnalysisHostImpl::new() } | 63 | AnalysisHost { |
64 | imp: AnalysisHostImpl::new(), | ||
65 | } | ||
68 | } | 66 | } |
69 | pub fn analysis(&self) -> Analysis { | 67 | pub fn analysis(&self) -> Analysis { |
70 | Analysis { imp: self.imp.analysis() } | 68 | Analysis { |
69 | imp: self.imp.analysis(), | ||
70 | } | ||
71 | } | 71 | } |
72 | pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { | 72 | pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { |
73 | self.change_files(::std::iter::once((file_id, text))); | 73 | self.change_files(::std::iter::once((file_id, text))); |
74 | } | 74 | } |
75 | pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { | 75 | pub fn change_files(&mut self, mut changes: impl Iterator<Item = (FileId, Option<String>)>) { |
76 | self.imp.change_files(&mut changes) | 76 | self.imp.change_files(&mut changes) |
77 | } | 77 | } |
78 | pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) { | 78 | pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) { |
@@ -115,7 +115,7 @@ pub enum FileSystemEdit { | |||
115 | MoveFile { | 115 | MoveFile { |
116 | file: FileId, | 116 | file: FileId, |
117 | path: RelativePathBuf, | 117 | path: RelativePathBuf, |
118 | } | 118 | }, |
119 | } | 119 | } |
120 | 120 | ||
121 | #[derive(Debug)] | 121 | #[derive(Debug)] |
@@ -144,7 +144,7 @@ impl Query { | |||
144 | only_types: false, | 144 | only_types: false, |
145 | libs: false, | 145 | libs: false, |
146 | exact: false, | 146 | exact: false, |
147 | limit: usize::max_value() | 147 | limit: usize::max_value(), |
148 | } | 148 | } |
149 | } | 149 | } |
150 | pub fn only_types(&mut self) { | 150 | pub fn only_types(&mut self) { |
@@ -163,7 +163,7 @@ impl Query { | |||
163 | 163 | ||
164 | #[derive(Debug)] | 164 | #[derive(Debug)] |
165 | pub struct Analysis { | 165 | pub struct Analysis { |
166 | imp: AnalysisImpl | 166 | imp: AnalysisImpl, |
167 | } | 167 | } |
168 | 168 | ||
169 | impl Analysis { | 169 | impl Analysis { |
@@ -195,7 +195,11 @@ impl Analysis { | |||
195 | } | 195 | } |
196 | pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { | 196 | pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { |
197 | let file = self.imp.file_syntax(file_id); | 197 | let file = self.imp.file_syntax(file_id); |
198 | Some(SourceChange::from_local_edit(file_id, "add semicolon", ra_editor::on_eq_typed(&file, offset)?)) | 198 | Some(SourceChange::from_local_edit( |
199 | file_id, | ||
200 | "add semicolon", | ||
201 | ra_editor::on_eq_typed(&file, offset)?, | ||
202 | )) | ||
199 | } | 203 | } |
200 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { | 204 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { |
201 | let file = self.imp.file_syntax(file_id); | 205 | let file = self.imp.file_syntax(file_id); |
@@ -204,8 +208,14 @@ impl Analysis { | |||
204 | pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 208 | pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
205 | self.imp.world_symbols(query, token) | 209 | self.imp.world_symbols(query, token) |
206 | } | 210 | } |
207 | pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 211 | pub fn approximately_resolve_symbol( |
208 | self.imp.approximately_resolve_symbol(file_id, offset, token) | 212 | &self, |
213 | file_id: FileId, | ||
214 | offset: TextUnit, | ||
215 | token: &JobToken, | ||
216 | ) -> Vec<(FileId, FileSymbol)> { | ||
217 | self.imp | ||
218 | .approximately_resolve_symbol(file_id, offset, token) | ||
209 | } | 219 | } |
210 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { | 220 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { |
211 | self.imp.parent_module(file_id) | 221 | self.imp.parent_module(file_id) |
@@ -239,15 +249,19 @@ impl Analysis { | |||
239 | ra_editor::folding_ranges(&file) | 249 | ra_editor::folding_ranges(&file) |
240 | } | 250 | } |
241 | 251 | ||
242 | pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken) | 252 | pub fn resolve_callable( |
243 | -> Option<(FnDescriptor, Option<usize>)> { | 253 | &self, |
254 | file_id: FileId, | ||
255 | offset: TextUnit, | ||
256 | token: &JobToken, | ||
257 | ) -> Option<(FnDescriptor, Option<usize>)> { | ||
244 | self.imp.resolve_callable(file_id, offset, token) | 258 | self.imp.resolve_callable(file_id, offset, token) |
245 | } | 259 | } |
246 | } | 260 | } |
247 | 261 | ||
248 | #[derive(Debug)] | 262 | #[derive(Debug)] |
249 | pub struct LibraryData { | 263 | pub struct LibraryData { |
250 | root: roots::ReadonlySourceRoot | 264 | root: roots::ReadonlySourceRoot, |
251 | } | 265 | } |
252 | 266 | ||
253 | impl LibraryData { | 267 | impl LibraryData { |
diff --git a/crates/ra_analysis/src/module_map.rs b/crates/ra_analysis/src/module_map.rs index c1799e3d4..ff0ec3cc7 100644 --- a/crates/ra_analysis/src/module_map.rs +++ b/crates/ra_analysis/src/module_map.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | use std::sync::Arc; | ||
2 | use crate::{ | 1 | use crate::{ |
3 | FileId, | 2 | db::SyntaxDatabase, |
4 | db::{SyntaxDatabase}, | ||
5 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | 3 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, |
4 | FileId, | ||
6 | }; | 5 | }; |
7 | 6 | ||
7 | use std::sync::Arc; | ||
8 | |||
8 | salsa::query_group! { | 9 | salsa::query_group! { |
9 | pub(crate) trait ModulesDatabase: SyntaxDatabase { | 10 | pub(crate) trait ModulesDatabase: SyntaxDatabase { |
10 | fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> { | 11 | fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> { |
@@ -16,7 +17,6 @@ salsa::query_group! { | |||
16 | } | 17 | } |
17 | } | 18 | } |
18 | 19 | ||
19 | |||
20 | fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { | 20 | fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { |
21 | let file = db.file_syntax(file_id); | 21 | let file = db.file_syntax(file_id); |
22 | Arc::new(ModuleDescriptor::new(file.ast())) | 22 | Arc::new(ModuleDescriptor::new(file.ast())) |
@@ -29,6 +29,9 @@ fn module_tree(db: &impl ModulesDatabase, (): ()) -> Arc<ModuleTreeDescriptor> { | |||
29 | let module_descr = db.module_descriptor(file_id); | 29 | let module_descr = db.module_descriptor(file_id); |
30 | files.push((file_id, module_descr)); | 30 | files.push((file_id, module_descr)); |
31 | } | 31 | } |
32 | let res = ModuleTreeDescriptor::new(files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.resolver); | 32 | let res = ModuleTreeDescriptor::new( |
33 | files.iter().map(|(file_id, descr)| (*file_id, &**descr)), | ||
34 | &file_set.resolver, | ||
35 | ); | ||
33 | Arc::new(res) | 36 | Arc::new(res) |
34 | } | 37 | } |
diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs index 76bcecd38..1f2b21b27 100644 --- a/crates/ra_analysis/src/roots.rs +++ b/crates/ra_analysis/src/roots.rs | |||
@@ -1,22 +1,19 @@ | |||
1 | use std::{ | 1 | use std::{panic, sync::Arc}; |
2 | sync::Arc, | ||
3 | panic, | ||
4 | }; | ||
5 | 2 | ||
6 | use once_cell::sync::OnceCell; | 3 | use once_cell::sync::OnceCell; |
7 | use rayon::prelude::*; | ||
8 | use salsa::Database; | ||
9 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
10 | use ra_editor::LineIndex; | 4 | use ra_editor::LineIndex; |
11 | use ra_syntax::File; | 5 | use ra_syntax::File; |
6 | use rayon::prelude::*; | ||
7 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
8 | use salsa::Database; | ||
12 | 9 | ||
13 | use crate::{ | 10 | use crate::{ |
14 | FileId, | ||
15 | imp::FileResolverImp, | ||
16 | symbol_index::SymbolIndex, | ||
17 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | ||
18 | db::{self, FilesDatabase, SyntaxDatabase}, | 11 | db::{self, FilesDatabase, SyntaxDatabase}, |
12 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | ||
13 | imp::FileResolverImp, | ||
19 | module_map::ModulesDatabase, | 14 | module_map::ModulesDatabase, |
15 | symbol_index::SymbolIndex, | ||
16 | FileId, | ||
20 | }; | 17 | }; |
21 | 18 | ||
22 | pub(crate) trait SourceRoot { | 19 | pub(crate) trait SourceRoot { |
@@ -35,7 +32,7 @@ pub(crate) struct WritableSourceRoot { | |||
35 | impl WritableSourceRoot { | 32 | impl WritableSourceRoot { |
36 | pub fn apply_changes( | 33 | pub fn apply_changes( |
37 | &mut self, | 34 | &mut self, |
38 | changes: &mut dyn Iterator<Item=(FileId, Option<String>)>, | 35 | changes: &mut dyn Iterator<Item = (FileId, Option<String>)>, |
39 | file_resolver: Option<FileResolverImp>, | 36 | file_resolver: Option<FileResolverImp>, |
40 | ) { | 37 | ) { |
41 | let mut changed = FxHashSet::default(); | 38 | let mut changed = FxHashSet::default(); |
@@ -46,22 +43,22 @@ impl WritableSourceRoot { | |||
46 | removed.insert(file_id); | 43 | removed.insert(file_id); |
47 | } | 44 | } |
48 | Some(text) => { | 45 | Some(text) => { |
49 | self.db.query(db::FileTextQuery) | 46 | self.db |
47 | .query(db::FileTextQuery) | ||
50 | .set(file_id, Arc::new(text)); | 48 | .set(file_id, Arc::new(text)); |
51 | changed.insert(file_id); | 49 | changed.insert(file_id); |
52 | } | 50 | } |
53 | } | 51 | } |
54 | } | 52 | } |
55 | let file_set = self.db.file_set(()); | 53 | let file_set = self.db.file_set(()); |
56 | let mut files: FxHashSet<FileId> = file_set | 54 | let mut files: FxHashSet<FileId> = file_set.files.clone(); |
57 | .files | ||
58 | .clone(); | ||
59 | for file_id in removed { | 55 | for file_id in removed { |
60 | files.remove(&file_id); | 56 | files.remove(&file_id); |
61 | } | 57 | } |
62 | files.extend(changed); | 58 | files.extend(changed); |
63 | let resolver = file_resolver.unwrap_or_else(|| file_set.resolver.clone()); | 59 | let resolver = file_resolver.unwrap_or_else(|| file_set.resolver.clone()); |
64 | self.db.query(db::FileSetQuery) | 60 | self.db |
61 | .query(db::FileSetQuery) | ||
65 | .set((), Arc::new(db::FileSet { files, resolver })); | 62 | .set((), Arc::new(db::FileSet { files, resolver })); |
66 | } | 63 | } |
67 | } | 64 | } |
@@ -71,9 +68,7 @@ impl SourceRoot for WritableSourceRoot { | |||
71 | self.db.module_tree(()) | 68 | self.db.module_tree(()) |
72 | } | 69 | } |
73 | fn contains(&self, file_id: FileId) -> bool { | 70 | fn contains(&self, file_id: FileId) -> bool { |
74 | self.db.file_set(()) | 71 | self.db.file_set(()).files.contains(&file_id) |
75 | .files | ||
76 | .contains(&file_id) | ||
77 | } | 72 | } |
78 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { | 73 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { |
79 | self.db.file_lines(file_id) | 74 | self.db.file_lines(file_id) |
@@ -83,7 +78,7 @@ impl SourceRoot for WritableSourceRoot { | |||
83 | } | 78 | } |
84 | fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) { | 79 | fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) { |
85 | let db = &self.db; | 80 | let db = &self.db; |
86 | let symbols = db.file_set(()); | 81 | let symbols = db.file_set(()); |
87 | let symbols = symbols | 82 | let symbols = symbols |
88 | .files | 83 | .files |
89 | .iter() | 84 | .iter() |
@@ -108,12 +103,15 @@ impl FileData { | |||
108 | } | 103 | } |
109 | } | 104 | } |
110 | fn lines(&self) -> &Arc<LineIndex> { | 105 | fn lines(&self) -> &Arc<LineIndex> { |
111 | self.lines.get_or_init(|| Arc::new(LineIndex::new(&self.text))) | 106 | self.lines |
107 | .get_or_init(|| Arc::new(LineIndex::new(&self.text))) | ||
112 | } | 108 | } |
113 | fn syntax(&self) -> &File { | 109 | fn syntax(&self) -> &File { |
114 | let text = &self.text; | 110 | let text = &self.text; |
115 | let syntax = &self.syntax; | 111 | let syntax = &self.syntax; |
116 | match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { | 112 | match panic::catch_unwind(panic::AssertUnwindSafe(|| { |
113 | syntax.get_or_init(|| File::parse(text)) | ||
114 | })) { | ||
117 | Ok(file) => file, | 115 | Ok(file) => file, |
118 | Err(err) => { | 116 | Err(err) => { |
119 | error!("Parser paniced on:\n------\n{}\n------\n", text); | 117 | error!("Parser paniced on:\n------\n{}\n------\n", text); |
@@ -131,22 +129,23 @@ pub(crate) struct ReadonlySourceRoot { | |||
131 | } | 129 | } |
132 | 130 | ||
133 | impl ReadonlySourceRoot { | 131 | impl ReadonlySourceRoot { |
134 | pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot { | 132 | pub(crate) fn new( |
135 | let modules = files.par_iter() | 133 | files: Vec<(FileId, String)>, |
134 | file_resolver: FileResolverImp, | ||
135 | ) -> ReadonlySourceRoot { | ||
136 | let modules = files | ||
137 | .par_iter() | ||
136 | .map(|(file_id, text)| { | 138 | .map(|(file_id, text)| { |
137 | let syntax = File::parse(text); | 139 | let syntax = File::parse(text); |
138 | let mod_descr = ModuleDescriptor::new(syntax.ast()); | 140 | let mod_descr = ModuleDescriptor::new(syntax.ast()); |
139 | (*file_id, syntax, mod_descr) | 141 | (*file_id, syntax, mod_descr) |
140 | }) | 142 | }) |
141 | .collect::<Vec<_>>(); | 143 | .collect::<Vec<_>>(); |
142 | let module_tree = ModuleTreeDescriptor::new( | 144 | let module_tree = |
143 | modules.iter().map(|it| (it.0, &it.2)), | 145 | ModuleTreeDescriptor::new(modules.iter().map(|it| (it.0, &it.2)), &file_resolver); |
144 | &file_resolver, | ||
145 | ); | ||
146 | 146 | ||
147 | let symbol_index = SymbolIndex::for_files( | 147 | let symbol_index = |
148 | modules.par_iter().map(|it| (it.0, it.1.clone())) | 148 | SymbolIndex::for_files(modules.par_iter().map(|it| (it.0, it.1.clone()))); |
149 | ); | ||
150 | let file_map: FxHashMap<FileId, FileData> = files | 149 | let file_map: FxHashMap<FileId, FileData> = files |
151 | .into_iter() | 150 | .into_iter() |
152 | .map(|(id, text)| (id, FileData::new(text))) | 151 | .map(|(id, text)| (id, FileData::new(text))) |
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 54672fde4..51eef8170 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs | |||
@@ -1,15 +1,16 @@ | |||
1 | use std::{ | 1 | use crate::{FileId, JobToken, Query}; |
2 | sync::Arc, | 2 | use fst::{self, Streamer}; |
3 | hash::{Hash, Hasher}, | 3 | use ra_editor::{file_symbols, FileSymbol}; |
4 | }; | ||
5 | use ra_editor::{FileSymbol, file_symbols}; | ||
6 | use ra_syntax::{ | 4 | use ra_syntax::{ |
7 | File, | 5 | File, |
8 | SyntaxKind::{self, *}, | 6 | SyntaxKind::{self, *}, |
9 | }; | 7 | }; |
10 | use fst::{self, Streamer}; | ||
11 | use rayon::prelude::*; | 8 | use rayon::prelude::*; |
12 | use crate::{Query, FileId, JobToken}; | 9 | |
10 | use std::{ | ||
11 | hash::{Hash, Hasher}, | ||
12 | sync::Arc, | ||
13 | }; | ||
13 | 14 | ||
14 | #[derive(Debug)] | 15 | #[derive(Debug)] |
15 | pub(crate) struct SymbolIndex { | 16 | pub(crate) struct SymbolIndex { |
@@ -23,8 +24,7 @@ impl PartialEq for SymbolIndex { | |||
23 | } | 24 | } |
24 | } | 25 | } |
25 | 26 | ||
26 | impl Eq for SymbolIndex { | 27 | impl Eq for SymbolIndex {} |
27 | } | ||
28 | 28 | ||
29 | impl Hash for SymbolIndex { | 29 | impl Hash for SymbolIndex { |
30 | fn hash<H: Hasher>(&self, hasher: &mut H) { | 30 | fn hash<H: Hasher>(&self, hasher: &mut H) { |
@@ -33,14 +33,12 @@ impl Hash for SymbolIndex { | |||
33 | } | 33 | } |
34 | 34 | ||
35 | impl SymbolIndex { | 35 | impl SymbolIndex { |
36 | pub(crate) fn for_files(files: impl ParallelIterator<Item=(FileId, File)>) -> SymbolIndex { | 36 | pub(crate) fn for_files(files: impl ParallelIterator<Item = (FileId, File)>) -> SymbolIndex { |
37 | let mut symbols = files | 37 | let mut symbols = files |
38 | .flat_map(|(file_id, file)| { | 38 | .flat_map(|(file_id, file)| { |
39 | file_symbols(&file) | 39 | file_symbols(&file) |
40 | .into_iter() | 40 | .into_iter() |
41 | .map(move |symbol| { | 41 | .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) |
42 | (symbol.name.as_str().to_lowercase(), (file_id, symbol)) | ||
43 | }) | ||
44 | .collect::<Vec<_>>() | 42 | .collect::<Vec<_>>() |
45 | }) | 43 | }) |
46 | .collect::<Vec<_>>(); | 44 | .collect::<Vec<_>>(); |
@@ -48,9 +46,7 @@ impl SymbolIndex { | |||
48 | symbols.dedup_by(|s1, s2| s1.0 == s2.0); | 46 | symbols.dedup_by(|s1, s2| s1.0 == s2.0); |
49 | let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = | 47 | let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = |
50 | symbols.into_iter().unzip(); | 48 | symbols.into_iter().unzip(); |
51 | let map = fst::Map::from_iter( | 49 | let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap(); |
52 | names.into_iter().zip(0u64..) | ||
53 | ).unwrap(); | ||
54 | SymbolIndex { symbols, map } | 50 | SymbolIndex { symbols, map } |
55 | } | 51 | } |
56 | 52 | ||
@@ -65,7 +61,6 @@ impl Query { | |||
65 | indices: &[Arc<SymbolIndex>], | 61 | indices: &[Arc<SymbolIndex>], |
66 | token: &JobToken, | 62 | token: &JobToken, |
67 | ) -> Vec<(FileId, FileSymbol)> { | 63 | ) -> Vec<(FileId, FileSymbol)> { |
68 | |||
69 | let mut op = fst::map::OpBuilder::new(); | 64 | let mut op = fst::map::OpBuilder::new(); |
70 | for file_symbols in indices.iter() { | 65 | for file_symbols in indices.iter() { |
71 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); | 66 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); |
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index 2d3679fa9..e0c637d65 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs | |||
@@ -1,32 +1,31 @@ | |||
1 | extern crate relative_path; | ||
2 | extern crate ra_analysis; | 1 | extern crate ra_analysis; |
3 | extern crate rustc_hash; | ||
4 | extern crate ra_editor; | 2 | extern crate ra_editor; |
5 | extern crate ra_syntax; | 3 | extern crate ra_syntax; |
4 | extern crate relative_path; | ||
5 | extern crate rustc_hash; | ||
6 | extern crate test_utils; | 6 | extern crate test_utils; |
7 | 7 | ||
8 | use std::{ | 8 | use std::sync::Arc; |
9 | sync::Arc, | ||
10 | }; | ||
11 | 9 | ||
12 | use rustc_hash::FxHashMap; | 10 | use ra_analysis::{ |
11 | Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle, | ||
12 | }; | ||
13 | use relative_path::{RelativePath, RelativePathBuf}; | 13 | use relative_path::{RelativePath, RelativePathBuf}; |
14 | use ra_analysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId, FnDescriptor}; | 14 | use rustc_hash::FxHashMap; |
15 | use test_utils::{assert_eq_dbg, extract_offset}; | 15 | use test_utils::{assert_eq_dbg, extract_offset}; |
16 | 16 | ||
17 | #[derive(Debug)] | 17 | #[derive(Debug)] |
18 | struct FileMap(Vec<(FileId, RelativePathBuf)>); | 18 | struct FileMap(Vec<(FileId, RelativePathBuf)>); |
19 | 19 | ||
20 | impl FileMap { | 20 | impl FileMap { |
21 | fn iter<'a>(&'a self) -> impl Iterator<Item=(FileId, &'a RelativePath)> + 'a { | 21 | fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a { |
22 | self.0.iter().map(|(id, path)| (*id, path.as_relative_path())) | 22 | self.0 |
23 | .iter() | ||
24 | .map(|(id, path)| (*id, path.as_relative_path())) | ||
23 | } | 25 | } |
24 | 26 | ||
25 | fn path(&self, id: FileId) -> &RelativePath { | 27 | fn path(&self, id: FileId) -> &RelativePath { |
26 | self.iter() | 28 | self.iter().find(|&(it, _)| it == id).unwrap().1 |
27 | .find(|&(it, _)| it == id) | ||
28 | .unwrap() | ||
29 | .1 | ||
30 | } | 29 | } |
31 | } | 30 | } |
32 | 31 | ||
@@ -71,10 +70,7 @@ fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) { | |||
71 | 70 | ||
72 | #[test] | 71 | #[test] |
73 | fn test_resolve_module() { | 72 | fn test_resolve_module() { |
74 | let snap = analysis(&[ | 73 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); |
75 | ("/lib.rs", "mod foo;"), | ||
76 | ("/foo.rs", "") | ||
77 | ]); | ||
78 | let (_handle, token) = JobHandle::new(); | 74 | let (_handle, token) = JobHandle::new(); |
79 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); | 75 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); |
80 | assert_eq_dbg( | 76 | assert_eq_dbg( |
@@ -82,10 +78,7 @@ fn test_resolve_module() { | |||
82 | &symbols, | 78 | &symbols, |
83 | ); | 79 | ); |
84 | 80 | ||
85 | let snap = analysis(&[ | 81 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]); |
86 | ("/lib.rs", "mod foo;"), | ||
87 | ("/foo/mod.rs", "") | ||
88 | ]); | ||
89 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); | 82 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); |
90 | assert_eq_dbg( | 83 | assert_eq_dbg( |
91 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, | 84 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, |
@@ -114,18 +107,12 @@ fn test_unresolved_module_diagnostic() { | |||
114 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { | 107 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { |
115 | let snap = analysis(&[("/lib.rs", "mod foo {}")]); | 108 | let snap = analysis(&[("/lib.rs", "mod foo {}")]); |
116 | let diagnostics = snap.diagnostics(FileId(1)); | 109 | let diagnostics = snap.diagnostics(FileId(1)); |
117 | assert_eq_dbg( | 110 | assert_eq_dbg(r#"[]"#, &diagnostics); |
118 | r#"[]"#, | ||
119 | &diagnostics, | ||
120 | ); | ||
121 | } | 111 | } |
122 | 112 | ||
123 | #[test] | 113 | #[test] |
124 | fn test_resolve_parent_module() { | 114 | fn test_resolve_parent_module() { |
125 | let snap = analysis(&[ | 115 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); |
126 | ("/lib.rs", "mod foo;"), | ||
127 | ("/foo.rs", ""), | ||
128 | ]); | ||
129 | let symbols = snap.parent_module(FileId(2)); | 116 | let symbols = snap.parent_module(FileId(2)); |
130 | assert_eq_dbg( | 117 | assert_eq_dbg( |
131 | r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, | 118 | r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, |
@@ -135,10 +122,7 @@ fn test_resolve_parent_module() { | |||
135 | 122 | ||
136 | #[test] | 123 | #[test] |
137 | fn test_resolve_crate_root() { | 124 | fn test_resolve_crate_root() { |
138 | let mut host = analysis_host(&[ | 125 | let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); |
139 | ("/lib.rs", "mod foo;"), | ||
140 | ("/foo.rs", ""), | ||
141 | ]); | ||
142 | let snap = host.analysis(); | 126 | let snap = host.analysis(); |
143 | assert!(snap.crate_for(FileId(2)).is_empty()); | 127 | assert!(snap.crate_for(FileId(2)).is_empty()); |
144 | 128 | ||
@@ -152,20 +136,18 @@ fn test_resolve_crate_root() { | |||
152 | host.set_crate_graph(crate_graph); | 136 | host.set_crate_graph(crate_graph); |
153 | let snap = host.analysis(); | 137 | let snap = host.analysis(); |
154 | 138 | ||
155 | assert_eq!( | 139 | assert_eq!(snap.crate_for(FileId(2)), vec![CrateId(1)],); |
156 | snap.crate_for(FileId(2)), | ||
157 | vec![CrateId(1)], | ||
158 | ); | ||
159 | } | 140 | } |
160 | 141 | ||
161 | #[test] | 142 | #[test] |
162 | fn test_fn_signature_two_args_first() { | 143 | fn test_fn_signature_two_args_first() { |
163 | let (desc, param) = get_signature( | 144 | let (desc, param) = get_signature( |
164 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 145 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} |
165 | fn bar() { foo(<|>3, ); }"#); | 146 | fn bar() { foo(<|>3, ); }"#, |
147 | ); | ||
166 | 148 | ||
167 | assert_eq!(desc.name, "foo".to_string()); | 149 | assert_eq!(desc.name, "foo".to_string()); |
168 | assert_eq!(desc.params, vec!("x".to_string(),"y".to_string())); | 150 | assert_eq!(desc.params, vec!("x".to_string(), "y".to_string())); |
169 | assert_eq!(desc.ret_type, Some("-> u32".into())); | 151 | assert_eq!(desc.ret_type, Some("-> u32".into())); |
170 | assert_eq!(param, Some(0)); | 152 | assert_eq!(param, Some(0)); |
171 | } | 153 | } |
@@ -174,10 +156,11 @@ fn bar() { foo(<|>3, ); }"#); | |||
174 | fn test_fn_signature_two_args_second() { | 156 | fn test_fn_signature_two_args_second() { |
175 | let (desc, param) = get_signature( | 157 | let (desc, param) = get_signature( |
176 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 158 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} |
177 | fn bar() { foo(3, <|>); }"#); | 159 | fn bar() { foo(3, <|>); }"#, |
160 | ); | ||
178 | 161 | ||
179 | assert_eq!(desc.name, "foo".to_string()); | 162 | assert_eq!(desc.name, "foo".to_string()); |
180 | assert_eq!(desc.params, vec!("x".to_string(),"y".to_string())); | 163 | assert_eq!(desc.params, vec!("x".to_string(), "y".to_string())); |
181 | assert_eq!(desc.ret_type, Some("-> u32".into())); | 164 | assert_eq!(desc.ret_type, Some("-> u32".into())); |
182 | assert_eq!(param, Some(1)); | 165 | assert_eq!(param, Some(1)); |
183 | } | 166 | } |
@@ -185,8 +168,9 @@ fn bar() { foo(3, <|>); }"#); | |||
185 | #[test] | 168 | #[test] |
186 | fn test_fn_signature_for_impl() { | 169 | fn test_fn_signature_for_impl() { |
187 | let (desc, param) = get_signature( | 170 | let (desc, param) = get_signature( |
188 | r#"struct F; impl F { pub fn new() { F{}} } | 171 | r#"struct F; impl F { pub fn new() { F{}} } |
189 | fn bar() {let _ : F = F::new(<|>);}"#); | 172 | fn bar() {let _ : F = F::new(<|>);}"#, |
173 | ); | ||
190 | 174 | ||
191 | assert_eq!(desc.name, "new".to_string()); | 175 | assert_eq!(desc.name, "new".to_string()); |
192 | assert_eq!(desc.params, Vec::<String>::new()); | 176 | assert_eq!(desc.params, Vec::<String>::new()); |
@@ -197,7 +181,7 @@ fn bar() {let _ : F = F::new(<|>);}"#); | |||
197 | #[test] | 181 | #[test] |
198 | fn test_fn_signature_for_method_self() { | 182 | fn test_fn_signature_for_method_self() { |
199 | let (desc, param) = get_signature( | 183 | let (desc, param) = get_signature( |
200 | r#"struct F; | 184 | r#"struct F; |
201 | impl F { | 185 | impl F { |
202 | pub fn new() -> F{ | 186 | pub fn new() -> F{ |
203 | F{} | 187 | F{} |
@@ -209,7 +193,8 @@ impl F { | |||
209 | fn bar() { | 193 | fn bar() { |
210 | let f : F = F::new(); | 194 | let f : F = F::new(); |
211 | f.do_it(<|>); | 195 | f.do_it(<|>); |
212 | }"#); | 196 | }"#, |
197 | ); | ||
213 | 198 | ||
214 | assert_eq!(desc.name, "do_it".to_string()); | 199 | assert_eq!(desc.name, "do_it".to_string()); |
215 | assert_eq!(desc.params, vec!["&self".to_string()]); | 200 | assert_eq!(desc.params, vec!["&self".to_string()]); |
@@ -220,7 +205,7 @@ fn bar() { | |||
220 | #[test] | 205 | #[test] |
221 | fn test_fn_signature_for_method_with_arg() { | 206 | fn test_fn_signature_for_method_with_arg() { |
222 | let (desc, param) = get_signature( | 207 | let (desc, param) = get_signature( |
223 | r#"struct F; | 208 | r#"struct F; |
224 | impl F { | 209 | impl F { |
225 | pub fn new() -> F{ | 210 | pub fn new() -> F{ |
226 | F{} | 211 | F{} |
@@ -232,7 +217,8 @@ impl F { | |||
232 | fn bar() { | 217 | fn bar() { |
233 | let f : F = F::new(); | 218 | let f : F = F::new(); |
234 | f.do_it(<|>); | 219 | f.do_it(<|>); |
235 | }"#); | 220 | }"#, |
221 | ); | ||
236 | 222 | ||
237 | assert_eq!(desc.name, "do_it".to_string()); | 223 | assert_eq!(desc.name, "do_it".to_string()); |
238 | assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]); | 224 | assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]); |
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 11605cfd8..239d846b3 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -2,19 +2,17 @@ extern crate clap; | |||
2 | #[macro_use] | 2 | #[macro_use] |
3 | extern crate failure; | 3 | extern crate failure; |
4 | extern crate join_to_string; | 4 | extern crate join_to_string; |
5 | extern crate ra_syntax; | ||
6 | extern crate ra_editor; | 5 | extern crate ra_editor; |
6 | extern crate ra_syntax; | ||
7 | extern crate tools; | 7 | extern crate tools; |
8 | 8 | ||
9 | use std::{ | 9 | use std::{fs, io::Read, path::Path, time::Instant}; |
10 | fs, io::Read, path::Path, | 10 | |
11 | time::Instant | ||
12 | }; | ||
13 | use clap::{App, Arg, SubCommand}; | 11 | use clap::{App, Arg, SubCommand}; |
14 | use join_to_string::join; | 12 | use join_to_string::join; |
13 | use ra_editor::{extend_selection, file_structure, syntax_tree}; | ||
14 | use ra_syntax::{File, TextRange}; | ||
15 | use tools::collect_tests; | 15 | use tools::collect_tests; |
16 | use ra_syntax::{TextRange, File}; | ||
17 | use ra_editor::{syntax_tree, file_structure, extend_selection}; | ||
18 | 16 | ||
19 | type Result<T> = ::std::result::Result<T, failure::Error>; | 17 | type Result<T> = ::std::result::Result<T, failure::Error>; |
20 | 18 | ||
@@ -36,14 +34,12 @@ fn main() -> Result<()> { | |||
36 | .takes_value(true), | 34 | .takes_value(true), |
37 | ), | 35 | ), |
38 | ) | 36 | ) |
39 | .subcommand( | 37 | .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) |
40 | SubCommand::with_name("parse") | ||
41 | .arg(Arg::with_name("no-dump").long("--no-dump")) | ||
42 | ) | ||
43 | .subcommand(SubCommand::with_name("symbols")) | 38 | .subcommand(SubCommand::with_name("symbols")) |
44 | .subcommand(SubCommand::with_name("extend-selection") | 39 | .subcommand( |
45 | .arg(Arg::with_name("start")) | 40 | SubCommand::with_name("extend-selection") |
46 | .arg(Arg::with_name("end")) | 41 | .arg(Arg::with_name("start")) |
42 | .arg(Arg::with_name("end")), | ||
47 | ) | 43 | ) |
48 | .get_matches(); | 44 | .get_matches(); |
49 | match matches.subcommand() { | 45 | match matches.subcommand() { |
@@ -116,7 +112,8 @@ fn selections(file: &File, start: u32, end: u32) -> String { | |||
116 | ranges.push(r); | 112 | ranges.push(r); |
117 | cur = extend_selection(&file, r); | 113 | cur = extend_selection(&file, r); |
118 | } | 114 | } |
119 | let ranges = ranges.iter() | 115 | let ranges = ranges |
116 | .iter() | ||
120 | .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end()))) | 117 | .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end()))) |
121 | .map(|(s, e)| format!("({} {})", s, e)); | 118 | .map(|(s, e)| format!("({} {})", s, e)); |
122 | join(ranges) | 119 | join(ranges) |
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs index 7b0a48c81..cadcd2720 100644 --- a/crates/ra_editor/src/code_actions.rs +++ b/crates/ra_editor/src/code_actions.rs | |||
@@ -1,17 +1,14 @@ | |||
1 | use join_to_string::join; | 1 | use join_to_string::join; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | File, TextUnit, TextRange, Direction, | 4 | algo::{find_covering_node, find_leaf_at_offset}, |
5 | ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner}, | 5 | ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, |
6 | Direction, File, | ||
6 | SyntaxKind::{COMMA, WHITESPACE}, | 7 | SyntaxKind::{COMMA, WHITESPACE}, |
7 | SyntaxNodeRef, | 8 | SyntaxNodeRef, TextRange, TextUnit, |
8 | algo::{ | ||
9 | find_leaf_at_offset, | ||
10 | find_covering_node, | ||
11 | }, | ||
12 | }; | 9 | }; |
13 | 10 | ||
14 | use crate::{EditBuilder, Edit, find_node_at_offset}; | 11 | use crate::{find_node_at_offset, Edit, EditBuilder}; |
15 | 12 | ||
16 | #[derive(Debug)] | 13 | #[derive(Debug)] |
17 | pub struct LocalEdit { | 14 | pub struct LocalEdit { |
@@ -52,9 +49,7 @@ pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() | |||
52 | edit.insert(node_start, "#[derive()]\n".to_string()); | 49 | edit.insert(node_start, "#[derive()]\n".to_string()); |
53 | node_start + TextUnit::of_str("#[derive(") | 50 | node_start + TextUnit::of_str("#[derive(") |
54 | } | 51 | } |
55 | Some(tt) => { | 52 | Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'), |
56 | tt.syntax().range().end() - TextUnit::of_char(')') | ||
57 | } | ||
58 | }; | 53 | }; |
59 | LocalEdit { | 54 | LocalEdit { |
60 | edit: edit.finish(), | 55 | edit: edit.finish(), |
@@ -74,14 +69,19 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> | |||
74 | let mut buf = String::new(); | 69 | let mut buf = String::new(); |
75 | buf.push_str("\n\nimpl"); | 70 | buf.push_str("\n\nimpl"); |
76 | if let Some(type_params) = type_params { | 71 | if let Some(type_params) = type_params { |
77 | type_params.syntax().text() | 72 | type_params.syntax().text().push_to(&mut buf); |
78 | .push_to(&mut buf); | ||
79 | } | 73 | } |
80 | buf.push_str(" "); | 74 | buf.push_str(" "); |
81 | buf.push_str(name.text().as_str()); | 75 | buf.push_str(name.text().as_str()); |
82 | if let Some(type_params) = type_params { | 76 | if let Some(type_params) = type_params { |
83 | let lifetime_params = type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text()); | 77 | let lifetime_params = type_params |
84 | let type_params = type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); | 78 | .lifetime_params() |
79 | .filter_map(|it| it.lifetime()) | ||
80 | .map(|it| it.text()); | ||
81 | let type_params = type_params | ||
82 | .type_params() | ||
83 | .filter_map(|it| it.name()) | ||
84 | .map(|it| it.text()); | ||
85 | join(lifetime_params.chain(type_params)) | 85 | join(lifetime_params.chain(type_params)) |
86 | .surround_with("<", ">") | 86 | .surround_with("<", ">") |
87 | .to_buf(&mut buf); | 87 | .to_buf(&mut buf); |
@@ -97,10 +97,17 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> | |||
97 | }) | 97 | }) |
98 | } | 98 | } |
99 | 99 | ||
100 | pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl FnOnce() -> LocalEdit + 'a> { | 100 | pub fn introduce_variable<'a>( |
101 | file: &'a File, | ||
102 | range: TextRange, | ||
103 | ) -> Option<impl FnOnce() -> LocalEdit + 'a> { | ||
101 | let node = find_covering_node(file.syntax(), range); | 104 | let node = find_covering_node(file.syntax(), range); |
102 | let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; | 105 | let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; |
103 | let anchor_stmt = expr.syntax().ancestors().filter_map(ast::Stmt::cast).next()?; | 106 | let anchor_stmt = expr |
107 | .syntax() | ||
108 | .ancestors() | ||
109 | .filter_map(ast::Stmt::cast) | ||
110 | .next()?; | ||
104 | let indent = anchor_stmt.syntax().prev_sibling()?; | 111 | let indent = anchor_stmt.syntax().prev_sibling()?; |
105 | if indent.kind() != WHITESPACE { | 112 | if indent.kind() != WHITESPACE { |
106 | return None; | 113 | return None; |
@@ -191,7 +198,8 @@ mod tests { | |||
191 | " | 198 | " |
192 | fn foo() { | 199 | fn foo() { |
193 | foo(<|>1 + 1<|>); | 200 | foo(<|>1 + 1<|>); |
194 | }", " | 201 | }", |
202 | " | ||
195 | fn foo() { | 203 | fn foo() { |
196 | let <|>var_name = 1 + 1; | 204 | let <|>var_name = 1 + 1; |
197 | foo(var_name); | 205 | foo(var_name); |
@@ -201,11 +209,12 @@ fn foo() { | |||
201 | } | 209 | } |
202 | #[test] | 210 | #[test] |
203 | fn test_intrdoduce_var_expr_stmt() { | 211 | fn test_intrdoduce_var_expr_stmt() { |
204 | check_action_range( | 212 | check_action_range( |
205 | " | 213 | " |
206 | fn foo() { | 214 | fn foo() { |
207 | <|>1 + 1<|>; | 215 | <|>1 + 1<|>; |
208 | }", " | 216 | }", |
217 | " | ||
209 | fn foo() { | 218 | fn foo() { |
210 | let <|>var_name = 1 + 1; | 219 | let <|>var_name = 1 + 1; |
211 | }", | 220 | }", |
diff --git a/crates/ra_editor/src/completion.rs b/crates/ra_editor/src/completion.rs index b6095dca9..86ef46ebd 100644 --- a/crates/ra_editor/src/completion.rs +++ b/crates/ra_editor/src/completion.rs | |||
@@ -1,17 +1,18 @@ | |||
1 | use rustc_hash::{FxHashMap, FxHashSet}; | 1 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*, | 4 | algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx}, |
5 | ast::{self, LoopBodyOwner, ModuleItemOwner}, | 5 | ast::{self, LoopBodyOwner, ModuleItemOwner}, |
6 | algo::{ | ||
7 | visit::{visitor, Visitor, visitor_ctx, VisitorCtx}, | ||
8 | }, | ||
9 | text_utils::is_subrange, | 6 | text_utils::is_subrange, |
7 | AstNode, File, | ||
8 | SyntaxKind::*, | ||
9 | SyntaxNodeRef, TextUnit, | ||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | AtomEdit, find_node_at_offset, | 13 | find_node_at_offset, |
14 | scope::{FnScopes, ModuleScope}, | 14 | scope::{FnScopes, ModuleScope}, |
15 | AtomEdit, | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | #[derive(Debug)] | 18 | #[derive(Debug)] |
@@ -21,7 +22,7 @@ pub struct CompletionItem { | |||
21 | /// What string is used for filtering, defaults to label | 22 | /// What string is used for filtering, defaults to label |
22 | pub lookup: Option<String>, | 23 | pub lookup: Option<String>, |
23 | /// What is inserted, defaults to label | 24 | /// What is inserted, defaults to label |
24 | pub snippet: Option<String> | 25 | pub snippet: Option<String>, |
25 | } | 26 | } |
26 | 27 | ||
27 | pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> { | 28 | pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> { |
@@ -40,7 +41,12 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI | |||
40 | param_completions(name_ref.syntax(), &mut res); | 41 | param_completions(name_ref.syntax(), &mut res); |
41 | } | 42 | } |
42 | let name_range = name_ref.syntax().range(); | 43 | let name_range = name_ref.syntax().range(); |
43 | let top_node = name_ref.syntax().ancestors().take_while(|it| it.range() == name_range).last().unwrap(); | 44 | let top_node = name_ref |
45 | .syntax() | ||
46 | .ancestors() | ||
47 | .take_while(|it| it.range() == name_range) | ||
48 | .last() | ||
49 | .unwrap(); | ||
44 | match top_node.parent().map(|it| it.kind()) { | 50 | match top_node.parent().map(|it| it.kind()) { |
45 | Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res), | 51 | Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res), |
46 | _ => (), | 52 | _ => (), |
@@ -68,21 +74,23 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<Completi | |||
68 | if let Some(items) = visitor() | 74 | if let Some(items) = visitor() |
69 | .visit::<ast::Root, _>(|it| Some(it.items())) | 75 | .visit::<ast::Root, _>(|it| Some(it.items())) |
70 | .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) | 76 | .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) |
71 | .accept(node) { | 77 | .accept(node) |
78 | { | ||
72 | if let Some(items) = items { | 79 | if let Some(items) = items { |
73 | let scope = ModuleScope::new(items); | 80 | let scope = ModuleScope::new(items); |
74 | acc.extend( | 81 | acc.extend( |
75 | scope.entries().iter() | 82 | scope |
83 | .entries() | ||
84 | .iter() | ||
76 | .filter(|entry| entry.syntax() != name_ref.syntax()) | 85 | .filter(|entry| entry.syntax() != name_ref.syntax()) |
77 | .map(|entry| CompletionItem { | 86 | .map(|entry| CompletionItem { |
78 | label: entry.name().to_string(), | 87 | label: entry.name().to_string(), |
79 | lookup: None, | 88 | lookup: None, |
80 | snippet: None, | 89 | snippet: None, |
81 | }) | 90 | }), |
82 | ); | 91 | ); |
83 | } | 92 | } |
84 | break; | 93 | break; |
85 | |||
86 | } else if !visited_fn { | 94 | } else if !visited_fn { |
87 | if let Some(fn_def) = ast::FnDef::cast(node) { | 95 | if let Some(fn_def) = ast::FnDef::cast(node) { |
88 | visited_fn = true; | 96 | visited_fn = true; |
@@ -103,26 +111,34 @@ fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) { | |||
103 | .visit::<ast::ItemList, _>(process) | 111 | .visit::<ast::ItemList, _>(process) |
104 | .accept(node); | 112 | .accept(node); |
105 | } | 113 | } |
106 | params.into_iter() | 114 | params |
115 | .into_iter() | ||
107 | .filter_map(|(label, (count, param))| { | 116 | .filter_map(|(label, (count, param))| { |
108 | let lookup = param.pat()?.syntax().text().to_string(); | 117 | let lookup = param.pat()?.syntax().text().to_string(); |
109 | if count < 2 { None } else { Some((label, lookup)) } | 118 | if count < 2 { |
119 | None | ||
120 | } else { | ||
121 | Some((label, lookup)) | ||
122 | } | ||
110 | }) | 123 | }) |
111 | .for_each(|(label, lookup)| { | 124 | .for_each(|(label, lookup)| { |
112 | acc.push(CompletionItem { | 125 | acc.push(CompletionItem { |
113 | label, lookup: Some(lookup), snippet: None | 126 | label, |
127 | lookup: Some(lookup), | ||
128 | snippet: None, | ||
114 | }) | 129 | }) |
115 | }); | 130 | }); |
116 | 131 | ||
117 | fn process<'a, N: ast::FnDefOwner<'a>>(node: N, params: &mut FxHashMap<String, (u32, ast::Param<'a>)>) { | 132 | fn process<'a, N: ast::FnDefOwner<'a>>( |
133 | node: N, | ||
134 | params: &mut FxHashMap<String, (u32, ast::Param<'a>)>, | ||
135 | ) { | ||
118 | node.functions() | 136 | node.functions() |
119 | .filter_map(|it| it.param_list()) | 137 | .filter_map(|it| it.param_list()) |
120 | .flat_map(|it| it.params()) | 138 | .flat_map(|it| it.params()) |
121 | .for_each(|param| { | 139 | .for_each(|param| { |
122 | let text = param.syntax().text().to_string(); | 140 | let text = param.syntax().text().to_string(); |
123 | params.entry(text) | 141 | params.entry(text).or_insert((0, param)).0 += 1; |
124 | .or_insert((0, param)) | ||
125 | .0 += 1; | ||
126 | }) | 142 | }) |
127 | } | 143 | } |
128 | } | 144 | } |
@@ -134,8 +150,12 @@ fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool { | |||
134 | } | 150 | } |
135 | } | 151 | } |
136 | 152 | ||
137 | 153 | fn complete_expr_keywords( | |
138 | fn complete_expr_keywords(file: &File, fn_def: ast::FnDef, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) { | 154 | file: &File, |
155 | fn_def: ast::FnDef, | ||
156 | name_ref: ast::NameRef, | ||
157 | acc: &mut Vec<CompletionItem>, | ||
158 | ) { | ||
139 | acc.push(keyword("if", "if $0 {}")); | 159 | acc.push(keyword("if", "if $0 {}")); |
140 | acc.push(keyword("match", "match $0 {}")); | 160 | acc.push(keyword("match", "match $0 {}")); |
141 | acc.push(keyword("while", "while $0 {}")); | 161 | acc.push(keyword("while", "while $0 {}")); |
@@ -186,9 +206,14 @@ fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<Complet | |||
186 | // return None; | 206 | // return None; |
187 | // } | 207 | // } |
188 | 208 | ||
189 | let is_stmt = match name_ref.syntax().ancestors().filter_map(ast::ExprStmt::cast).next() { | 209 | let is_stmt = match name_ref |
210 | .syntax() | ||
211 | .ancestors() | ||
212 | .filter_map(ast::ExprStmt::cast) | ||
213 | .next() | ||
214 | { | ||
190 | None => false, | 215 | None => false, |
191 | Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range() | 216 | Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(), |
192 | }; | 217 | }; |
193 | let snip = match (is_stmt, fn_def.ret_type().is_some()) { | 218 | let snip = match (is_stmt, fn_def.ret_type().is_some()) { |
194 | (true, true) => "return $0;", | 219 | (true, true) => "return $0;", |
@@ -209,39 +234,37 @@ fn keyword(kw: &str, snip: &str) -> CompletionItem { | |||
209 | 234 | ||
210 | fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) { | 235 | fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) { |
211 | acc.push(CompletionItem { | 236 | acc.push(CompletionItem { |
212 | label: "pd".to_string(), | 237 | label: "pd".to_string(), |
213 | lookup: None, | 238 | lookup: None, |
214 | snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()), | 239 | snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()), |
215 | } | 240 | }); |
216 | ); | ||
217 | acc.push(CompletionItem { | 241 | acc.push(CompletionItem { |
218 | label: "ppd".to_string(), | 242 | label: "ppd".to_string(), |
219 | lookup: None, | 243 | lookup: None, |
220 | snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()), | 244 | snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()), |
221 | } | 245 | }); |
222 | ); | ||
223 | } | 246 | } |
224 | 247 | ||
225 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { | 248 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { |
226 | acc.push(CompletionItem { | 249 | acc.push(CompletionItem { |
227 | label: "tfn".to_string(), | 250 | label: "tfn".to_string(), |
228 | lookup: None, | 251 | lookup: None, |
229 | snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()), | 252 | snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()), |
230 | } | 253 | }); |
231 | ); | ||
232 | } | 254 | } |
233 | 255 | ||
234 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | 256 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { |
235 | let mut shadowed = FxHashSet::default(); | 257 | let mut shadowed = FxHashSet::default(); |
236 | acc.extend( | 258 | acc.extend( |
237 | scopes.scope_chain(name_ref.syntax()) | 259 | scopes |
260 | .scope_chain(name_ref.syntax()) | ||
238 | .flat_map(|scope| scopes.entries(scope).iter()) | 261 | .flat_map(|scope| scopes.entries(scope).iter()) |
239 | .filter(|entry| shadowed.insert(entry.name())) | 262 | .filter(|entry| shadowed.insert(entry.name())) |
240 | .map(|entry| CompletionItem { | 263 | .map(|entry| CompletionItem { |
241 | label: entry.name().to_string(), | 264 | label: entry.name().to_string(), |
242 | lookup: None, | 265 | lookup: None, |
243 | snippet: None, | 266 | snippet: None, |
244 | }) | 267 | }), |
245 | ); | 268 | ); |
246 | if scopes.self_param.is_some() { | 269 | if scopes.self_param.is_some() { |
247 | acc.push(CompletionItem { | 270 | acc.push(CompletionItem { |
@@ -281,20 +304,24 @@ mod tests { | |||
281 | 304 | ||
282 | #[test] | 305 | #[test] |
283 | fn test_completion_let_scope() { | 306 | fn test_completion_let_scope() { |
284 | check_scope_completion(r" | 307 | check_scope_completion( |
308 | r" | ||
285 | fn quux(x: i32) { | 309 | fn quux(x: i32) { |
286 | let y = 92; | 310 | let y = 92; |
287 | 1 + <|>; | 311 | 1 + <|>; |
288 | let z = (); | 312 | let z = (); |
289 | } | 313 | } |
290 | ", r#"[CompletionItem { label: "y", lookup: None, snippet: None }, | 314 | ", |
315 | r#"[CompletionItem { label: "y", lookup: None, snippet: None }, | ||
291 | CompletionItem { label: "x", lookup: None, snippet: None }, | 316 | CompletionItem { label: "x", lookup: None, snippet: None }, |
292 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#); | 317 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, |
318 | ); | ||
293 | } | 319 | } |
294 | 320 | ||
295 | #[test] | 321 | #[test] |
296 | fn test_completion_if_let_scope() { | 322 | fn test_completion_if_let_scope() { |
297 | check_scope_completion(r" | 323 | check_scope_completion( |
324 | r" | ||
298 | fn quux() { | 325 | fn quux() { |
299 | if let Some(x) = foo() { | 326 | if let Some(x) = foo() { |
300 | let y = 92; | 327 | let y = 92; |
@@ -304,67 +331,85 @@ mod tests { | |||
304 | 1 + <|> | 331 | 1 + <|> |
305 | } | 332 | } |
306 | } | 333 | } |
307 | ", r#"[CompletionItem { label: "b", lookup: None, snippet: None }, | 334 | ", |
335 | r#"[CompletionItem { label: "b", lookup: None, snippet: None }, | ||
308 | CompletionItem { label: "a", lookup: None, snippet: None }, | 336 | CompletionItem { label: "a", lookup: None, snippet: None }, |
309 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#); | 337 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, |
338 | ); | ||
310 | } | 339 | } |
311 | 340 | ||
312 | #[test] | 341 | #[test] |
313 | fn test_completion_for_scope() { | 342 | fn test_completion_for_scope() { |
314 | check_scope_completion(r" | 343 | check_scope_completion( |
344 | r" | ||
315 | fn quux() { | 345 | fn quux() { |
316 | for x in &[1, 2, 3] { | 346 | for x in &[1, 2, 3] { |
317 | <|> | 347 | <|> |
318 | } | 348 | } |
319 | } | 349 | } |
320 | ", r#"[CompletionItem { label: "x", lookup: None, snippet: None }, | 350 | ", |
321 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#); | 351 | r#"[CompletionItem { label: "x", lookup: None, snippet: None }, |
352 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
353 | ); | ||
322 | } | 354 | } |
323 | 355 | ||
324 | #[test] | 356 | #[test] |
325 | fn test_completion_mod_scope() { | 357 | fn test_completion_mod_scope() { |
326 | check_scope_completion(r" | 358 | check_scope_completion( |
359 | r" | ||
327 | struct Foo; | 360 | struct Foo; |
328 | enum Baz {} | 361 | enum Baz {} |
329 | fn quux() { | 362 | fn quux() { |
330 | <|> | 363 | <|> |
331 | } | 364 | } |
332 | ", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, | 365 | ", |
366 | r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, | ||
333 | CompletionItem { label: "Baz", lookup: None, snippet: None }, | 367 | CompletionItem { label: "Baz", lookup: None, snippet: None }, |
334 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#); | 368 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, |
369 | ); | ||
335 | } | 370 | } |
336 | 371 | ||
337 | #[test] | 372 | #[test] |
338 | fn test_completion_mod_scope_no_self_use() { | 373 | fn test_completion_mod_scope_no_self_use() { |
339 | check_scope_completion(r" | 374 | check_scope_completion( |
375 | r" | ||
340 | use foo<|>; | 376 | use foo<|>; |
341 | ", r#"[]"#); | 377 | ", |
378 | r#"[]"#, | ||
379 | ); | ||
342 | } | 380 | } |
343 | 381 | ||
344 | #[test] | 382 | #[test] |
345 | fn test_completion_mod_scope_nested() { | 383 | fn test_completion_mod_scope_nested() { |
346 | check_scope_completion(r" | 384 | check_scope_completion( |
385 | r" | ||
347 | struct Foo; | 386 | struct Foo; |
348 | mod m { | 387 | mod m { |
349 | struct Bar; | 388 | struct Bar; |
350 | fn quux() { <|> } | 389 | fn quux() { <|> } |
351 | } | 390 | } |
352 | ", r#"[CompletionItem { label: "Bar", lookup: None, snippet: None }, | 391 | ", |
353 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#); | 392 | r#"[CompletionItem { label: "Bar", lookup: None, snippet: None }, |
393 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
394 | ); | ||
354 | } | 395 | } |
355 | 396 | ||
356 | #[test] | 397 | #[test] |
357 | fn test_complete_type() { | 398 | fn test_complete_type() { |
358 | check_scope_completion(r" | 399 | check_scope_completion( |
400 | r" | ||
359 | struct Foo; | 401 | struct Foo; |
360 | fn x() -> <|> | 402 | fn x() -> <|> |
361 | ", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, | 403 | ", |
362 | CompletionItem { label: "x", lookup: None, snippet: None }]"#) | 404 | r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, |
405 | CompletionItem { label: "x", lookup: None, snippet: None }]"#, | ||
406 | ) | ||
363 | } | 407 | } |
364 | 408 | ||
365 | #[test] | 409 | #[test] |
366 | fn test_complete_shadowing() { | 410 | fn test_complete_shadowing() { |
367 | check_scope_completion(r" | 411 | check_scope_completion( |
412 | r" | ||
368 | fn foo() -> { | 413 | fn foo() -> { |
369 | let bar = 92; | 414 | let bar = 92; |
370 | { | 415 | { |
@@ -372,15 +417,20 @@ mod tests { | |||
372 | <|> | 417 | <|> |
373 | } | 418 | } |
374 | } | 419 | } |
375 | ", r#"[CompletionItem { label: "bar", lookup: None, snippet: None }, | 420 | ", |
376 | CompletionItem { label: "foo", lookup: None, snippet: None }]"#) | 421 | r#"[CompletionItem { label: "bar", lookup: None, snippet: None }, |
422 | CompletionItem { label: "foo", lookup: None, snippet: None }]"#, | ||
423 | ) | ||
377 | } | 424 | } |
378 | 425 | ||
379 | #[test] | 426 | #[test] |
380 | fn test_complete_self() { | 427 | fn test_complete_self() { |
381 | check_scope_completion(r" | 428 | check_scope_completion( |
429 | r" | ||
382 | impl S { fn foo(&self) { <|> } } | 430 | impl S { fn foo(&self) { <|> } } |
383 | ", r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#) | 431 | ", |
432 | r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#, | ||
433 | ) | ||
384 | } | 434 | } |
385 | 435 | ||
386 | #[test] | 436 | #[test] |
diff --git a/crates/ra_editor/src/edit.rs b/crates/ra_editor/src/edit.rs index 46e687319..c3149ec54 100644 --- a/crates/ra_editor/src/edit.rs +++ b/crates/ra_editor/src/edit.rs | |||
@@ -1,8 +1,5 @@ | |||
1 | use crate::{TextRange, TextUnit}; | 1 | use crate::{TextRange, TextUnit}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{text_utils::contains_offset_nonstrict, AtomEdit}; |
3 | AtomEdit, | ||
4 | text_utils::contains_offset_nonstrict, | ||
5 | }; | ||
6 | 3 | ||
7 | #[derive(Debug, Clone)] | 4 | #[derive(Debug, Clone)] |
8 | pub struct Edit { | 5 | pub struct Edit { |
@@ -11,7 +8,7 @@ pub struct Edit { | |||
11 | 8 | ||
12 | #[derive(Debug)] | 9 | #[derive(Debug)] |
13 | pub struct EditBuilder { | 10 | pub struct EditBuilder { |
14 | atoms: Vec<AtomEdit> | 11 | atoms: Vec<AtomEdit>, |
15 | } | 12 | } |
16 | 13 | ||
17 | impl EditBuilder { | 14 | impl EditBuilder { |
@@ -36,7 +33,9 @@ impl EditBuilder { | |||
36 | Edit { atoms } | 33 | Edit { atoms } |
37 | } | 34 | } |
38 | pub fn invalidates_offset(&self, offset: TextUnit) -> bool { | 35 | pub fn invalidates_offset(&self, offset: TextUnit) -> bool { |
39 | self.atoms.iter().any(|atom| contains_offset_nonstrict(atom.delete, offset)) | 36 | self.atoms |
37 | .iter() | ||
38 | .any(|atom| contains_offset_nonstrict(atom.delete, offset)) | ||
40 | } | 39 | } |
41 | } | 40 | } |
42 | 41 | ||
@@ -74,7 +73,7 @@ impl Edit { | |||
74 | break; | 73 | break; |
75 | } | 74 | } |
76 | if offset < atom.delete.end() { | 75 | if offset < atom.delete.end() { |
77 | return None | 76 | return None; |
78 | } | 77 | } |
79 | res += TextUnit::of_str(&atom.insert); | 78 | res += TextUnit::of_str(&atom.insert); |
80 | res -= atom.delete.len(); | 79 | res -= atom.delete.len(); |
diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs index ab03a717e..9ee1df281 100644 --- a/crates/ra_editor/src/extend_selection.rs +++ b/crates/ra_editor/src/extend_selection.rs | |||
@@ -1,7 +1,8 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | File, TextRange, SyntaxNodeRef, TextUnit, Direction, | 2 | algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, |
3 | Direction, File, | ||
3 | SyntaxKind::*, | 4 | SyntaxKind::*, |
4 | algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node}, | 5 | SyntaxNodeRef, TextRange, TextUnit, |
5 | }; | 6 | }; |
6 | 7 | ||
7 | pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { | 8 | pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { |
@@ -20,11 +21,11 @@ pub(crate) fn extend(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> | |||
20 | LeafAtOffset::None => return None, | 21 | LeafAtOffset::None => return None, |
21 | LeafAtOffset::Single(l) => { | 22 | LeafAtOffset::Single(l) => { |
22 | if l.kind() == COMMENT { | 23 | if l.kind() == COMMENT { |
23 | extend_single_word_in_comment(l, offset).unwrap_or_else(||l.range()) | 24 | extend_single_word_in_comment(l, offset).unwrap_or_else(|| l.range()) |
24 | } else { | 25 | } else { |
25 | l.range() | 26 | l.range() |
26 | } | 27 | } |
27 | }, | 28 | } |
28 | LeafAtOffset::Between(l, r) => pick_best(l, r).range(), | 29 | LeafAtOffset::Between(l, r) => pick_best(l, r).range(), |
29 | }; | 30 | }; |
30 | return Some(leaf_range); | 31 | return Some(leaf_range); |
@@ -66,7 +67,7 @@ fn extend_ws(root: SyntaxNodeRef, ws: SyntaxNodeRef, offset: TextUnit) -> TextRa | |||
66 | if let Some(node) = ws.next_sibling() { | 67 | if let Some(node) = ws.next_sibling() { |
67 | let start = match ws_prefix.rfind('\n') { | 68 | let start = match ws_prefix.rfind('\n') { |
68 | Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32), | 69 | Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32), |
69 | None => node.range().start() | 70 | None => node.range().start(), |
70 | }; | 71 | }; |
71 | let end = if root.text().char_at(node.range().end()) == Some('\n') { | 72 | let end = if root.text().char_at(node.range().end()) == Some('\n') { |
72 | node.range().end() + TextUnit::of_char('\n') | 73 | node.range().end() + TextUnit::of_char('\n') |
@@ -94,10 +95,7 @@ fn extend_comments(node: SyntaxNodeRef) -> Option<TextRange> { | |||
94 | let prev = adj_comments(node, Direction::Prev); | 95 | let prev = adj_comments(node, Direction::Prev); |
95 | let next = adj_comments(node, Direction::Next); | 96 | let next = adj_comments(node, Direction::Next); |
96 | if prev != next { | 97 | if prev != next { |
97 | Some(TextRange::from_to( | 98 | Some(TextRange::from_to(prev.range().start(), next.range().end())) |
98 | prev.range().start(), | ||
99 | next.range().end(), | ||
100 | )) | ||
101 | } else { | 99 | } else { |
102 | None | 100 | None |
103 | } | 101 | } |
@@ -109,7 +107,7 @@ fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef { | |||
109 | match node.kind() { | 107 | match node.kind() { |
110 | COMMENT => res = node, | 108 | COMMENT => res = node, |
111 | WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), | 109 | WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), |
112 | _ => break | 110 | _ => break, |
113 | } | 111 | } |
114 | } | 112 | } |
115 | res | 113 | res |
@@ -125,8 +123,7 @@ mod tests { | |||
125 | let file = File::parse(&before); | 123 | let file = File::parse(&before); |
126 | let mut range = TextRange::offset_len(cursor, 0.into()); | 124 | let mut range = TextRange::offset_len(cursor, 0.into()); |
127 | for &after in afters { | 125 | for &after in afters { |
128 | range = extend_selection(&file, range) | 126 | range = extend_selection(&file, range).unwrap(); |
129 | .unwrap(); | ||
130 | let actual = &before[range]; | 127 | let actual = &before[range]; |
131 | assert_eq!(after, actual); | 128 | assert_eq!(after, actual); |
132 | } | 129 | } |
@@ -134,10 +131,7 @@ mod tests { | |||
134 | 131 | ||
135 | #[test] | 132 | #[test] |
136 | fn test_extend_selection_arith() { | 133 | fn test_extend_selection_arith() { |
137 | do_check( | 134 | do_check(r#"fn foo() { <|>1 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]); |
138 | r#"fn foo() { <|>1 + 1 }"#, | ||
139 | &["1", "1 + 1", "{ 1 + 1 }"], | ||
140 | ); | ||
141 | } | 135 | } |
142 | 136 | ||
143 | #[test] | 137 | #[test] |
@@ -149,7 +143,7 @@ impl S { | |||
149 | 143 | ||
150 | } | 144 | } |
151 | }"#, | 145 | }"#, |
152 | &[" fn foo() {\n\n }\n"] | 146 | &[" fn foo() {\n\n }\n"], |
153 | ); | 147 | ); |
154 | } | 148 | } |
155 | 149 | ||
@@ -165,7 +159,11 @@ struct B { | |||
165 | <|> | 159 | <|> |
166 | } | 160 | } |
167 | "#, | 161 | "#, |
168 | &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"] | 162 | &[ |
163 | "\n \n", | ||
164 | "{\n \n}", | ||
165 | "/// bla\n/// bla\nstruct B {\n \n}", | ||
166 | ], | ||
169 | ) | 167 | ) |
170 | } | 168 | } |
171 | 169 | ||
@@ -181,7 +179,7 @@ fn bar(){} | |||
181 | 179 | ||
182 | // fn foo(){} | 180 | // fn foo(){} |
183 | "#, | 181 | "#, |
184 | &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"] | 182 | &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"], |
185 | ); | 183 | ); |
186 | } | 184 | } |
187 | 185 | ||
@@ -191,42 +189,34 @@ fn bar(){} | |||
191 | r#" | 189 | r#" |
192 | fn main() { foo<|>+bar;} | 190 | fn main() { foo<|>+bar;} |
193 | "#, | 191 | "#, |
194 | &["foo", "foo+bar"] | 192 | &["foo", "foo+bar"], |
195 | ); | 193 | ); |
196 | do_check( | 194 | do_check( |
197 | r#" | 195 | r#" |
198 | fn main() { foo+<|>bar;} | 196 | fn main() { foo+<|>bar;} |
199 | "#, | 197 | "#, |
200 | &["bar", "foo+bar"] | 198 | &["bar", "foo+bar"], |
201 | ); | 199 | ); |
202 | } | 200 | } |
203 | 201 | ||
204 | #[test] | 202 | #[test] |
205 | fn test_extend_selection_prefer_lifetimes() { | 203 | fn test_extend_selection_prefer_lifetimes() { |
206 | do_check( | 204 | do_check(r#"fn foo<<|>'a>() {}"#, &["'a", "<'a>"]); |
207 | r#"fn foo<<|>'a>() {}"#, | 205 | do_check(r#"fn foo<'a<|>>() {}"#, &["'a", "<'a>"]); |
208 | &["'a", "<'a>"] | ||
209 | ); | ||
210 | do_check( | ||
211 | r#"fn foo<'a<|>>() {}"#, | ||
212 | &["'a", "<'a>"] | ||
213 | ); | ||
214 | } | 206 | } |
215 | 207 | ||
216 | #[test] | 208 | #[test] |
217 | fn test_extend_selection_select_first_word() { | 209 | fn test_extend_selection_select_first_word() { |
210 | do_check(r#"// foo bar b<|>az quxx"#, &["baz", "// foo bar baz quxx"]); | ||
218 | do_check( | 211 | do_check( |
219 | r#"// foo bar b<|>az quxx"#, | 212 | r#" |
220 | &["baz", "// foo bar baz quxx"] | ||
221 | ); | ||
222 | do_check(r#" | ||
223 | impl S { | 213 | impl S { |
224 | fn foo() { | 214 | fn foo() { |
225 | // hel<|>lo world | 215 | // hel<|>lo world |
226 | } | 216 | } |
227 | } | 217 | } |
228 | "#, | 218 | "#, |
229 | &["hello", "// hello world"] | 219 | &["hello", "// hello world"], |
230 | ); | 220 | ); |
231 | } | 221 | } |
232 | } | 222 | } |
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs index a1699d449..e5bc0c4ee 100644 --- a/crates/ra_editor/src/folding_ranges.rs +++ b/crates/ra_editor/src/folding_ranges.rs | |||
@@ -1,11 +1,9 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast, | 4 | ast, AstNode, Direction, File, |
5 | AstNode, | ||
6 | File, TextRange, SyntaxNodeRef, | ||
7 | SyntaxKind::{self, *}, | 5 | SyntaxKind::{self, *}, |
8 | Direction, | 6 | SyntaxNodeRef, TextRange, |
9 | }; | 7 | }; |
10 | 8 | ||
11 | #[derive(Debug, PartialEq, Eq)] | 9 | #[derive(Debug, PartialEq, Eq)] |
@@ -28,7 +26,10 @@ pub fn folding_ranges(file: &File) -> Vec<Fold> { | |||
28 | // Fold items that span multiple lines | 26 | // Fold items that span multiple lines |
29 | if let Some(kind) = fold_kind(node.kind()) { | 27 | if let Some(kind) = fold_kind(node.kind()) { |
30 | if has_newline(node) { | 28 | if has_newline(node) { |
31 | res.push(Fold { range: node.range(), kind }); | 29 | res.push(Fold { |
30 | range: node.range(), | ||
31 | kind, | ||
32 | }); | ||
32 | } | 33 | } |
33 | } | 34 | } |
34 | 35 | ||
@@ -37,8 +38,12 @@ pub fn folding_ranges(file: &File) -> Vec<Fold> { | |||
37 | continue; | 38 | continue; |
38 | } | 39 | } |
39 | if node.kind() == COMMENT { | 40 | if node.kind() == COMMENT { |
40 | contiguous_range_for_comment(node, &mut visited_comments) | 41 | contiguous_range_for_comment(node, &mut visited_comments).map(|range| { |
41 | .map(|range| res.push(Fold { range, kind: FoldKind::Comment })); | 42 | res.push(Fold { |
43 | range, | ||
44 | kind: FoldKind::Comment, | ||
45 | }) | ||
46 | }); | ||
42 | } | 47 | } |
43 | } | 48 | } |
44 | 49 | ||
@@ -49,13 +54,11 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { | |||
49 | match kind { | 54 | match kind { |
50 | COMMENT => Some(FoldKind::Comment), | 55 | COMMENT => Some(FoldKind::Comment), |
51 | USE_ITEM => Some(FoldKind::Imports), | 56 | USE_ITEM => Some(FoldKind::Imports), |
52 | _ => None | 57 | _ => None, |
53 | } | 58 | } |
54 | } | 59 | } |
55 | 60 | ||
56 | fn has_newline( | 61 | fn has_newline(node: SyntaxNodeRef) -> bool { |
57 | node: SyntaxNodeRef, | ||
58 | ) -> bool { | ||
59 | for descendant in node.descendants() { | 62 | for descendant in node.descendants() { |
60 | if let Some(ws) = ast::Whitespace::cast(descendant) { | 63 | if let Some(ws) = ast::Whitespace::cast(descendant) { |
61 | if ws.has_newlines() { | 64 | if ws.has_newlines() { |
@@ -100,9 +103,7 @@ fn contiguous_range_for_comment<'a>( | |||
100 | // The comment group ends because either: | 103 | // The comment group ends because either: |
101 | // * An element of a different kind was reached | 104 | // * An element of a different kind was reached |
102 | // * A comment of a different flavor was reached | 105 | // * A comment of a different flavor was reached |
103 | _ => { | 106 | _ => break, |
104 | break | ||
105 | } | ||
106 | } | 107 | } |
107 | } | 108 | } |
108 | 109 | ||
@@ -128,7 +129,11 @@ mod tests { | |||
128 | let folds = folding_ranges(&file); | 129 | let folds = folding_ranges(&file); |
129 | 130 | ||
130 | assert_eq!(folds.len(), ranges.len()); | 131 | assert_eq!(folds.len(), ranges.len()); |
131 | for ((fold, range), fold_kind) in folds.into_iter().zip(ranges.into_iter()).zip(fold_kinds.into_iter()) { | 132 | for ((fold, range), fold_kind) in folds |
133 | .into_iter() | ||
134 | .zip(ranges.into_iter()) | ||
135 | .zip(fold_kinds.into_iter()) | ||
136 | { | ||
132 | assert_eq!(fold.range.start(), range.start()); | 137 | assert_eq!(fold.range.start(), range.start()); |
133 | assert_eq!(fold.range.end(), range.end()); | 138 | assert_eq!(fold.range.end(), range.end()); |
134 | assert_eq!(&fold.kind, fold_kind); | 139 | assert_eq!(&fold.kind, fold_kind); |
@@ -181,5 +186,4 @@ fn main() { | |||
181 | do_check(text, folds); | 186 | do_check(text, folds); |
182 | } | 187 | } |
183 | 188 | ||
184 | |||
185 | } | 189 | } |
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs index bd61fd191..417080d90 100644 --- a/crates/ra_editor/src/lib.rs +++ b/crates/ra_editor/src/lib.rs | |||
@@ -1,44 +1,41 @@ | |||
1 | extern crate ra_syntax; | ||
2 | extern crate superslice; | ||
3 | extern crate itertools; | 1 | extern crate itertools; |
4 | extern crate join_to_string; | 2 | extern crate join_to_string; |
3 | extern crate ra_syntax; | ||
5 | extern crate rustc_hash; | 4 | extern crate rustc_hash; |
5 | extern crate superslice; | ||
6 | #[cfg(test)] | 6 | #[cfg(test)] |
7 | #[macro_use] | 7 | #[macro_use] |
8 | extern crate test_utils as _test_utils; | 8 | extern crate test_utils as _test_utils; |
9 | 9 | ||
10 | mod extend_selection; | ||
11 | mod symbols; | ||
12 | mod line_index; | ||
13 | mod edit; | ||
14 | mod folding_ranges; | ||
15 | mod code_actions; | 10 | mod code_actions; |
16 | mod typing; | ||
17 | mod completion; | 11 | mod completion; |
12 | mod edit; | ||
13 | mod extend_selection; | ||
14 | mod folding_ranges; | ||
15 | mod line_index; | ||
18 | mod scope; | 16 | mod scope; |
17 | mod symbols; | ||
19 | #[cfg(test)] | 18 | #[cfg(test)] |
20 | mod test_utils; | 19 | mod test_utils; |
20 | mod typing; | ||
21 | 21 | ||
22 | pub use self::{ | ||
23 | code_actions::{add_derive, add_impl, flip_comma, introduce_variable, LocalEdit}, | ||
24 | completion::{scope_completion, CompletionItem}, | ||
25 | edit::{Edit, EditBuilder}, | ||
26 | extend_selection::extend_selection, | ||
27 | folding_ranges::{folding_ranges, Fold, FoldKind}, | ||
28 | line_index::{LineCol, LineIndex}, | ||
29 | symbols::{file_structure, file_symbols, FileSymbol, StructureNode}, | ||
30 | typing::{join_lines, on_enter, on_eq_typed}, | ||
31 | }; | ||
32 | pub use ra_syntax::AtomEdit; | ||
22 | use ra_syntax::{ | 33 | use ra_syntax::{ |
23 | File, TextUnit, TextRange, SmolStr, SyntaxNodeRef, | ||
24 | ast::{self, AstNode, NameOwner}, | ||
25 | algo::find_leaf_at_offset, | 34 | algo::find_leaf_at_offset, |
35 | ast::{self, AstNode, NameOwner}, | ||
36 | File, SmolStr, | ||
26 | SyntaxKind::{self, *}, | 37 | SyntaxKind::{self, *}, |
27 | }; | 38 | SyntaxNodeRef, TextRange, TextUnit, |
28 | pub use ra_syntax::AtomEdit; | ||
29 | pub use self::{ | ||
30 | line_index::{LineIndex, LineCol}, | ||
31 | extend_selection::extend_selection, | ||
32 | symbols::{StructureNode, file_structure, FileSymbol, file_symbols}, | ||
33 | edit::{EditBuilder, Edit}, | ||
34 | code_actions::{ | ||
35 | LocalEdit, | ||
36 | flip_comma, add_derive, add_impl, | ||
37 | introduce_variable, | ||
38 | }, | ||
39 | typing::{join_lines, on_eq_typed, on_enter}, | ||
40 | completion::{scope_completion, CompletionItem}, | ||
41 | folding_ranges::{Fold, FoldKind, folding_ranges} | ||
42 | }; | 39 | }; |
43 | 40 | ||
44 | #[derive(Debug)] | 41 | #[derive(Debug)] |
@@ -67,10 +64,7 @@ pub enum RunnableKind { | |||
67 | 64 | ||
68 | pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { | 65 | pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { |
69 | const BRACES: &[SyntaxKind] = &[ | 66 | const BRACES: &[SyntaxKind] = &[ |
70 | L_CURLY, R_CURLY, | 67 | L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE, |
71 | L_BRACK, R_BRACK, | ||
72 | L_PAREN, R_PAREN, | ||
73 | L_ANGLE, R_ANGLE, | ||
74 | ]; | 68 | ]; |
75 | let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset) | 69 | let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset) |
76 | .filter_map(|node| { | 70 | .filter_map(|node| { |
@@ -80,7 +74,8 @@ pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { | |||
80 | .next()?; | 74 | .next()?; |
81 | let parent = brace_node.parent()?; | 75 | let parent = brace_node.parent()?; |
82 | let matching_kind = BRACES[brace_idx ^ 1]; | 76 | let matching_kind = BRACES[brace_idx ^ 1]; |
83 | let matching_node = parent.children() | 77 | let matching_node = parent |
78 | .children() | ||
84 | .find(|node| node.kind() == matching_kind)?; | 79 | .find(|node| node.kind() == matching_kind)?; |
85 | Some(matching_node.range().start()) | 80 | Some(matching_node.range().start()) |
86 | } | 81 | } |
@@ -108,10 +103,13 @@ pub fn highlight(file: &File) -> Vec<HighlightedRange> { | |||
108 | } | 103 | } |
109 | 104 | ||
110 | pub fn diagnostics(file: &File) -> Vec<Diagnostic> { | 105 | pub fn diagnostics(file: &File) -> Vec<Diagnostic> { |
111 | file.errors().into_iter().map(|err| Diagnostic { | 106 | file.errors() |
112 | range: TextRange::offset_len(err.offset, 1.into()), | 107 | .into_iter() |
113 | msg: "Syntax Error: ".to_string() + &err.msg, | 108 | .map(|err| Diagnostic { |
114 | }).collect() | 109 | range: TextRange::offset_len(err.offset, 1.into()), |
110 | msg: "Syntax Error: ".to_string() + &err.msg, | ||
111 | }) | ||
112 | .collect() | ||
115 | } | 113 | } |
116 | 114 | ||
117 | pub fn syntax_tree(file: &File) -> String { | 115 | pub fn syntax_tree(file: &File) -> String { |
@@ -119,7 +117,8 @@ pub fn syntax_tree(file: &File) -> String { | |||
119 | } | 117 | } |
120 | 118 | ||
121 | pub fn runnables(file: &File) -> Vec<Runnable> { | 119 | pub fn runnables(file: &File) -> Vec<Runnable> { |
122 | file.syntax().descendants() | 120 | file.syntax() |
121 | .descendants() | ||
123 | .filter_map(ast::FnDef::cast) | 122 | .filter_map(ast::FnDef::cast) |
124 | .filter_map(|f| { | 123 | .filter_map(|f| { |
125 | let name = f.name()?.text(); | 124 | let name = f.name()?.text(); |
@@ -127,7 +126,7 @@ pub fn runnables(file: &File) -> Vec<Runnable> { | |||
127 | RunnableKind::Bin | 126 | RunnableKind::Bin |
128 | } else if f.has_atom_attr("test") { | 127 | } else if f.has_atom_attr("test") { |
129 | RunnableKind::Test { | 128 | RunnableKind::Test { |
130 | name: name.to_string() | 129 | name: name.to_string(), |
131 | } | 130 | } |
132 | } else { | 131 | } else { |
133 | return None; | 132 | return None; |
@@ -145,15 +144,18 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>( | |||
145 | offset: TextUnit, | 144 | offset: TextUnit, |
146 | ) -> Option<N> { | 145 | ) -> Option<N> { |
147 | let leaves = find_leaf_at_offset(syntax, offset); | 146 | let leaves = find_leaf_at_offset(syntax, offset); |
148 | let leaf = leaves.clone() | 147 | let leaf = leaves |
148 | .clone() | ||
149 | .find(|leaf| !leaf.kind().is_trivia()) | 149 | .find(|leaf| !leaf.kind().is_trivia()) |
150 | .or_else(|| leaves.right_biased())?; | 150 | .or_else(|| leaves.right_biased())?; |
151 | leaf.ancestors() | 151 | leaf.ancestors().filter_map(N::cast).next() |
152 | .filter_map(N::cast) | ||
153 | .next() | ||
154 | } | 152 | } |
155 | 153 | ||
156 | pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef) -> Option<(SmolStr, TextRange)> { | 154 | pub fn resolve_local_name( |
155 | file: &File, | ||
156 | offset: TextUnit, | ||
157 | name_ref: ast::NameRef, | ||
158 | ) -> Option<(SmolStr, TextRange)> { | ||
157 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), offset)?; | 159 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), offset)?; |
158 | let scopes = scope::FnScopes::new(fn_def); | 160 | let scopes = scope::FnScopes::new(fn_def); |
159 | let scope_entry = scope::resolve_local_name(name_ref, &scopes)?; | 161 | let scope_entry = scope::resolve_local_name(name_ref, &scopes)?; |
@@ -164,15 +166,17 @@ pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef) | |||
164 | #[cfg(test)] | 166 | #[cfg(test)] |
165 | mod tests { | 167 | mod tests { |
166 | use super::*; | 168 | use super::*; |
167 | use crate::test_utils::{assert_eq_dbg, extract_offset, add_cursor}; | 169 | use crate::test_utils::{add_cursor, assert_eq_dbg, extract_offset}; |
168 | 170 | ||
169 | #[test] | 171 | #[test] |
170 | fn test_highlighting() { | 172 | fn test_highlighting() { |
171 | let file = File::parse(r#" | 173 | let file = File::parse( |
174 | r#" | ||
172 | // comment | 175 | // comment |
173 | fn main() {} | 176 | fn main() {} |
174 | println!("Hello, {}!", 92); | 177 | println!("Hello, {}!", 92); |
175 | "#); | 178 | "#, |
179 | ); | ||
176 | let hls = highlight(&file); | 180 | let hls = highlight(&file); |
177 | assert_eq_dbg( | 181 | assert_eq_dbg( |
178 | r#"[HighlightedRange { range: [1; 11), tag: "comment" }, | 182 | r#"[HighlightedRange { range: [1; 11), tag: "comment" }, |
@@ -187,7 +191,8 @@ fn main() {} | |||
187 | 191 | ||
188 | #[test] | 192 | #[test] |
189 | fn test_runnables() { | 193 | fn test_runnables() { |
190 | let file = File::parse(r#" | 194 | let file = File::parse( |
195 | r#" | ||
191 | fn main() {} | 196 | fn main() {} |
192 | 197 | ||
193 | #[test] | 198 | #[test] |
@@ -196,7 +201,8 @@ fn test_foo() {} | |||
196 | #[test] | 201 | #[test] |
197 | #[ignore] | 202 | #[ignore] |
198 | fn test_foo() {} | 203 | fn test_foo() {} |
199 | "#); | 204 | "#, |
205 | ); | ||
200 | let runnables = runnables(&file); | 206 | let runnables = runnables(&file); |
201 | assert_eq_dbg( | 207 | assert_eq_dbg( |
202 | r#"[Runnable { range: [1; 13), kind: Bin }, | 208 | r#"[Runnable { range: [1; 13), kind: Bin }, |
@@ -219,9 +225,6 @@ fn test_foo() {} | |||
219 | assert_eq_text!(after, &actual); | 225 | assert_eq_text!(after, &actual); |
220 | } | 226 | } |
221 | 227 | ||
222 | do_check( | 228 | do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); |
223 | "struct Foo { a: i32, }<|>", | ||
224 | "struct Foo <|>{ a: i32, }", | ||
225 | ); | ||
226 | } | 229 | } |
227 | } | 230 | } |
diff --git a/crates/ra_editor/src/line_index.rs b/crates/ra_editor/src/line_index.rs index 95d64b8a8..da0f2a7f7 100644 --- a/crates/ra_editor/src/line_index.rs +++ b/crates/ra_editor/src/line_index.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use superslice::Ext; | ||
2 | use crate::TextUnit; | 1 | use crate::TextUnit; |
2 | use superslice::Ext; | ||
3 | 3 | ||
4 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 4 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
5 | pub struct LineIndex { | 5 | pub struct LineIndex { |
@@ -29,7 +29,10 @@ impl LineIndex { | |||
29 | let line = self.newlines.upper_bound(&offset) - 1; | 29 | let line = self.newlines.upper_bound(&offset) - 1; |
30 | let line_start_offset = self.newlines[line]; | 30 | let line_start_offset = self.newlines[line]; |
31 | let col = offset - line_start_offset; | 31 | let col = offset - line_start_offset; |
32 | return LineCol { line: line as u32, col }; | 32 | return LineCol { |
33 | line: line as u32, | ||
34 | col, | ||
35 | }; | ||
33 | } | 36 | } |
34 | 37 | ||
35 | pub fn offset(&self, line_col: LineCol) -> TextUnit { | 38 | pub fn offset(&self, line_col: LineCol) -> TextUnit { |
@@ -42,21 +45,105 @@ impl LineIndex { | |||
42 | fn test_line_index() { | 45 | fn test_line_index() { |
43 | let text = "hello\nworld"; | 46 | let text = "hello\nworld"; |
44 | let index = LineIndex::new(text); | 47 | let index = LineIndex::new(text); |
45 | assert_eq!(index.line_col(0.into()), LineCol { line: 0, col: 0.into() }); | 48 | assert_eq!( |
46 | assert_eq!(index.line_col(1.into()), LineCol { line: 0, col: 1.into() }); | 49 | index.line_col(0.into()), |
47 | assert_eq!(index.line_col(5.into()), LineCol { line: 0, col: 5.into() }); | 50 | LineCol { |
48 | assert_eq!(index.line_col(6.into()), LineCol { line: 1, col: 0.into() }); | 51 | line: 0, |
49 | assert_eq!(index.line_col(7.into()), LineCol { line: 1, col: 1.into() }); | 52 | col: 0.into() |
50 | assert_eq!(index.line_col(8.into()), LineCol { line: 1, col: 2.into() }); | 53 | } |
51 | assert_eq!(index.line_col(10.into()), LineCol { line: 1, col: 4.into() }); | 54 | ); |
52 | assert_eq!(index.line_col(11.into()), LineCol { line: 1, col: 5.into() }); | 55 | assert_eq!( |
53 | assert_eq!(index.line_col(12.into()), LineCol { line: 1, col: 6.into() }); | 56 | index.line_col(1.into()), |
57 | LineCol { | ||
58 | line: 0, | ||
59 | col: 1.into() | ||
60 | } | ||
61 | ); | ||
62 | assert_eq!( | ||
63 | index.line_col(5.into()), | ||
64 | LineCol { | ||
65 | line: 0, | ||
66 | col: 5.into() | ||
67 | } | ||
68 | ); | ||
69 | assert_eq!( | ||
70 | index.line_col(6.into()), | ||
71 | LineCol { | ||
72 | line: 1, | ||
73 | col: 0.into() | ||
74 | } | ||
75 | ); | ||
76 | assert_eq!( | ||
77 | index.line_col(7.into()), | ||
78 | LineCol { | ||
79 | line: 1, | ||
80 | col: 1.into() | ||
81 | } | ||
82 | ); | ||
83 | assert_eq!( | ||
84 | index.line_col(8.into()), | ||
85 | LineCol { | ||
86 | line: 1, | ||
87 | col: 2.into() | ||
88 | } | ||
89 | ); | ||
90 | assert_eq!( | ||
91 | index.line_col(10.into()), | ||
92 | LineCol { | ||
93 | line: 1, | ||
94 | col: 4.into() | ||
95 | } | ||
96 | ); | ||
97 | assert_eq!( | ||
98 | index.line_col(11.into()), | ||
99 | LineCol { | ||
100 | line: 1, | ||
101 | col: 5.into() | ||
102 | } | ||
103 | ); | ||
104 | assert_eq!( | ||
105 | index.line_col(12.into()), | ||
106 | LineCol { | ||
107 | line: 1, | ||
108 | col: 6.into() | ||
109 | } | ||
110 | ); | ||
54 | 111 | ||
55 | let text = "\nhello\nworld"; | 112 | let text = "\nhello\nworld"; |
56 | let index = LineIndex::new(text); | 113 | let index = LineIndex::new(text); |
57 | assert_eq!(index.line_col(0.into()), LineCol { line: 0, col: 0.into() }); | 114 | assert_eq!( |
58 | assert_eq!(index.line_col(1.into()), LineCol { line: 1, col: 0.into() }); | 115 | index.line_col(0.into()), |
59 | assert_eq!(index.line_col(2.into()), LineCol { line: 1, col: 1.into() }); | 116 | LineCol { |
60 | assert_eq!(index.line_col(6.into()), LineCol { line: 1, col: 5.into() }); | 117 | line: 0, |
61 | assert_eq!(index.line_col(7.into()), LineCol { line: 2, col: 0.into() }); | 118 | col: 0.into() |
119 | } | ||
120 | ); | ||
121 | assert_eq!( | ||
122 | index.line_col(1.into()), | ||
123 | LineCol { | ||
124 | line: 1, | ||
125 | col: 0.into() | ||
126 | } | ||
127 | ); | ||
128 | assert_eq!( | ||
129 | index.line_col(2.into()), | ||
130 | LineCol { | ||
131 | line: 1, | ||
132 | col: 1.into() | ||
133 | } | ||
134 | ); | ||
135 | assert_eq!( | ||
136 | index.line_col(6.into()), | ||
137 | LineCol { | ||
138 | line: 1, | ||
139 | col: 5.into() | ||
140 | } | ||
141 | ); | ||
142 | assert_eq!( | ||
143 | index.line_col(7.into()), | ||
144 | LineCol { | ||
145 | line: 2, | ||
146 | col: 0.into() | ||
147 | } | ||
148 | ); | ||
62 | } | 149 | } |
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs index 99d698b60..9088e5a60 100644 --- a/crates/ra_editor/src/scope/fn_scope.rs +++ b/crates/ra_editor/src/scope/fn_scope.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | use std::fmt; | 1 | use std::fmt; |
2 | |||
2 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
3 | 4 | ||
4 | use ra_syntax::{ | 5 | use ra_syntax::{ |
5 | SyntaxNodeRef, SyntaxNode, SmolStr, AstNode, | 6 | algo::generate, |
6 | ast::{self, NameOwner, LoopBodyOwner, ArgListOwner}, | 7 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, |
7 | algo::{generate} | 8 | AstNode, SmolStr, SyntaxNode, SyntaxNodeRef, |
8 | }; | 9 | }; |
9 | 10 | ||
10 | type ScopeId = usize; | 11 | type ScopeId = usize; |
@@ -19,11 +20,12 @@ pub struct FnScopes { | |||
19 | impl FnScopes { | 20 | impl FnScopes { |
20 | pub fn new(fn_def: ast::FnDef) -> FnScopes { | 21 | pub fn new(fn_def: ast::FnDef) -> FnScopes { |
21 | let mut scopes = FnScopes { | 22 | let mut scopes = FnScopes { |
22 | self_param: fn_def.param_list() | 23 | self_param: fn_def |
24 | .param_list() | ||
23 | .and_then(|it| it.self_param()) | 25 | .and_then(|it| it.self_param()) |
24 | .map(|it| it.syntax().owned()), | 26 | .map(|it| it.syntax().owned()), |
25 | scopes: Vec::new(), | 27 | scopes: Vec::new(), |
26 | scope_for: FxHashMap::default() | 28 | scope_for: FxHashMap::default(), |
27 | }; | 29 | }; |
28 | let root = scopes.root_scope(); | 30 | let root = scopes.root_scope(); |
29 | scopes.add_params_bindings(root, fn_def.param_list()); | 31 | scopes.add_params_bindings(root, fn_def.param_list()); |
@@ -35,27 +37,38 @@ impl FnScopes { | |||
35 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | 37 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { |
36 | &self.scopes[scope].entries | 38 | &self.scopes[scope].entries |
37 | } | 39 | } |
38 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a { | 40 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { |
39 | generate(self.scope_for(node), move |&scope| self.scopes[scope].parent) | 41 | generate(self.scope_for(node), move |&scope| { |
42 | self.scopes[scope].parent | ||
43 | }) | ||
40 | } | 44 | } |
41 | fn root_scope(&mut self) -> ScopeId { | 45 | fn root_scope(&mut self) -> ScopeId { |
42 | let res = self.scopes.len(); | 46 | let res = self.scopes.len(); |
43 | self.scopes.push(ScopeData { parent: None, entries: vec![] }); | 47 | self.scopes.push(ScopeData { |
48 | parent: None, | ||
49 | entries: vec![], | ||
50 | }); | ||
44 | res | 51 | res |
45 | } | 52 | } |
46 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | 53 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { |
47 | let res = self.scopes.len(); | 54 | let res = self.scopes.len(); |
48 | self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] }); | 55 | self.scopes.push(ScopeData { |
56 | parent: Some(parent), | ||
57 | entries: vec![], | ||
58 | }); | ||
49 | res | 59 | res |
50 | } | 60 | } |
51 | fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { | 61 | fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { |
52 | let entries = pat.syntax().descendants() | 62 | let entries = pat |
63 | .syntax() | ||
64 | .descendants() | ||
53 | .filter_map(ast::BindPat::cast) | 65 | .filter_map(ast::BindPat::cast) |
54 | .filter_map(ScopeEntry::new); | 66 | .filter_map(ScopeEntry::new); |
55 | self.scopes[scope].entries.extend(entries); | 67 | self.scopes[scope].entries.extend(entries); |
56 | } | 68 | } |
57 | fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { | 69 | fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { |
58 | params.into_iter() | 70 | params |
71 | .into_iter() | ||
59 | .flat_map(|it| it.params()) | 72 | .flat_map(|it| it.params()) |
60 | .filter_map(|it| it.pat()) | 73 | .filter_map(|it| it.pat()) |
61 | .for_each(|it| self.add_bindings(scope, it)); | 74 | .for_each(|it| self.add_bindings(scope, it)); |
@@ -71,34 +84,33 @@ impl FnScopes { | |||
71 | } | 84 | } |
72 | 85 | ||
73 | pub struct ScopeEntry { | 86 | pub struct ScopeEntry { |
74 | syntax: SyntaxNode | 87 | syntax: SyntaxNode, |
75 | } | 88 | } |
76 | 89 | ||
77 | impl ScopeEntry { | 90 | impl ScopeEntry { |
78 | fn new(pat: ast::BindPat) -> Option<ScopeEntry> { | 91 | fn new(pat: ast::BindPat) -> Option<ScopeEntry> { |
79 | if pat.name().is_some() { | 92 | if pat.name().is_some() { |
80 | Some(ScopeEntry { syntax: pat.syntax().owned() }) | 93 | Some(ScopeEntry { |
94 | syntax: pat.syntax().owned(), | ||
95 | }) | ||
81 | } else { | 96 | } else { |
82 | None | 97 | None |
83 | } | 98 | } |
84 | } | 99 | } |
85 | pub fn name(&self) -> SmolStr { | 100 | pub fn name(&self) -> SmolStr { |
86 | self.ast().name() | 101 | self.ast().name().unwrap().text() |
87 | .unwrap() | ||
88 | .text() | ||
89 | } | 102 | } |
90 | pub fn ast(&self) -> ast::BindPat { | 103 | pub fn ast(&self) -> ast::BindPat { |
91 | ast::BindPat::cast(self.syntax.borrowed()) | 104 | ast::BindPat::cast(self.syntax.borrowed()).unwrap() |
92 | .unwrap() | ||
93 | } | 105 | } |
94 | } | 106 | } |
95 | 107 | ||
96 | impl fmt::Debug for ScopeEntry { | 108 | impl fmt::Debug for ScopeEntry { |
97 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 109 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
98 | f.debug_struct("ScopeEntry") | 110 | f.debug_struct("ScopeEntry") |
99 | .field("name", &self.name()) | 111 | .field("name", &self.name()) |
100 | .field("syntax", &self.syntax) | 112 | .field("syntax", &self.syntax) |
101 | .finish() | 113 | .finish() |
102 | } | 114 | } |
103 | } | 115 | } |
104 | 116 | ||
@@ -132,16 +144,16 @@ fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: Sco | |||
132 | fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | 144 | fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { |
133 | match expr { | 145 | match expr { |
134 | ast::Expr::IfExpr(e) => { | 146 | ast::Expr::IfExpr(e) => { |
135 | let cond_scope = e.condition().and_then(|cond| { | 147 | let cond_scope = e |
136 | compute_cond_scopes(cond, scopes, scope) | 148 | .condition() |
137 | }); | 149 | .and_then(|cond| compute_cond_scopes(cond, scopes, scope)); |
138 | if let Some(block) = e.then_branch() { | 150 | if let Some(block) = e.then_branch() { |
139 | compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); | 151 | compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); |
140 | } | 152 | } |
141 | if let Some(block) = e.else_branch() { | 153 | if let Some(block) = e.else_branch() { |
142 | compute_block_scopes(block, scopes, scope); | 154 | compute_block_scopes(block, scopes, scope); |
143 | } | 155 | } |
144 | }, | 156 | } |
145 | ast::Expr::BlockExpr(e) => { | 157 | ast::Expr::BlockExpr(e) => { |
146 | if let Some(block) = e.block() { | 158 | if let Some(block) = e.block() { |
147 | compute_block_scopes(block, scopes, scope); | 159 | compute_block_scopes(block, scopes, scope); |
@@ -153,9 +165,9 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
153 | } | 165 | } |
154 | } | 166 | } |
155 | ast::Expr::WhileExpr(e) => { | 167 | ast::Expr::WhileExpr(e) => { |
156 | let cond_scope = e.condition().and_then(|cond| { | 168 | let cond_scope = e |
157 | compute_cond_scopes(cond, scopes, scope) | 169 | .condition() |
158 | }); | 170 | .and_then(|cond| compute_cond_scopes(cond, scopes, scope)); |
159 | if let Some(block) = e.loop_body() { | 171 | if let Some(block) = e.loop_body() { |
160 | compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); | 172 | compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); |
161 | } | 173 | } |
@@ -201,25 +213,31 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
201 | } | 213 | } |
202 | } | 214 | } |
203 | } | 215 | } |
204 | _ => { | 216 | _ => expr |
205 | expr.syntax().children() | 217 | .syntax() |
206 | .filter_map(ast::Expr::cast) | 218 | .children() |
207 | .for_each(|expr| compute_expr_scopes(expr, scopes, scope)) | 219 | .filter_map(ast::Expr::cast) |
208 | } | 220 | .for_each(|expr| compute_expr_scopes(expr, scopes, scope)), |
209 | }; | 221 | }; |
210 | 222 | ||
211 | fn compute_call_scopes( | 223 | fn compute_call_scopes( |
212 | receiver: Option<ast::Expr>, | 224 | receiver: Option<ast::Expr>, |
213 | arg_list: Option<ast::ArgList>, | 225 | arg_list: Option<ast::ArgList>, |
214 | scopes: &mut FnScopes, scope: ScopeId, | 226 | scopes: &mut FnScopes, |
227 | scope: ScopeId, | ||
215 | ) { | 228 | ) { |
216 | arg_list.into_iter() | 229 | arg_list |
230 | .into_iter() | ||
217 | .flat_map(|it| it.args()) | 231 | .flat_map(|it| it.args()) |
218 | .chain(receiver) | 232 | .chain(receiver) |
219 | .for_each(|expr| compute_expr_scopes(expr, scopes, scope)); | 233 | .for_each(|expr| compute_expr_scopes(expr, scopes, scope)); |
220 | } | 234 | } |
221 | 235 | ||
222 | fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> { | 236 | fn compute_cond_scopes( |
237 | cond: ast::Condition, | ||
238 | scopes: &mut FnScopes, | ||
239 | scope: ScopeId, | ||
240 | ) -> Option<ScopeId> { | ||
223 | if let Some(expr) = cond.expr() { | 241 | if let Some(expr) = cond.expr() { |
224 | compute_expr_scopes(expr, scopes, scope); | 242 | compute_expr_scopes(expr, scopes, scope); |
225 | } | 243 | } |
@@ -236,14 +254,18 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
236 | #[derive(Debug)] | 254 | #[derive(Debug)] |
237 | struct ScopeData { | 255 | struct ScopeData { |
238 | parent: Option<ScopeId>, | 256 | parent: Option<ScopeId>, |
239 | entries: Vec<ScopeEntry> | 257 | entries: Vec<ScopeEntry>, |
240 | } | 258 | } |
241 | 259 | ||
242 | pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> Option<&'a ScopeEntry> { | 260 | pub fn resolve_local_name<'a>( |
261 | name_ref: ast::NameRef, | ||
262 | scopes: &'a FnScopes, | ||
263 | ) -> Option<&'a ScopeEntry> { | ||
243 | use rustc_hash::FxHashSet; | 264 | use rustc_hash::FxHashSet; |
244 | 265 | ||
245 | let mut shadowed = FxHashSet::default(); | 266 | let mut shadowed = FxHashSet::default(); |
246 | let ret = scopes.scope_chain(name_ref.syntax()) | 267 | let ret = scopes |
268 | .scope_chain(name_ref.syntax()) | ||
247 | .flat_map(|scope| scopes.entries(scope).iter()) | 269 | .flat_map(|scope| scopes.entries(scope).iter()) |
248 | .filter(|entry| shadowed.insert(entry.name())) | 270 | .filter(|entry| shadowed.insert(entry.name())) |
249 | .filter(|entry| entry.name() == name_ref.text()) | 271 | .filter(|entry| entry.name() == name_ref.text()) |
@@ -255,8 +277,8 @@ pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> O | |||
255 | #[cfg(test)] | 277 | #[cfg(test)] |
256 | mod tests { | 278 | mod tests { |
257 | use super::*; | 279 | use super::*; |
258 | use ra_syntax::File; | ||
259 | use crate::{find_node_at_offset, test_utils::extract_offset}; | 280 | use crate::{find_node_at_offset, test_utils::extract_offset}; |
281 | use ra_syntax::File; | ||
260 | 282 | ||
261 | fn do_check(code: &str, expected: &[&str]) { | 283 | fn do_check(code: &str, expected: &[&str]) { |
262 | let (off, code) = extract_offset(code); | 284 | let (off, code) = extract_offset(code); |
@@ -272,7 +294,8 @@ mod tests { | |||
272 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 294 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
273 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 295 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
274 | let scopes = FnScopes::new(fn_def); | 296 | let scopes = FnScopes::new(fn_def); |
275 | let actual = scopes.scope_chain(marker.syntax()) | 297 | let actual = scopes |
298 | .scope_chain(marker.syntax()) | ||
276 | .flat_map(|scope| scopes.entries(scope)) | 299 | .flat_map(|scope| scopes.entries(scope)) |
277 | .map(|it| it.name()) | 300 | .map(|it| it.name()) |
278 | .collect::<Vec<_>>(); | 301 | .collect::<Vec<_>>(); |
@@ -281,7 +304,8 @@ mod tests { | |||
281 | 304 | ||
282 | #[test] | 305 | #[test] |
283 | fn test_lambda_scope() { | 306 | fn test_lambda_scope() { |
284 | do_check(r" | 307 | do_check( |
308 | r" | ||
285 | fn quux(foo: i32) { | 309 | fn quux(foo: i32) { |
286 | let f = |bar, baz: i32| { | 310 | let f = |bar, baz: i32| { |
287 | <|> | 311 | <|> |
@@ -293,7 +317,8 @@ mod tests { | |||
293 | 317 | ||
294 | #[test] | 318 | #[test] |
295 | fn test_call_scope() { | 319 | fn test_call_scope() { |
296 | do_check(r" | 320 | do_check( |
321 | r" | ||
297 | fn quux() { | 322 | fn quux() { |
298 | f(|x| <|> ); | 323 | f(|x| <|> ); |
299 | }", | 324 | }", |
@@ -303,7 +328,8 @@ mod tests { | |||
303 | 328 | ||
304 | #[test] | 329 | #[test] |
305 | fn test_metod_call_scope() { | 330 | fn test_metod_call_scope() { |
306 | do_check(r" | 331 | do_check( |
332 | r" | ||
307 | fn quux() { | 333 | fn quux() { |
308 | z.f(|x| <|> ); | 334 | z.f(|x| <|> ); |
309 | }", | 335 | }", |
@@ -313,7 +339,8 @@ mod tests { | |||
313 | 339 | ||
314 | #[test] | 340 | #[test] |
315 | fn test_loop_scope() { | 341 | fn test_loop_scope() { |
316 | do_check(r" | 342 | do_check( |
343 | r" | ||
317 | fn quux() { | 344 | fn quux() { |
318 | loop { | 345 | loop { |
319 | let x = (); | 346 | let x = (); |
@@ -326,7 +353,8 @@ mod tests { | |||
326 | 353 | ||
327 | #[test] | 354 | #[test] |
328 | fn test_match() { | 355 | fn test_match() { |
329 | do_check(r" | 356 | do_check( |
357 | r" | ||
330 | fn quux() { | 358 | fn quux() { |
331 | match () { | 359 | match () { |
332 | Some(x) => { | 360 | Some(x) => { |
@@ -340,7 +368,8 @@ mod tests { | |||
340 | 368 | ||
341 | #[test] | 369 | #[test] |
342 | fn test_shadow_variable() { | 370 | fn test_shadow_variable() { |
343 | do_check(r" | 371 | do_check( |
372 | r" | ||
344 | fn foo(x: String) { | 373 | fn foo(x: String) { |
345 | let x : &str = &x<|>; | 374 | let x : &str = &x<|>; |
346 | }", | 375 | }", |
@@ -356,14 +385,20 @@ mod tests { | |||
356 | 385 | ||
357 | let scopes = FnScopes::new(fn_def); | 386 | let scopes = FnScopes::new(fn_def); |
358 | 387 | ||
359 | let local_name = resolve_local_name(name_ref, &scopes).unwrap().ast().name().unwrap(); | 388 | let local_name = resolve_local_name(name_ref, &scopes) |
360 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); | 389 | .unwrap() |
390 | .ast() | ||
391 | .name() | ||
392 | .unwrap(); | ||
393 | let expected_name = | ||
394 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); | ||
361 | assert_eq!(local_name.syntax().range(), expected_name.syntax().range()); | 395 | assert_eq!(local_name.syntax().range(), expected_name.syntax().range()); |
362 | } | 396 | } |
363 | 397 | ||
364 | #[test] | 398 | #[test] |
365 | fn test_resolve_local_name() { | 399 | fn test_resolve_local_name() { |
366 | do_check_local_name(r#" | 400 | do_check_local_name( |
401 | r#" | ||
367 | fn foo(x: i32, y: u32) { | 402 | fn foo(x: i32, y: u32) { |
368 | { | 403 | { |
369 | let z = x * 2; | 404 | let z = x * 2; |
@@ -372,25 +407,30 @@ mod tests { | |||
372 | let t = x<|> * 3; | 407 | let t = x<|> * 3; |
373 | } | 408 | } |
374 | }"#, | 409 | }"#, |
375 | 21); | 410 | 21, |
411 | ); | ||
376 | } | 412 | } |
377 | 413 | ||
378 | #[test] | 414 | #[test] |
379 | fn test_resolve_local_name_declaration() { | 415 | fn test_resolve_local_name_declaration() { |
380 | do_check_local_name(r#" | 416 | do_check_local_name( |
417 | r#" | ||
381 | fn foo(x: String) { | 418 | fn foo(x: String) { |
382 | let x : &str = &x<|>; | 419 | let x : &str = &x<|>; |
383 | }"#, | 420 | }"#, |
384 | 21); | 421 | 21, |
422 | ); | ||
385 | } | 423 | } |
386 | 424 | ||
387 | #[test] | 425 | #[test] |
388 | fn test_resolve_local_name_shadow() { | 426 | fn test_resolve_local_name_shadow() { |
389 | do_check_local_name(r" | 427 | do_check_local_name( |
428 | r" | ||
390 | fn foo(x: String) { | 429 | fn foo(x: String) { |
391 | let x : &str = &x; | 430 | let x : &str = &x; |
392 | x<|> | 431 | x<|> |
393 | }", | 432 | }", |
394 | 46); | 433 | 46, |
434 | ); | ||
395 | } | 435 | } |
396 | } | 436 | } |
diff --git a/crates/ra_editor/src/scope/mod.rs b/crates/ra_editor/src/scope/mod.rs index 7d6d530f7..cc2d49392 100644 --- a/crates/ra_editor/src/scope/mod.rs +++ b/crates/ra_editor/src/scope/mod.rs | |||
@@ -2,7 +2,6 @@ mod fn_scope; | |||
2 | mod mod_scope; | 2 | mod mod_scope; |
3 | 3 | ||
4 | pub use self::{ | 4 | pub use self::{ |
5 | fn_scope::{FnScopes, resolve_local_name}, | 5 | fn_scope::{resolve_local_name, FnScopes}, |
6 | mod_scope::ModuleScope, | 6 | mod_scope::ModuleScope, |
7 | }; | 7 | }; |
8 | |||
diff --git a/crates/ra_editor/src/scope/mod_scope.rs b/crates/ra_editor/src/scope/mod_scope.rs index d2a3e7c58..8d7e408f8 100644 --- a/crates/ra_editor/src/scope/mod_scope.rs +++ b/crates/ra_editor/src/scope/mod_scope.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | AstNode, SyntaxNode, SyntaxNodeRef, SmolStr, | ||
3 | ast::{self, AstChildren}, | 2 | ast::{self, AstChildren}, |
3 | AstNode, SmolStr, SyntaxNode, SyntaxNodeRef, | ||
4 | }; | 4 | }; |
5 | 5 | ||
6 | pub struct ModuleScope { | 6 | pub struct ModuleScope { |
@@ -13,7 +13,8 @@ pub struct Entry { | |||
13 | } | 13 | } |
14 | 14 | ||
15 | enum EntryKind { | 15 | enum EntryKind { |
16 | Item, Import, | 16 | Item, |
17 | Import, | ||
17 | } | 18 | } |
18 | 19 | ||
19 | impl ModuleScope { | 20 | impl ModuleScope { |
@@ -34,9 +35,8 @@ impl ModuleScope { | |||
34 | collect_imports(tree, &mut entries); | 35 | collect_imports(tree, &mut entries); |
35 | } | 36 | } |
36 | continue; | 37 | continue; |
37 | }, | 38 | } |
38 | ast::ModuleItem::ExternCrateItem(_) | | 39 | ast::ModuleItem::ExternCrateItem(_) | ast::ModuleItem::ImplItem(_) => continue, |
39 | ast::ModuleItem::ImplItem(_) => continue, | ||
40 | }; | 40 | }; |
41 | entries.extend(entry) | 41 | entries.extend(entry) |
42 | } | 42 | } |
@@ -52,20 +52,22 @@ impl ModuleScope { | |||
52 | impl Entry { | 52 | impl Entry { |
53 | fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<Entry> { | 53 | fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<Entry> { |
54 | let name = item.name()?; | 54 | let name = item.name()?; |
55 | Some(Entry { node: name.syntax().owned(), kind: EntryKind::Item }) | 55 | Some(Entry { |
56 | node: name.syntax().owned(), | ||
57 | kind: EntryKind::Item, | ||
58 | }) | ||
56 | } | 59 | } |
57 | fn new_import(path: ast::Path) -> Option<Entry> { | 60 | fn new_import(path: ast::Path) -> Option<Entry> { |
58 | let name_ref = path.segment()?.name_ref()?; | 61 | let name_ref = path.segment()?.name_ref()?; |
59 | Some(Entry { node: name_ref.syntax().owned(), kind: EntryKind::Import }) | 62 | Some(Entry { |
63 | node: name_ref.syntax().owned(), | ||
64 | kind: EntryKind::Import, | ||
65 | }) | ||
60 | } | 66 | } |
61 | pub fn name(&self) -> SmolStr { | 67 | pub fn name(&self) -> SmolStr { |
62 | match self.kind { | 68 | match self.kind { |
63 | EntryKind::Item => | 69 | EntryKind::Item => ast::Name::cast(self.node.borrowed()).unwrap().text(), |
64 | ast::Name::cast(self.node.borrowed()).unwrap() | 70 | EntryKind::Import => ast::NameRef::cast(self.node.borrowed()).unwrap().text(), |
65 | .text(), | ||
66 | EntryKind::Import => | ||
67 | ast::NameRef::cast(self.node.borrowed()).unwrap() | ||
68 | .text(), | ||
69 | } | 71 | } |
70 | } | 72 | } |
71 | pub fn syntax(&self) -> SyntaxNodeRef { | 73 | pub fn syntax(&self) -> SyntaxNodeRef { |
@@ -75,32 +77,31 @@ impl Entry { | |||
75 | 77 | ||
76 | fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) { | 78 | fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) { |
77 | if let Some(use_tree_list) = tree.use_tree_list() { | 79 | if let Some(use_tree_list) = tree.use_tree_list() { |
78 | return use_tree_list.use_trees().for_each(|it| collect_imports(it, acc)); | 80 | return use_tree_list |
81 | .use_trees() | ||
82 | .for_each(|it| collect_imports(it, acc)); | ||
79 | } | 83 | } |
80 | if let Some(path) = tree.path() { | 84 | if let Some(path) = tree.path() { |
81 | acc.extend(Entry::new_import(path)); | 85 | acc.extend(Entry::new_import(path)); |
82 | } | 86 | } |
83 | } | 87 | } |
84 | 88 | ||
85 | |||
86 | #[cfg(test)] | 89 | #[cfg(test)] |
87 | mod tests { | 90 | mod tests { |
88 | use super::*; | 91 | use super::*; |
89 | use ra_syntax::{File, ast::ModuleItemOwner}; | 92 | use ra_syntax::{ast::ModuleItemOwner, File}; |
90 | 93 | ||
91 | fn do_check(code: &str, expected: &[&str]) { | 94 | fn do_check(code: &str, expected: &[&str]) { |
92 | let file = File::parse(&code); | 95 | let file = File::parse(&code); |
93 | let scope = ModuleScope::new(file.ast().items()); | 96 | let scope = ModuleScope::new(file.ast().items()); |
94 | let actual = scope.entries | 97 | let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>(); |
95 | .iter() | ||
96 | .map(|it| it.name()) | ||
97 | .collect::<Vec<_>>(); | ||
98 | assert_eq!(expected, actual.as_slice()); | 98 | assert_eq!(expected, actual.as_slice()); |
99 | } | 99 | } |
100 | 100 | ||
101 | #[test] | 101 | #[test] |
102 | fn test_module_scope() { | 102 | fn test_module_scope() { |
103 | do_check(" | 103 | do_check( |
104 | " | ||
104 | struct Foo; | 105 | struct Foo; |
105 | enum Bar {} | 106 | enum Bar {} |
106 | mod baz {} | 107 | mod baz {} |
@@ -110,6 +111,8 @@ mod tests { | |||
110 | t, | 111 | t, |
111 | }; | 112 | }; |
112 | type T = (); | 113 | type T = (); |
113 | ", &["Foo", "Bar", "baz", "quux", "z", "t", "T"]) | 114 | ", |
115 | &["Foo", "Bar", "baz", "quux", "z", "t", "T"], | ||
116 | ) | ||
114 | } | 117 | } |
115 | } | 118 | } |
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs index d9e4b2df7..b768b34bc 100644 --- a/crates/ra_editor/src/symbols.rs +++ b/crates/ra_editor/src/symbols.rs | |||
@@ -1,12 +1,13 @@ | |||
1 | use crate::TextRange; | ||
2 | |||
1 | use ra_syntax::{ | 3 | use ra_syntax::{ |
2 | SyntaxKind, SyntaxNodeRef, AstNode, File, SmolStr, | ||
3 | ast::{self, NameOwner}, | ||
4 | algo::{ | 4 | algo::{ |
5 | visit::{visitor, Visitor}, | 5 | visit::{visitor, Visitor}, |
6 | walk::{walk, WalkEvent}, | 6 | walk::{walk, WalkEvent}, |
7 | }, | 7 | }, |
8 | ast::{self, NameOwner}, | ||
9 | AstNode, File, SmolStr, SyntaxKind, SyntaxNodeRef, | ||
8 | }; | 10 | }; |
9 | use crate::TextRange; | ||
10 | 11 | ||
11 | #[derive(Debug, Clone)] | 12 | #[derive(Debug, Clone)] |
12 | pub struct StructureNode { | 13 | pub struct StructureNode { |
@@ -25,9 +26,7 @@ pub struct FileSymbol { | |||
25 | } | 26 | } |
26 | 27 | ||
27 | pub fn file_symbols(file: &File) -> Vec<FileSymbol> { | 28 | pub fn file_symbols(file: &File) -> Vec<FileSymbol> { |
28 | file.syntax().descendants() | 29 | file.syntax().descendants().filter_map(to_symbol).collect() |
29 | .filter_map(to_symbol) | ||
30 | .collect() | ||
31 | } | 30 | } |
32 | 31 | ||
33 | fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { | 32 | fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { |
@@ -51,23 +50,20 @@ fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { | |||
51 | .accept(node)? | 50 | .accept(node)? |
52 | } | 51 | } |
53 | 52 | ||
54 | |||
55 | pub fn file_structure(file: &File) -> Vec<StructureNode> { | 53 | pub fn file_structure(file: &File) -> Vec<StructureNode> { |
56 | let mut res = Vec::new(); | 54 | let mut res = Vec::new(); |
57 | let mut stack = Vec::new(); | 55 | let mut stack = Vec::new(); |
58 | 56 | ||
59 | for event in walk(file.syntax()) { | 57 | for event in walk(file.syntax()) { |
60 | match event { | 58 | match event { |
61 | WalkEvent::Enter(node) => { | 59 | WalkEvent::Enter(node) => match structure_node(node) { |
62 | match structure_node(node) { | 60 | Some(mut symbol) => { |
63 | Some(mut symbol) => { | 61 | symbol.parent = stack.last().map(|&n| n); |
64 | symbol.parent = stack.last().map(|&n| n); | 62 | stack.push(res.len()); |
65 | stack.push(res.len()); | 63 | res.push(symbol); |
66 | res.push(symbol); | ||
67 | } | ||
68 | None => (), | ||
69 | } | 64 | } |
70 | } | 65 | None => (), |
66 | }, | ||
71 | WalkEvent::Exit(node) => { | 67 | WalkEvent::Exit(node) => { |
72 | if structure_node(node).is_some() { | 68 | if structure_node(node).is_some() { |
73 | stack.pop().unwrap(); | 69 | stack.pop().unwrap(); |
@@ -131,7 +127,8 @@ mod tests { | |||
131 | 127 | ||
132 | #[test] | 128 | #[test] |
133 | fn test_file_structure() { | 129 | fn test_file_structure() { |
134 | let file = File::parse(r#" | 130 | let file = File::parse( |
131 | r#" | ||
135 | struct Foo { | 132 | struct Foo { |
136 | x: i32 | 133 | x: i32 |
137 | } | 134 | } |
@@ -148,7 +145,8 @@ const C: i32 = 92; | |||
148 | impl E {} | 145 | impl E {} |
149 | 146 | ||
150 | impl fmt::Debug for E {} | 147 | impl fmt::Debug for E {} |
151 | "#); | 148 | "#, |
149 | ); | ||
152 | let symbols = file_structure(&file); | 150 | let symbols = file_structure(&file); |
153 | assert_eq_dbg( | 151 | assert_eq_dbg( |
154 | r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF }, | 152 | r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF }, |
diff --git a/crates/ra_editor/src/test_utils.rs b/crates/ra_editor/src/test_utils.rs index 49eb530d5..bc3d700f6 100644 --- a/crates/ra_editor/src/test_utils.rs +++ b/crates/ra_editor/src/test_utils.rs | |||
@@ -1,12 +1,8 @@ | |||
1 | use ra_syntax::{File, TextUnit, TextRange}; | ||
2 | pub use crate::_test_utils::*; | ||
3 | use crate::LocalEdit; | 1 | use crate::LocalEdit; |
2 | pub use crate::_test_utils::*; | ||
3 | use ra_syntax::{File, TextRange, TextUnit}; | ||
4 | 4 | ||
5 | pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> ( | 5 | pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>>(before: &str, after: &str, f: F) { |
6 | before: &str, | ||
7 | after: &str, | ||
8 | f: F, | ||
9 | ) { | ||
10 | let (before_cursor_pos, before) = extract_offset(before); | 6 | let (before_cursor_pos, before) = extract_offset(before); |
11 | let file = File::parse(&before); | 7 | let file = File::parse(&before); |
12 | let result = f(&file, before_cursor_pos).expect("code action is not applicable"); | 8 | let result = f(&file, before_cursor_pos).expect("code action is not applicable"); |
@@ -19,7 +15,7 @@ pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> ( | |||
19 | assert_eq_text!(after, &actual); | 15 | assert_eq_text!(after, &actual); |
20 | } | 16 | } |
21 | 17 | ||
22 | pub fn check_action_range<F: Fn(&File, TextRange) -> Option<LocalEdit>> ( | 18 | pub fn check_action_range<F: Fn(&File, TextRange) -> Option<LocalEdit>>( |
23 | before: &str, | 19 | before: &str, |
24 | after: &str, | 20 | after: &str, |
25 | f: F, | 21 | f: F, |
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs index 542b9e10b..50b52e7a1 100644 --- a/crates/ra_editor/src/typing.rs +++ b/crates/ra_editor/src/typing.rs | |||
@@ -1,32 +1,30 @@ | |||
1 | use std::mem; | 1 | use std::mem; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind, | 4 | algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, |
5 | ast, | 5 | ast, |
6 | algo::{ | 6 | text_utils::{contains_offset_nonstrict, intersect}, |
7 | find_covering_node, find_leaf_at_offset, LeafAtOffset, | 7 | AstNode, File, SyntaxKind, |
8 | }, | ||
9 | text_utils::{intersect, contains_offset_nonstrict}, | ||
10 | SyntaxKind::*, | 8 | SyntaxKind::*, |
9 | SyntaxNodeRef, TextRange, TextUnit, | ||
11 | }; | 10 | }; |
12 | 11 | ||
13 | use crate::{LocalEdit, EditBuilder, find_node_at_offset}; | 12 | use crate::{find_node_at_offset, EditBuilder, LocalEdit}; |
14 | 13 | ||
15 | pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { | 14 | pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { |
16 | let range = if range.is_empty() { | 15 | let range = if range.is_empty() { |
17 | let syntax = file.syntax(); | 16 | let syntax = file.syntax(); |
18 | let text = syntax.text().slice(range.start()..); | 17 | let text = syntax.text().slice(range.start()..); |
19 | let pos = match text.find('\n') { | 18 | let pos = match text.find('\n') { |
20 | None => return LocalEdit { | 19 | None => { |
21 | edit: EditBuilder::new().finish(), | 20 | return LocalEdit { |
22 | cursor_position: None | 21 | edit: EditBuilder::new().finish(), |
23 | }, | 22 | cursor_position: None, |
24 | Some(pos) => pos | 23 | } |
24 | } | ||
25 | Some(pos) => pos, | ||
25 | }; | 26 | }; |
26 | TextRange::offset_len( | 27 | TextRange::offset_len(range.start() + pos, TextUnit::of_char('\n')) |
27 | range.start() + pos, | ||
28 | TextUnit::of_char('\n'), | ||
29 | ) | ||
30 | } else { | 28 | } else { |
31 | range | 29 | range |
32 | }; | 30 | }; |
@@ -58,7 +56,9 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { | |||
58 | } | 56 | } |
59 | 57 | ||
60 | pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> { | 58 | pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> { |
61 | let comment = find_leaf_at_offset(file.syntax(), offset).left_biased().and_then(|it| ast::Comment::cast(it))?; | 59 | let comment = find_leaf_at_offset(file.syntax(), offset) |
60 | .left_biased() | ||
61 | .and_then(|it| ast::Comment::cast(it))?; | ||
62 | 62 | ||
63 | if let ast::CommentFlavor::Multiline = comment.flavor() { | 63 | if let ast::CommentFlavor::Multiline = comment.flavor() { |
64 | return None; | 64 | return None; |
@@ -88,7 +88,7 @@ fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> { | |||
88 | } | 88 | } |
89 | LeafAtOffset::Single(n) => { | 89 | LeafAtOffset::Single(n) => { |
90 | assert!(n == node); | 90 | assert!(n == node); |
91 | return Some("") | 91 | return Some(""); |
92 | } | 92 | } |
93 | LeafAtOffset::None => unreachable!(), | 93 | LeafAtOffset::None => unreachable!(), |
94 | }; | 94 | }; |
@@ -110,7 +110,12 @@ pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> { | |||
110 | if contains_offset_nonstrict(expr_range, offset) && offset != expr_range.start() { | 110 | if contains_offset_nonstrict(expr_range, offset) && offset != expr_range.start() { |
111 | return None; | 111 | return None; |
112 | } | 112 | } |
113 | if file.syntax().text().slice(offset..expr_range.start()).contains('\n') { | 113 | if file |
114 | .syntax() | ||
115 | .text() | ||
116 | .slice(offset..expr_range.start()) | ||
117 | .contains('\n') | ||
118 | { | ||
114 | return None; | 119 | return None; |
115 | } | 120 | } |
116 | } else { | 121 | } else { |
@@ -125,12 +130,7 @@ pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> { | |||
125 | }) | 130 | }) |
126 | } | 131 | } |
127 | 132 | ||
128 | fn remove_newline( | 133 | fn remove_newline(edit: &mut EditBuilder, node: SyntaxNodeRef, node_text: &str, offset: TextUnit) { |
129 | edit: &mut EditBuilder, | ||
130 | node: SyntaxNodeRef, | ||
131 | node_text: &str, | ||
132 | offset: TextUnit, | ||
133 | ) { | ||
134 | if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 { | 134 | if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 { |
135 | // The node is either the first or the last in the file | 135 | // The node is either the first or the last in the file |
136 | let suff = &node_text[TextRange::from_to( | 136 | let suff = &node_text[TextRange::from_to( |
@@ -156,7 +156,7 @@ fn remove_newline( | |||
156 | // | 156 | // |
157 | // into `my_function(<some-expr>)` | 157 | // into `my_function(<some-expr>)` |
158 | if join_single_expr_block(edit, node).is_some() { | 158 | if join_single_expr_block(edit, node).is_some() { |
159 | return | 159 | return; |
160 | } | 160 | } |
161 | 161 | ||
162 | // The node is between two other nodes | 162 | // The node is between two other nodes |
@@ -170,34 +170,28 @@ fn remove_newline( | |||
170 | // Adds: a single whitespace | 170 | // Adds: a single whitespace |
171 | edit.replace( | 171 | edit.replace( |
172 | TextRange::from_to(prev.range().start(), node.range().end()), | 172 | TextRange::from_to(prev.range().start(), node.range().end()), |
173 | " ".to_string() | 173 | " ".to_string(), |
174 | ); | 174 | ); |
175 | } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) { | 175 | } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) { |
176 | // Removes: newline (incl. surrounding whitespace), start of the next comment | 176 | // Removes: newline (incl. surrounding whitespace), start of the next comment |
177 | edit.delete(TextRange::from_to( | 177 | edit.delete(TextRange::from_to( |
178 | node.range().start(), | 178 | node.range().start(), |
179 | next.syntax().range().start() + TextUnit::of_str(next.prefix()) | 179 | next.syntax().range().start() + TextUnit::of_str(next.prefix()), |
180 | )); | 180 | )); |
181 | } else { | 181 | } else { |
182 | // Remove newline but add a computed amount of whitespace characters | 182 | // Remove newline but add a computed amount of whitespace characters |
183 | edit.replace( | 183 | edit.replace(node.range(), compute_ws(prev, next).to_string()); |
184 | node.range(), | ||
185 | compute_ws(prev, next).to_string(), | ||
186 | ); | ||
187 | } | 184 | } |
188 | } | 185 | } |
189 | 186 | ||
190 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | 187 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { |
191 | match (left, right) { | 188 | match (left, right) { |
192 | (COMMA, R_PAREN) | (COMMA, R_BRACK) => true, | 189 | (COMMA, R_PAREN) | (COMMA, R_BRACK) => true, |
193 | _ => false | 190 | _ => false, |
194 | } | 191 | } |
195 | } | 192 | } |
196 | 193 | ||
197 | fn join_single_expr_block( | 194 | fn join_single_expr_block(edit: &mut EditBuilder, node: SyntaxNodeRef) -> Option<()> { |
198 | edit: &mut EditBuilder, | ||
199 | node: SyntaxNodeRef, | ||
200 | ) -> Option<()> { | ||
201 | let block = ast::Block::cast(node.parent()?)?; | 195 | let block = ast::Block::cast(node.parent()?)?; |
202 | let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?; | 196 | let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?; |
203 | let expr = single_expr(block)?; | 197 | let expr = single_expr(block)?; |
@@ -244,7 +238,7 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str { | |||
244 | #[cfg(test)] | 238 | #[cfg(test)] |
245 | mod tests { | 239 | mod tests { |
246 | use super::*; | 240 | use super::*; |
247 | use crate::test_utils::{check_action, extract_range, extract_offset, add_cursor}; | 241 | use crate::test_utils::{add_cursor, check_action, extract_offset, extract_range}; |
248 | 242 | ||
249 | fn check_join_lines(before: &str, after: &str) { | 243 | fn check_join_lines(before: &str, after: &str) { |
250 | check_action(before, after, |file, offset| { | 244 | check_action(before, after, |file, offset| { |
@@ -256,118 +250,142 @@ mod tests { | |||
256 | 250 | ||
257 | #[test] | 251 | #[test] |
258 | fn test_join_lines_comma() { | 252 | fn test_join_lines_comma() { |
259 | check_join_lines(r" | 253 | check_join_lines( |
254 | r" | ||
260 | fn foo() { | 255 | fn foo() { |
261 | <|>foo(1, | 256 | <|>foo(1, |
262 | ) | 257 | ) |
263 | } | 258 | } |
264 | ", r" | 259 | ", |
260 | r" | ||
265 | fn foo() { | 261 | fn foo() { |
266 | <|>foo(1) | 262 | <|>foo(1) |
267 | } | 263 | } |
268 | "); | 264 | ", |
265 | ); | ||
269 | } | 266 | } |
270 | 267 | ||
271 | #[test] | 268 | #[test] |
272 | fn test_join_lines_lambda_block() { | 269 | fn test_join_lines_lambda_block() { |
273 | check_join_lines(r" | 270 | check_join_lines( |
271 | r" | ||
274 | pub fn reparse(&self, edit: &AtomEdit) -> File { | 272 | pub fn reparse(&self, edit: &AtomEdit) -> File { |
275 | <|>self.incremental_reparse(edit).unwrap_or_else(|| { | 273 | <|>self.incremental_reparse(edit).unwrap_or_else(|| { |
276 | self.full_reparse(edit) | 274 | self.full_reparse(edit) |
277 | }) | 275 | }) |
278 | } | 276 | } |
279 | ", r" | 277 | ", |
278 | r" | ||
280 | pub fn reparse(&self, edit: &AtomEdit) -> File { | 279 | pub fn reparse(&self, edit: &AtomEdit) -> File { |
281 | <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | 280 | <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) |
282 | } | 281 | } |
283 | "); | 282 | ", |
283 | ); | ||
284 | } | 284 | } |
285 | 285 | ||
286 | #[test] | 286 | #[test] |
287 | fn test_join_lines_block() { | 287 | fn test_join_lines_block() { |
288 | check_join_lines(r" | 288 | check_join_lines( |
289 | r" | ||
289 | fn foo() { | 290 | fn foo() { |
290 | foo(<|>{ | 291 | foo(<|>{ |
291 | 92 | 292 | 92 |
292 | }) | 293 | }) |
293 | }", r" | 294 | }", |
295 | r" | ||
294 | fn foo() { | 296 | fn foo() { |
295 | foo(<|>92) | 297 | foo(<|>92) |
296 | }"); | 298 | }", |
299 | ); | ||
297 | } | 300 | } |
298 | 301 | ||
299 | #[test] | 302 | #[test] |
300 | fn test_join_lines_normal_comments() { | 303 | fn test_join_lines_normal_comments() { |
301 | check_join_lines(r" | 304 | check_join_lines( |
305 | r" | ||
302 | fn foo() { | 306 | fn foo() { |
303 | // Hello<|> | 307 | // Hello<|> |
304 | // world! | 308 | // world! |
305 | } | 309 | } |
306 | ", r" | 310 | ", |
311 | r" | ||
307 | fn foo() { | 312 | fn foo() { |
308 | // Hello<|> world! | 313 | // Hello<|> world! |
309 | } | 314 | } |
310 | "); | 315 | ", |
316 | ); | ||
311 | } | 317 | } |
312 | 318 | ||
313 | #[test] | 319 | #[test] |
314 | fn test_join_lines_doc_comments() { | 320 | fn test_join_lines_doc_comments() { |
315 | check_join_lines(r" | 321 | check_join_lines( |
322 | r" | ||
316 | fn foo() { | 323 | fn foo() { |
317 | /// Hello<|> | 324 | /// Hello<|> |
318 | /// world! | 325 | /// world! |
319 | } | 326 | } |
320 | ", r" | 327 | ", |
328 | r" | ||
321 | fn foo() { | 329 | fn foo() { |
322 | /// Hello<|> world! | 330 | /// Hello<|> world! |
323 | } | 331 | } |
324 | "); | 332 | ", |
333 | ); | ||
325 | } | 334 | } |
326 | 335 | ||
327 | #[test] | 336 | #[test] |
328 | fn test_join_lines_mod_comments() { | 337 | fn test_join_lines_mod_comments() { |
329 | check_join_lines(r" | 338 | check_join_lines( |
339 | r" | ||
330 | fn foo() { | 340 | fn foo() { |
331 | //! Hello<|> | 341 | //! Hello<|> |
332 | //! world! | 342 | //! world! |
333 | } | 343 | } |
334 | ", r" | 344 | ", |
345 | r" | ||
335 | fn foo() { | 346 | fn foo() { |
336 | //! Hello<|> world! | 347 | //! Hello<|> world! |
337 | } | 348 | } |
338 | "); | 349 | ", |
350 | ); | ||
339 | } | 351 | } |
340 | 352 | ||
341 | #[test] | 353 | #[test] |
342 | fn test_join_lines_multiline_comments_1() { | 354 | fn test_join_lines_multiline_comments_1() { |
343 | check_join_lines(r" | 355 | check_join_lines( |
356 | r" | ||
344 | fn foo() { | 357 | fn foo() { |
345 | // Hello<|> | 358 | // Hello<|> |
346 | /* world! */ | 359 | /* world! */ |
347 | } | 360 | } |
348 | ", r" | 361 | ", |
362 | r" | ||
349 | fn foo() { | 363 | fn foo() { |
350 | // Hello<|> world! */ | 364 | // Hello<|> world! */ |
351 | } | 365 | } |
352 | "); | 366 | ", |
367 | ); | ||
353 | } | 368 | } |
354 | 369 | ||
355 | #[test] | 370 | #[test] |
356 | fn test_join_lines_multiline_comments_2() { | 371 | fn test_join_lines_multiline_comments_2() { |
357 | check_join_lines(r" | 372 | check_join_lines( |
373 | r" | ||
358 | fn foo() { | 374 | fn foo() { |
359 | // The<|> | 375 | // The<|> |
360 | /* quick | 376 | /* quick |
361 | brown | 377 | brown |
362 | fox! */ | 378 | fox! */ |
363 | } | 379 | } |
364 | ", r" | 380 | ", |
381 | r" | ||
365 | fn foo() { | 382 | fn foo() { |
366 | // The<|> quick | 383 | // The<|> quick |
367 | brown | 384 | brown |
368 | fox! */ | 385 | fox! */ |
369 | } | 386 | } |
370 | "); | 387 | ", |
388 | ); | ||
371 | } | 389 | } |
372 | 390 | ||
373 | fn check_join_lines_sel(before: &str, after: &str) { | 391 | fn check_join_lines_sel(before: &str, after: &str) { |
@@ -380,59 +398,71 @@ fn foo() { | |||
380 | 398 | ||
381 | #[test] | 399 | #[test] |
382 | fn test_join_lines_selection_fn_args() { | 400 | fn test_join_lines_selection_fn_args() { |
383 | check_join_lines_sel(r" | 401 | check_join_lines_sel( |
402 | r" | ||
384 | fn foo() { | 403 | fn foo() { |
385 | <|>foo(1, | 404 | <|>foo(1, |
386 | 2, | 405 | 2, |
387 | 3, | 406 | 3, |
388 | <|>) | 407 | <|>) |
389 | } | 408 | } |
390 | ", r" | 409 | ", |
410 | r" | ||
391 | fn foo() { | 411 | fn foo() { |
392 | foo(1, 2, 3) | 412 | foo(1, 2, 3) |
393 | } | 413 | } |
394 | "); | 414 | ", |
415 | ); | ||
395 | } | 416 | } |
396 | 417 | ||
397 | #[test] | 418 | #[test] |
398 | fn test_join_lines_selection_struct() { | 419 | fn test_join_lines_selection_struct() { |
399 | check_join_lines_sel(r" | 420 | check_join_lines_sel( |
421 | r" | ||
400 | struct Foo <|>{ | 422 | struct Foo <|>{ |
401 | f: u32, | 423 | f: u32, |
402 | }<|> | 424 | }<|> |
403 | ", r" | 425 | ", |
426 | r" | ||
404 | struct Foo { f: u32 } | 427 | struct Foo { f: u32 } |
405 | "); | 428 | ", |
429 | ); | ||
406 | } | 430 | } |
407 | 431 | ||
408 | #[test] | 432 | #[test] |
409 | fn test_join_lines_selection_dot_chain() { | 433 | fn test_join_lines_selection_dot_chain() { |
410 | check_join_lines_sel(r" | 434 | check_join_lines_sel( |
435 | r" | ||
411 | fn foo() { | 436 | fn foo() { |
412 | join(<|>type_params.type_params() | 437 | join(<|>type_params.type_params() |
413 | .filter_map(|it| it.name()) | 438 | .filter_map(|it| it.name()) |
414 | .map(|it| it.text())<|>) | 439 | .map(|it| it.text())<|>) |
415 | }", r" | 440 | }", |
441 | r" | ||
416 | fn foo() { | 442 | fn foo() { |
417 | join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text())) | 443 | join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text())) |
418 | }"); | 444 | }", |
445 | ); | ||
419 | } | 446 | } |
420 | 447 | ||
421 | #[test] | 448 | #[test] |
422 | fn test_join_lines_selection_lambda_block_body() { | 449 | fn test_join_lines_selection_lambda_block_body() { |
423 | check_join_lines_sel(r" | 450 | check_join_lines_sel( |
451 | r" | ||
424 | pub fn handle_find_matching_brace() { | 452 | pub fn handle_find_matching_brace() { |
425 | params.offsets | 453 | params.offsets |
426 | .map(|offset| <|>{ | 454 | .map(|offset| <|>{ |
427 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) | 455 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) |
428 | }<|>) | 456 | }<|>) |
429 | .collect(); | 457 | .collect(); |
430 | }", r" | 458 | }", |
459 | r" | ||
431 | pub fn handle_find_matching_brace() { | 460 | pub fn handle_find_matching_brace() { |
432 | params.offsets | 461 | params.offsets |
433 | .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset)) | 462 | .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset)) |
434 | .collect(); | 463 | .collect(); |
435 | }"); | 464 | }", |
465 | ); | ||
436 | } | 466 | } |
437 | 467 | ||
438 | #[test] | 468 | #[test] |
@@ -454,15 +484,18 @@ pub fn handle_find_matching_brace() { | |||
454 | // let foo =; | 484 | // let foo =; |
455 | // } | 485 | // } |
456 | // "); | 486 | // "); |
457 | do_check(r" | 487 | do_check( |
488 | r" | ||
458 | fn foo() { | 489 | fn foo() { |
459 | let foo =<|> 1 + 1 | 490 | let foo =<|> 1 + 1 |
460 | } | 491 | } |
461 | ", r" | 492 | ", |
493 | r" | ||
462 | fn foo() { | 494 | fn foo() { |
463 | let foo = 1 + 1; | 495 | let foo = 1 + 1; |
464 | } | 496 | } |
465 | "); | 497 | ", |
498 | ); | ||
466 | // do_check(r" | 499 | // do_check(r" |
467 | // fn foo() { | 500 | // fn foo() { |
468 | // let foo =<|> | 501 | // let foo =<|> |
@@ -496,28 +529,34 @@ fn foo() { | |||
496 | assert!(apply_on_enter(text).is_none()) | 529 | assert!(apply_on_enter(text).is_none()) |
497 | } | 530 | } |
498 | 531 | ||
499 | do_check(r" | 532 | do_check( |
533 | r" | ||
500 | /// Some docs<|> | 534 | /// Some docs<|> |
501 | fn foo() { | 535 | fn foo() { |
502 | } | 536 | } |
503 | ", r" | 537 | ", |
538 | r" | ||
504 | /// Some docs | 539 | /// Some docs |
505 | /// <|> | 540 | /// <|> |
506 | fn foo() { | 541 | fn foo() { |
507 | } | 542 | } |
508 | "); | 543 | ", |
509 | do_check(r" | 544 | ); |
545 | do_check( | ||
546 | r" | ||
510 | impl S { | 547 | impl S { |
511 | /// Some<|> docs. | 548 | /// Some<|> docs. |
512 | fn foo() {} | 549 | fn foo() {} |
513 | } | 550 | } |
514 | ", r" | 551 | ", |
552 | r" | ||
515 | impl S { | 553 | impl S { |
516 | /// Some | 554 | /// Some |
517 | /// <|> docs. | 555 | /// <|> docs. |
518 | fn foo() {} | 556 | fn foo() {} |
519 | } | 557 | } |
520 | "); | 558 | ", |
559 | ); | ||
521 | do_check_noop(r"<|>//! docz"); | 560 | do_check_noop(r"<|>//! docz"); |
522 | } | 561 | } |
523 | } | 562 | } |
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index 5598ec75f..1dd495791 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs | |||
@@ -1,14 +1,8 @@ | |||
1 | use languageserver_types::{ | 1 | use languageserver_types::{ |
2 | ServerCapabilities, | 2 | CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions, |
3 | CodeActionProviderCapability, | 3 | ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities, |
4 | FoldingRangeProviderCapability, | 4 | SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, |
5 | TextDocumentSyncCapability, | ||
6 | TextDocumentSyncOptions, | 5 | TextDocumentSyncOptions, |
7 | TextDocumentSyncKind, | ||
8 | ExecuteCommandOptions, | ||
9 | CompletionOptions, | ||
10 | SignatureHelpOptions, | ||
11 | DocumentOnTypeFormattingOptions, | ||
12 | }; | 6 | }; |
13 | 7 | ||
14 | pub fn server_capabilities() -> ServerCapabilities { | 8 | pub fn server_capabilities() -> ServerCapabilities { |
@@ -20,7 +14,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
20 | will_save: None, | 14 | will_save: None, |
21 | will_save_wait_until: None, | 15 | will_save_wait_until: None, |
22 | save: None, | 16 | save: None, |
23 | } | 17 | }, |
24 | )), | 18 | )), |
25 | hover_provider: None, | 19 | hover_provider: None, |
26 | completion_provider: Some(CompletionOptions { | 20 | completion_provider: Some(CompletionOptions { |
@@ -28,7 +22,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
28 | trigger_characters: None, | 22 | trigger_characters: None, |
29 | }), | 23 | }), |
30 | signature_help_provider: Some(SignatureHelpOptions { | 24 | signature_help_provider: Some(SignatureHelpOptions { |
31 | trigger_characters: Some(vec!["(".to_string(), ",".to_string()]) | 25 | trigger_characters: Some(vec!["(".to_string(), ",".to_string()]), |
32 | }), | 26 | }), |
33 | definition_provider: Some(true), | 27 | definition_provider: Some(true), |
34 | type_definition_provider: None, | 28 | type_definition_provider: None, |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index a75b160c5..8325e8c1e 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -1,17 +1,12 @@ | |||
1 | use languageserver_types::{ | 1 | use languageserver_types::{ |
2 | Range, SymbolKind, Position, TextEdit, Location, Url, | 2 | Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, |
3 | TextDocumentIdentifier, VersionedTextDocumentIdentifier, TextDocumentItem, | 3 | TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier, |
4 | TextDocumentPositionParams, TextDocumentEdit, | ||
5 | }; | ||
6 | use ra_editor::{LineIndex, LineCol, Edit, AtomEdit}; | ||
7 | use ra_syntax::{SyntaxKind, TextUnit, TextRange}; | ||
8 | use ra_analysis::{FileId, SourceChange, SourceFileEdit, FileSystemEdit}; | ||
9 | |||
10 | use crate::{ | ||
11 | Result, | ||
12 | server_world::ServerWorld, | ||
13 | req, | ||
14 | }; | 4 | }; |
5 | use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit}; | ||
6 | use ra_editor::{AtomEdit, Edit, LineCol, LineIndex}; | ||
7 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; | ||
8 | |||
9 | use crate::{req, server_world::ServerWorld, Result}; | ||
15 | 10 | ||
16 | pub trait Conv { | 11 | pub trait Conv { |
17 | type Output; | 12 | type Output; |
@@ -190,8 +185,12 @@ impl TryConvWith for SourceChange { | |||
190 | None => None, | 185 | None => None, |
191 | Some(pos) => { | 186 | Some(pos) => { |
192 | let line_index = world.analysis().file_line_index(pos.file_id); | 187 | let line_index = world.analysis().file_line_index(pos.file_id); |
193 | let edits = self.source_file_edits.iter().find(|it| it.file_id == pos.file_id) | 188 | let edits = self |
194 | .map(|it| it.edits.as_slice()).unwrap_or(&[]); | 189 | .source_file_edits |
190 | .iter() | ||
191 | .find(|it| it.file_id == pos.file_id) | ||
192 | .map(|it| it.edits.as_slice()) | ||
193 | .unwrap_or(&[]); | ||
195 | let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits); | 194 | let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits); |
196 | let position = Position::new(line_col.line as u64, u32::from(line_col.col) as u64); | 195 | let position = Position::new(line_col.line as u64, u32::from(line_col.col) as u64); |
197 | Some(TextDocumentPositionParams { | 196 | Some(TextDocumentPositionParams { |
@@ -224,11 +223,11 @@ fn translate_offset_with_edit( | |||
224 | let fallback = pre_edit_index.line_col(offset); | 223 | let fallback = pre_edit_index.line_col(offset); |
225 | let edit = match edits.first() { | 224 | let edit = match edits.first() { |
226 | None => return fallback, | 225 | None => return fallback, |
227 | Some(edit) => edit | 226 | Some(edit) => edit, |
228 | }; | 227 | }; |
229 | let end_offset = edit.delete.start() + TextUnit::of_str(&edit.insert); | 228 | let end_offset = edit.delete.start() + TextUnit::of_str(&edit.insert); |
230 | if !(edit.delete.start() <= offset && offset <= end_offset) { | 229 | if !(edit.delete.start() <= offset && offset <= end_offset) { |
231 | return fallback | 230 | return fallback; |
232 | } | 231 | } |
233 | let rel_offset = offset - edit.delete.start(); | 232 | let rel_offset = offset - edit.delete.start(); |
234 | let in_edit_line_col = LineIndex::new(&edit.insert).line_col(rel_offset); | 233 | let in_edit_line_col = LineIndex::new(&edit.insert).line_col(rel_offset); |
@@ -255,11 +254,11 @@ impl TryConvWith for SourceFileEdit { | |||
255 | version: None, | 254 | version: None, |
256 | }; | 255 | }; |
257 | let line_index = world.analysis().file_line_index(self.file_id); | 256 | let line_index = world.analysis().file_line_index(self.file_id); |
258 | let edits = self.edits | 257 | let edits = self.edits.into_iter().map_conv_with(&line_index).collect(); |
259 | .into_iter() | 258 | Ok(TextDocumentEdit { |
260 | .map_conv_with(&line_index) | 259 | text_document, |
261 | .collect(); | 260 | edits, |
262 | Ok(TextDocumentEdit { text_document, edits }) | 261 | }) |
263 | } | 262 | } |
264 | } | 263 | } |
265 | 264 | ||
@@ -273,13 +272,13 @@ impl TryConvWith for FileSystemEdit { | |||
273 | let path = &path.as_str()[3..]; // strip `../` b/c url is weird | 272 | let path = &path.as_str()[3..]; // strip `../` b/c url is weird |
274 | let uri = uri.join(path)?; | 273 | let uri = uri.join(path)?; |
275 | req::FileSystemEdit::CreateFile { uri } | 274 | req::FileSystemEdit::CreateFile { uri } |
276 | }, | 275 | } |
277 | FileSystemEdit::MoveFile { file, path } => { | 276 | FileSystemEdit::MoveFile { file, path } => { |
278 | let src = world.file_id_to_uri(file)?; | 277 | let src = world.file_id_to_uri(file)?; |
279 | let path = &path.as_str()[3..]; // strip `../` b/c url is weird | 278 | let path = &path.as_str()[3..]; // strip `../` b/c url is weird |
280 | let dst = src.join(path)?; | 279 | let dst = src.join(path)?; |
281 | req::FileSystemEdit::MoveFile { src, dst } | 280 | req::FileSystemEdit::MoveFile { src, dst } |
282 | }, | 281 | } |
283 | }; | 282 | }; |
284 | Ok(res) | 283 | Ok(res) |
285 | } | 284 | } |
@@ -291,12 +290,9 @@ pub fn to_location( | |||
291 | world: &ServerWorld, | 290 | world: &ServerWorld, |
292 | line_index: &LineIndex, | 291 | line_index: &LineIndex, |
293 | ) -> Result<Location> { | 292 | ) -> Result<Location> { |
294 | let url = file_id.try_conv_with(world)?; | 293 | let url = file_id.try_conv_with(world)?; |
295 | let loc = Location::new( | 294 | let loc = Location::new(url, range.conv_with(line_index)); |
296 | url, | 295 | Ok(loc) |
297 | range.conv_with(line_index), | ||
298 | ); | ||
299 | Ok(loc) | ||
300 | } | 296 | } |
301 | 297 | ||
302 | pub trait MapConvWith<'a>: Sized + 'a { | 298 | pub trait MapConvWith<'a>: Sized + 'a { |
@@ -309,8 +305,9 @@ pub trait MapConvWith<'a>: Sized + 'a { | |||
309 | } | 305 | } |
310 | 306 | ||
311 | impl<'a, I> MapConvWith<'a> for I | 307 | impl<'a, I> MapConvWith<'a> for I |
312 | where I: Iterator + 'a, | 308 | where |
313 | I::Item: ConvWith | 309 | I: Iterator + 'a, |
310 | I::Item: ConvWith, | ||
314 | { | 311 | { |
315 | type Ctx = <I::Item as ConvWith>::Ctx; | 312 | type Ctx = <I::Item as ConvWith>::Ctx; |
316 | type Output = <I::Item as ConvWith>::Output; | 313 | type Output = <I::Item as ConvWith>::Output; |
@@ -322,9 +319,9 @@ pub struct ConvWithIter<'a, I, Ctx: 'a> { | |||
322 | } | 319 | } |
323 | 320 | ||
324 | impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx> | 321 | impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx> |
325 | where | 322 | where |
326 | I: Iterator, | 323 | I: Iterator, |
327 | I::Item: ConvWith<Ctx=Ctx>, | 324 | I::Item: ConvWith<Ctx = Ctx>, |
328 | { | 325 | { |
329 | type Item = <I::Item as ConvWith>::Output; | 326 | type Item = <I::Item as ConvWith>::Output; |
330 | 327 | ||
@@ -332,4 +329,3 @@ impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx> | |||
332 | self.iter.next().map(|item| item.conv_with(self.ctx)) | 329 | self.iter.next().map(|item| item.conv_with(self.ctx)) |
333 | } | 330 | } |
334 | } | 331 | } |
335 | |||
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index 7224b1476..f1b17f282 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs | |||
@@ -2,39 +2,36 @@ | |||
2 | extern crate failure; | 2 | extern crate failure; |
3 | #[macro_use] | 3 | #[macro_use] |
4 | extern crate serde_derive; | 4 | extern crate serde_derive; |
5 | extern crate languageserver_types; | ||
5 | extern crate serde; | 6 | extern crate serde; |
6 | extern crate serde_json; | 7 | extern crate serde_json; |
7 | extern crate languageserver_types; | ||
8 | #[macro_use] | 8 | #[macro_use] |
9 | extern crate crossbeam_channel; | 9 | extern crate crossbeam_channel; |
10 | extern crate rayon; | 10 | extern crate rayon; |
11 | #[macro_use] | 11 | #[macro_use] |
12 | extern crate log; | 12 | extern crate log; |
13 | extern crate cargo_metadata; | ||
13 | extern crate drop_bomb; | 14 | extern crate drop_bomb; |
14 | extern crate url_serde; | ||
15 | extern crate walkdir; | ||
16 | extern crate im; | 15 | extern crate im; |
17 | extern crate relative_path; | 16 | extern crate relative_path; |
18 | extern crate cargo_metadata; | ||
19 | extern crate rustc_hash; | 17 | extern crate rustc_hash; |
18 | extern crate url_serde; | ||
19 | extern crate walkdir; | ||
20 | 20 | ||
21 | extern crate gen_lsp_server; | 21 | extern crate gen_lsp_server; |
22 | extern crate ra_editor; | ||
23 | extern crate ra_analysis; | 22 | extern crate ra_analysis; |
23 | extern crate ra_editor; | ||
24 | extern crate ra_syntax; | 24 | extern crate ra_syntax; |
25 | 25 | ||
26 | mod caps; | 26 | mod caps; |
27 | pub mod req; | ||
28 | mod conv; | 27 | mod conv; |
29 | mod main_loop; | 28 | mod main_loop; |
30 | mod vfs; | ||
31 | mod path_map; | 29 | mod path_map; |
32 | mod server_world; | ||
33 | mod project_model; | 30 | mod project_model; |
31 | pub mod req; | ||
32 | mod server_world; | ||
34 | pub mod thread_watcher; | 33 | pub mod thread_watcher; |
34 | mod vfs; | ||
35 | 35 | ||
36 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 36 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
37 | pub use crate::{ | 37 | pub use crate::{caps::server_capabilities, main_loop::main_loop}; |
38 | main_loop::main_loop, | ||
39 | caps::server_capabilities, | ||
40 | }; | ||
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index e5d1792b7..9f62347f1 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs | |||
@@ -6,7 +6,7 @@ extern crate flexi_logger; | |||
6 | extern crate gen_lsp_server; | 6 | extern crate gen_lsp_server; |
7 | extern crate ra_lsp_server; | 7 | extern crate ra_lsp_server; |
8 | 8 | ||
9 | use flexi_logger::{Logger, Duplicate}; | 9 | use flexi_logger::{Duplicate, Logger}; |
10 | use gen_lsp_server::{run_server, stdio_transport}; | 10 | use gen_lsp_server::{run_server, stdio_transport}; |
11 | use ra_lsp_server::Result; | 11 | use ra_lsp_server::Result; |
12 | 12 | ||
@@ -38,7 +38,8 @@ fn main_inner() -> Result<()> { | |||
38 | receiver, | 38 | receiver, |
39 | sender, | 39 | sender, |
40 | |params, r, s| { | 40 | |params, r, s| { |
41 | let root = params.root_uri | 41 | let root = params |
42 | .root_uri | ||
42 | .and_then(|it| it.to_file_path().ok()) | 43 | .and_then(|it| it.to_file_path().ok()) |
43 | .unwrap_or(cwd); | 44 | .unwrap_or(cwd); |
44 | ra_lsp_server::main_loop(false, root, r, s) | 45 | ra_lsp_server::main_loop(false, root, r, s) |
@@ -49,4 +50,3 @@ fn main_inner() -> Result<()> { | |||
49 | info!("... IO is down"); | 50 | info!("... IO is down"); |
50 | Ok(()) | 51 | Ok(()) |
51 | } | 52 | } |
52 | |||
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 5acb39b60..c25b63852 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -1,23 +1,20 @@ | |||
1 | use rustc_hash::FxHashMap; | 1 | use rustc_hash::FxHashMap; |
2 | 2 | ||
3 | use languageserver_types::{ | 3 | use languageserver_types::{ |
4 | Diagnostic, DiagnosticSeverity, DocumentSymbol, | 4 | CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, |
5 | CodeActionResponse, Command, TextDocumentIdentifier, | 5 | DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, |
6 | SymbolInformation, Position, Location, TextEdit, | 6 | InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit, |
7 | CompletionItem, InsertTextFormat, CompletionItemKind, | ||
8 | FoldingRange, FoldingRangeParams, FoldingRangeKind | ||
9 | }; | 7 | }; |
8 | use ra_analysis::{FileId, FoldKind, JobToken, Query, RunnableKind}; | ||
9 | use ra_syntax::text_utils::contains_offset_nonstrict; | ||
10 | use serde_json::to_value; | 10 | use serde_json::to_value; |
11 | use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind}; | ||
12 | use ra_syntax::{ | ||
13 | text_utils::contains_offset_nonstrict | ||
14 | }; | ||
15 | 11 | ||
16 | use crate::{ | 12 | use crate::{ |
17 | req::{self, Decoration}, Result, | 13 | conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith}, |
18 | conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location}, | ||
19 | server_world::ServerWorld, | ||
20 | project_model::TargetKind, | 14 | project_model::TargetKind, |
15 | req::{self, Decoration}, | ||
16 | server_world::ServerWorld, | ||
17 | Result, | ||
21 | }; | 18 | }; |
22 | 19 | ||
23 | pub fn handle_syntax_tree( | 20 | pub fn handle_syntax_tree( |
@@ -38,7 +35,9 @@ pub fn handle_extend_selection( | |||
38 | let file_id = params.text_document.try_conv_with(&world)?; | 35 | let file_id = params.text_document.try_conv_with(&world)?; |
39 | let file = world.analysis().file_syntax(file_id); | 36 | let file = world.analysis().file_syntax(file_id); |
40 | let line_index = world.analysis().file_line_index(file_id); | 37 | let line_index = world.analysis().file_line_index(file_id); |
41 | let selections = params.selections.into_iter() | 38 | let selections = params |
39 | .selections | ||
40 | .into_iter() | ||
42 | .map_conv_with(&line_index) | 41 | .map_conv_with(&line_index) |
43 | .map(|r| world.analysis().extend_selection(&file, r)) | 42 | .map(|r| world.analysis().extend_selection(&file, r)) |
44 | .map_conv_with(&line_index) | 43 | .map_conv_with(&line_index) |
@@ -54,11 +53,15 @@ pub fn handle_find_matching_brace( | |||
54 | let file_id = params.text_document.try_conv_with(&world)?; | 53 | let file_id = params.text_document.try_conv_with(&world)?; |
55 | let file = world.analysis().file_syntax(file_id); | 54 | let file = world.analysis().file_syntax(file_id); |
56 | let line_index = world.analysis().file_line_index(file_id); | 55 | let line_index = world.analysis().file_line_index(file_id); |
57 | let res = params.offsets | 56 | let res = params |
57 | .offsets | ||
58 | .into_iter() | 58 | .into_iter() |
59 | .map_conv_with(&line_index) | 59 | .map_conv_with(&line_index) |
60 | .map(|offset| { | 60 | .map(|offset| { |
61 | world.analysis().matching_brace(&file, offset).unwrap_or(offset) | 61 | world |
62 | .analysis() | ||
63 | .matching_brace(&file, offset) | ||
64 | .unwrap_or(offset) | ||
62 | }) | 65 | }) |
63 | .map_conv_with(&line_index) | 66 | .map_conv_with(&line_index) |
64 | .collect(); | 67 | .collect(); |
@@ -73,7 +76,9 @@ pub fn handle_join_lines( | |||
73 | let file_id = params.text_document.try_conv_with(&world)?; | 76 | let file_id = params.text_document.try_conv_with(&world)?; |
74 | let line_index = world.analysis().file_line_index(file_id); | 77 | let line_index = world.analysis().file_line_index(file_id); |
75 | let range = params.range.conv_with(&line_index); | 78 | let range = params.range.conv_with(&line_index); |
76 | world.analysis().join_lines(file_id, range) | 79 | world |
80 | .analysis() | ||
81 | .join_lines(file_id, range) | ||
77 | .try_conv_with(&world) | 82 | .try_conv_with(&world) |
78 | } | 83 | } |
79 | 84 | ||
@@ -87,7 +92,7 @@ pub fn handle_on_enter( | |||
87 | let offset = params.position.conv_with(&line_index); | 92 | let offset = params.position.conv_with(&line_index); |
88 | match world.analysis().on_enter(file_id, offset) { | 93 | match world.analysis().on_enter(file_id, offset) { |
89 | None => Ok(None), | 94 | None => Ok(None), |
90 | Some(edit) => Ok(Some(edit.try_conv_with(&world)?)) | 95 | Some(edit) => Ok(Some(edit.try_conv_with(&world)?)), |
91 | } | 96 | } |
92 | } | 97 | } |
93 | 98 | ||
@@ -158,7 +163,9 @@ pub fn handle_workspace_symbol( | |||
158 | let all_symbols = params.query.contains("#"); | 163 | let all_symbols = params.query.contains("#"); |
159 | let libs = params.query.contains("*"); | 164 | let libs = params.query.contains("*"); |
160 | let query = { | 165 | let query = { |
161 | let query: String = params.query.chars() | 166 | let query: String = params |
167 | .query | ||
168 | .chars() | ||
162 | .filter(|&c| c != '#' && c != '*') | 169 | .filter(|&c| c != '#' && c != '*') |
163 | .collect(); | 170 | .collect(); |
164 | let mut q = Query::new(query); | 171 | let mut q = Query::new(query); |
@@ -180,22 +187,23 @@ pub fn handle_workspace_symbol( | |||
180 | 187 | ||
181 | return Ok(Some(res)); | 188 | return Ok(Some(res)); |
182 | 189 | ||
183 | fn exec_query(world: &ServerWorld, query: Query, token: &JobToken) -> Result<Vec<SymbolInformation>> { | 190 | fn exec_query( |
191 | world: &ServerWorld, | ||
192 | query: Query, | ||
193 | token: &JobToken, | ||
194 | ) -> Result<Vec<SymbolInformation>> { | ||
184 | let mut res = Vec::new(); | 195 | let mut res = Vec::new(); |
185 | for (file_id, symbol) in world.analysis().symbol_search(query, token) { | 196 | for (file_id, symbol) in world.analysis().symbol_search(query, token) { |
186 | let line_index = world.analysis().file_line_index(file_id); | 197 | let line_index = world.analysis().file_line_index(file_id); |
187 | let info = SymbolInformation { | 198 | let info = SymbolInformation { |
188 | name: symbol.name.to_string(), | 199 | name: symbol.name.to_string(), |
189 | kind: symbol.kind.conv |