diff options
Diffstat (limited to 'crates')
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(), | 200 | kind: symbol.kind.conv(), |
190 | location: to_location( | 201 | location: to_location(file_id, symbol.node_range, world, &line_index)?, |
191 | file_id, symbol.node_range, | ||
192 | world, &line_index | ||
193 | )?, | ||
194 | container_name: None, | 202 | container_name: None, |
195 | deprecated: None, | 203 | deprecated: None, |
196 | }; | 204 | }; |
197 | res.push(info); | 205 | res.push(info); |
198 | }; | 206 | } |
199 | Ok(res) | 207 | Ok(res) |
200 | } | 208 | } |
201 | } | 209 | } |
@@ -209,12 +217,12 @@ pub fn handle_goto_definition( | |||
209 | let line_index = world.analysis().file_line_index(file_id); | 217 | let line_index = world.analysis().file_line_index(file_id); |
210 | let offset = params.position.conv_with(&line_index); | 218 | let offset = params.position.conv_with(&line_index); |
211 | let mut res = Vec::new(); | 219 | let mut res = Vec::new(); |
212 | for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset, &token) { | 220 | for (file_id, symbol) in world |
221 | .analysis() | ||
222 | .approximately_resolve_symbol(file_id, offset, &token) | ||
223 | { | ||
213 | let line_index = world.analysis().file_line_index(file_id); | 224 | let line_index = world.analysis().file_line_index(file_id); |
214 | let location = to_location( | 225 | let location = to_location(file_id, symbol.node_range, &world, &line_index)?; |
215 | file_id, symbol.node_range, | ||
216 | &world, &line_index, | ||
217 | )?; | ||
218 | res.push(location) | 226 | res.push(location) |
219 | } | 227 | } |
220 | Ok(Some(req::GotoDefinitionResponse::Array(res))) | 228 | Ok(Some(req::GotoDefinitionResponse::Array(res))) |
@@ -229,10 +237,7 @@ pub fn handle_parent_module( | |||
229 | let mut res = Vec::new(); | 237 | let mut res = Vec::new(); |
230 | for (file_id, symbol) in world.analysis().parent_module(file_id) { | 238 | for (file_id, symbol) in world.analysis().parent_module(file_id) { |
231 | let line_index = world.analysis().file_line_index(file_id); | 239 | let line_index = world.analysis().file_line_index(file_id); |
232 | let location = to_location( | 240 | let location = to_location(file_id, symbol.node_range, &world, &line_index)?; |
233 | file_id, symbol.node_range, | ||
234 | &world, &line_index | ||
235 | )?; | ||
236 | res.push(location); | 241 | res.push(location); |
237 | } | 242 | } |
238 | Ok(res) | 243 | Ok(res) |
@@ -259,21 +264,16 @@ pub fn handle_runnables( | |||
259 | let r = req::Runnable { | 264 | let r = req::Runnable { |
260 | range: runnable.range.conv_with(&line_index), | 265 | range: runnable.range.conv_with(&line_index), |
261 | label: match &runnable.kind { | 266 | label: match &runnable.kind { |
262 | RunnableKind::Test { name } => | 267 | RunnableKind::Test { name } => format!("test {}", name), |
263 | format!("test {}", name), | 268 | RunnableKind::Bin => "run binary".to_string(), |
264 | RunnableKind::Bin => | ||
265 | "run binary".to_string(), | ||
266 | }, | 269 | }, |
267 | bin: "cargo".to_string(), | 270 | bin: "cargo".to_string(), |
268 | args, | 271 | args, |
269 | env: { | 272 | env: { |
270 | let mut m = FxHashMap::default(); | 273 | let mut m = FxHashMap::default(); |
271 | m.insert( | 274 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); |
272 | "RUST_BACKTRACE".to_string(), | ||
273 | "short".to_string(), | ||
274 | ); | ||
275 | m | 275 | m |
276 | } | 276 | }, |
277 | }; | 277 | }; |
278 | res.push(r); | 278 | res.push(r); |
279 | } | 279 | } |
@@ -283,10 +283,16 @@ pub fn handle_runnables( | |||
283 | let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id).first() { | 283 | let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id).first() { |
284 | let file_id = world.analysis().crate_root(crate_id); | 284 | let file_id = world.analysis().crate_root(crate_id); |
285 | let path = world.path_map.get_path(file_id); | 285 | let path = world.path_map.get_path(file_id); |
286 | world.workspaces.iter() | 286 | world |
287 | .workspaces | ||
288 | .iter() | ||
287 | .filter_map(|ws| { | 289 | .filter_map(|ws| { |
288 | let tgt = ws.target_by_root(path)?; | 290 | let tgt = ws.target_by_root(path)?; |
289 | Some((tgt.package(ws).name(ws).clone(), tgt.name(ws).clone(), tgt.kind(ws))) | 291 | Some(( |
292 | tgt.package(ws).name(ws).clone(), | ||
293 | tgt.name(ws).clone(), | ||
294 | tgt.kind(ws), | ||
295 | )) | ||
290 | }) | 296 | }) |
291 | .next() | 297 | .next() |
292 | } else { | 298 | } else { |
@@ -294,22 +300,22 @@ pub fn handle_runnables( | |||
294 | }; | 300 | }; |
295 | let mut res = Vec::new(); | 301 | let mut res = Vec::new(); |
296 | match kind { | 302 | match kind { |
297 | RunnableKind::Test { name } => { | 303 | RunnableKind::Test { name } => { |
298 | res.push("test".to_string()); | 304 | res.push("test".to_string()); |
299 | if let Some((pkg_name, tgt_name, tgt_kind)) = spec { | 305 | if let Some((pkg_name, tgt_name, tgt_kind)) = spec { |
300 | spec_args(pkg_name, tgt_name, tgt_kind, &mut res); | 306 | spec_args(pkg_name, tgt_name, tgt_kind, &mut res); |
301 | } | ||
302 | res.push("--".to_string()); | ||
303 | res.push(name.to_string()); | ||
304 | res.push("--nocapture".to_string()); | ||
305 | } | 307 | } |
306 | RunnableKind::Bin => { | 308 | res.push("--".to_string()); |
307 | res.push("run".to_string()); | 309 | res.push(name.to_string()); |
308 | if let Some((pkg_name, tgt_name, tgt_kind)) = spec { | 310 | res.push("--nocapture".to_string()); |
309 | spec_args(pkg_name, tgt_name, tgt_kind, &mut res); | 311 | } |
310 | } | 312 | RunnableKind::Bin => { |
313 | res.push("run".to_string()); | ||
314 | if let Some((pkg_name, tgt_name, tgt_kind)) = spec { | ||
315 | spec_args(pkg_name, tgt_name, tgt_kind, &mut res); | ||
311 | } | 316 | } |
312 | } | 317 | } |
318 | } | ||
313 | res | 319 | res |
314 | } | 320 | } |
315 | 321 | ||
@@ -362,12 +368,13 @@ pub fn handle_completion( | |||
362 | None => return Ok(None), | 368 | None => return Ok(None), |
363 | Some(items) => items, | 369 | Some(items) => items, |
364 | }; | 370 | }; |
365 | let items = items.into_iter() | 371 | let items = items |
372 | .into_iter() | ||
366 | .map(|item| { | 373 | .map(|item| { |
367 | let mut res = CompletionItem { | 374 | let mut res = CompletionItem { |
368 | label: item.label, | 375 | label: item.label, |
369 | filter_text: item.lookup, | 376 | filter_text: item.lookup, |
370 | .. Default::default() | 377 | ..Default::default() |
371 | }; | 378 | }; |
372 | if let Some(snip) = item.snippet { | 379 | if let Some(snip) = item.snippet { |
373 | res.insert_text = Some(snip); | 380 | res.insert_text = Some(snip); |
@@ -389,24 +396,27 @@ pub fn handle_folding_range( | |||
389 | let file_id = params.text_document.try_conv_with(&world)?; | 396 | let file_id = params.text_document.try_conv_with(&world)?; |
390 | let line_index = world.analysis().file_line_index(file_id); | 397 | let line_index = world.analysis().file_line_index(file_id); |
391 | 398 | ||
392 | let res = Some(world.analysis() | 399 | let res = Some( |
393 | .folding_ranges(file_id) | 400 | world |
394 | .into_iter() | 401 | .analysis() |
395 | .map(|fold| { | 402 | .folding_ranges(file_id) |
396 | let kind = match fold.kind { | 403 | .into_iter() |
397 | FoldKind::Comment => FoldingRangeKind::Comment, | 404 | .map(|fold| { |
398 | FoldKind::Imports => FoldingRangeKind::Imports | 405 | let kind = match fold.kind { |
399 | }; | 406 | FoldKind::Comment => FoldingRangeKind::Comment, |
400 | let range = fold.range.conv_with(&line_index); | 407 | FoldKind::Imports => FoldingRangeKind::Imports, |
401 | FoldingRange { | 408 | }; |
402 | start_line: range.start.line, | 409 | let range = fold.range.conv_with(&line_index); |
403 | start_character: Some(range.start.character), | 410 | FoldingRange { |
404 | end_line: range.end.line, | 411 | start_line: range.start.line, |
405 | end_character: Some(range.start.character), | 412 | start_character: Some(range.start.character), |
406 | kind: Some(kind) | 413 | end_line: range.end.line, |
407 | } | 414 | end_character: Some(range.start.character), |
408 | }) | 415 | kind: Some(kind), |
409 | .collect()); | 416 | } |
417 | }) | ||
418 | .collect(), | ||
419 | ); | ||
410 | 420 | ||
411 | Ok(res) | 421 | Ok(res) |
412 | } | 422 | } |
@@ -422,25 +432,28 @@ pub fn handle_signature_help( | |||
422 | let line_index = world.analysis().file_line_index(file_id); | 432 | let line_index = world.analysis().file_line_index(file_id); |
423 | let offset = params.position.conv_with(&line_index); | 433 | let offset = params.position.conv_with(&line_index); |
424 | 434 | ||
425 | if let Some((descriptor, active_param)) = world.analysis().resolve_callable(file_id, offset, &token) { | 435 | if let Some((descriptor, active_param)) = |
426 | let parameters : Vec<ParameterInformation> = | 436 | world.analysis().resolve_callable(file_id, offset, &token) |
427 | descriptor.params.iter().map(|param| | 437 | { |
428 | ParameterInformation { | 438 | let parameters: Vec<ParameterInformation> = descriptor |
429 | label: param.clone(), | 439 | .params |
430 | documentation: None | 440 | .iter() |
431 | } | 441 | .map(|param| ParameterInformation { |
432 | ).collect(); | 442 | label: param.clone(), |
443 | documentation: None, | ||
444 | }) | ||
445 | .collect(); | ||
433 | 446 | ||
434 | let sig_info = SignatureInformation { | 447 | let sig_info = SignatureInformation { |
435 | label: descriptor.label, | 448 | label: descriptor.label, |
436 | documentation: None, | 449 | documentation: None, |
437 | parameters: Some(parameters) | 450 | parameters: Some(parameters), |
438 | }; | 451 | }; |
439 | 452 | ||
440 | Ok(Some(req::SignatureHelp { | 453 | Ok(Some(req::SignatureHelp { |
441 | signatures: vec![sig_info], | 454 | signatures: vec![sig_info], |
442 | active_signature: Some(0), | 455 | active_signature: Some(0), |
443 | active_parameter: active_param.map(|a| a as u64) | 456 | active_parameter: active_param.map(|a| a as u64), |
444 | })) | 457 | })) |
445 | } else { | 458 | } else { |
446 | Ok(None) | 459 | Ok(None) |
@@ -457,7 +470,10 @@ pub fn handle_code_action( | |||
457 | let range = params.range.conv_with(&line_index); | 470 | let range = params.range.conv_with(&line_index); |
458 | 471 | ||
459 | let assists = world.analysis().assists(file_id, range).into_iter(); | 472 | let assists = world.analysis().assists(file_id, range).into_iter(); |
460 | let fixes = world.analysis().diagnostics(file_id).into_iter() | 473 | let fixes = world |
474 | .analysis() | ||
475 | .diagnostics(file_id) | ||
476 | .into_iter() | ||
461 | .filter_map(|d| Some((d.range, d.fix?))) | 477 | .filter_map(|d| Some((d.range, d.fix?))) |
462 | .filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start())) | 478 | .filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start())) |
463 | .map(|(_range, fix)| fix); | 479 | .map(|(_range, fix)| fix); |
@@ -483,7 +499,9 @@ pub fn publish_diagnostics( | |||
483 | ) -> Result<req::PublishDiagnosticsParams> { | 499 | ) -> Result<req::PublishDiagnosticsParams> { |
484 | let uri = world.file_id_to_uri(file_id)?; | 500 | let uri = world.file_id_to_uri(file_id)?; |
485 | let line_index = world.analysis().file_line_index(file_id); | 501 | let line_index = world.analysis().file_line_index(file_id); |
486 | let diagnostics = world.analysis().diagnostics(file_id) | 502 | let diagnostics = world |
503 | .analysis() | ||
504 | .diagnostics(file_id) | ||
487 | .into_iter() | 505 | .into_iter() |
488 | .map(|d| Diagnostic { | 506 | .map(|d| Diagnostic { |
489 | range: d.range.conv_with(&line_index), | 507 | range: d.range.conv_with(&line_index), |
@@ -492,7 +510,8 @@ pub fn publish_diagnostics( | |||
492 | source: Some("rust-analyzer".to_string()), | 510 | source: Some("rust-analyzer".to_string()), |
493 | message: d.message, | 511 | message: d.message, |
494 | related_information: None, | 512 | related_information: None, |
495 | }).collect(); | 513 | }) |
514 | .collect(); | ||
496 | Ok(req::PublishDiagnosticsParams { uri, diagnostics }) | 515 | Ok(req::PublishDiagnosticsParams { uri, diagnostics }) |
497 | } | 516 | } |
498 | 517 | ||
@@ -509,10 +528,13 @@ pub fn publish_decorations( | |||
509 | 528 | ||
510 | fn highlight(world: &ServerWorld, file_id: FileId) -> Vec<Decoration> { | 529 | fn highlight(world: &ServerWorld, file_id: FileId) -> Vec<Decoration> { |
511 | let line_index = world.analysis().file_line_index(file_id); | 530 | let line_index = world.analysis().file_line_index(file_id); |
512 | world.analysis().highlight(file_id) | 531 | world |
532 | .analysis() | ||
533 | .highlight(file_id) | ||
513 | .into_iter() | 534 | .into_iter() |
514 | .map(|h| Decoration { | 535 | .map(|h| Decoration { |
515 | range: h.range.conv_with(&line_index), | 536 | range: h.range.conv_with(&line_index), |
516 | tag: h.tag, | 537 | tag: h.tag, |
517 | }).collect() | 538 | }) |
539 | .collect() | ||
518 | } | 540 | } |
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs index cf2477cb5..a11baf4aa 100644 --- a/crates/ra_lsp_server/src/main_loop/mod.rs +++ b/crates/ra_lsp_server/src/main_loop/mod.rs | |||
@@ -1,29 +1,26 @@ | |||
1 | mod handlers; | 1 | mod handlers; |
2 | mod subscriptions; | 2 | mod subscriptions; |
3 | 3 | ||
4 | use std::{ | 4 | use std::path::PathBuf; |
5 | path::PathBuf, | ||
6 | }; | ||
7 | 5 | ||
8 | use serde::{Serialize, de::DeserializeOwned}; | 6 | use crossbeam_channel::{unbounded, Receiver, Sender}; |
9 | use crossbeam_channel::{unbounded, Sender, Receiver}; | ||
10 | use rayon::{self, ThreadPool}; | ||
11 | use languageserver_types::{NumberOrString}; | ||
12 | use ra_analysis::{FileId, JobHandle, JobToken, LibraryData}; | ||
13 | use gen_lsp_server::{ | 7 | use gen_lsp_server::{ |
14 | RawRequest, RawNotification, RawMessage, RawResponse, ErrorCode, | 8 | handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, |
15 | handle_shutdown, | ||
16 | }; | 9 | }; |
10 | use languageserver_types::NumberOrString; | ||
11 | use ra_analysis::{FileId, JobHandle, JobToken, LibraryData}; | ||
12 | use rayon::{self, ThreadPool}; | ||
17 | use rustc_hash::FxHashMap; | 13 | use rustc_hash::FxHashMap; |
14 | use serde::{de::DeserializeOwned, Serialize}; | ||
18 | 15 | ||
19 | use crate::{ | 16 | use crate::{ |
17 | main_loop::subscriptions::Subscriptions, | ||
18 | project_model::{workspace_loader, CargoWorkspace}, | ||
20 | req, | 19 | req, |
21 | Result, | 20 | server_world::{ServerWorld, ServerWorldState}, |
22 | vfs::{self, FileEvent}, | ||
23 | server_world::{ServerWorldState, ServerWorld}, | ||
24 | main_loop::subscriptions::{Subscriptions}, | ||
25 | project_model::{CargoWorkspace, workspace_loader}, | ||
26 | thread_watcher::Worker, | 21 | thread_watcher::Worker, |
22 | vfs::{self, FileEvent}, | ||
23 | Result, | ||
27 | }; | 24 | }; |
28 | 25 | ||
29 | #[derive(Debug)] | 26 | #[derive(Debug)] |
@@ -147,56 +144,50 @@ fn main_loop_inner( | |||
147 | } | 144 | } |
148 | state_changed = true; | 145 | state_changed = true; |
149 | } | 146 | } |
150 | Event::Ws(ws) => { | 147 | Event::Ws(ws) => match ws { |
151 | match ws { | 148 | Ok(ws) => { |
152 | Ok(ws) => { | 149 | let workspaces = vec![ws]; |
153 | let workspaces = vec![ws]; | 150 | feedback(internal_mode, "workspace loaded", msg_sender); |
154 | feedback(internal_mode, "workspace loaded", msg_sender); | 151 | for ws in workspaces.iter() { |
155 | for ws in workspaces.iter() { | 152 | for pkg in ws.packages().filter(|pkg| !pkg.is_member(ws)) { |
156 | for pkg in ws.packages().filter(|pkg| !pkg.is_member(ws)) { | 153 | debug!("sending root, {}", pkg.root(ws).to_path_buf().display()); |
157 | debug!("sending root, {}", pkg.root(ws).to_path_buf().display()); | 154 | fs_worker.send(pkg.root(ws).to_path_buf()); |
158 | fs_worker.send(pkg.root(ws).to_path_buf()); | ||
159 | } | ||
160 | } | 155 | } |
161 | state.set_workspaces(workspaces); | ||
162 | state_changed = true; | ||
163 | } | 156 | } |
164 | Err(e) => warn!("loading workspace failed: {}", e), | 157 | state.set_workspaces(workspaces); |
158 | state_changed = true; | ||
165 | } | 159 | } |
166 | } | 160 | Err(e) => warn!("loading workspace failed: {}", e), |
161 | }, | ||
167 | Event::Lib(lib) => { | 162 | Event::Lib(lib) => { |
168 | feedback(internal_mode, "library loaded", msg_sender); | 163 | feedback(internal_mode, "library loaded", msg_sender); |
169 | state.add_lib(lib); | 164 | state.add_lib(lib); |
170 | } | 165 | } |
171 | Event::Msg(msg) => { | 166 | Event::Msg(msg) => match msg { |
172 | match msg { | 167 | RawMessage::Request(req) => { |
173 | RawMessage::Request(req) => { | 168 | let req = match handle_shutdown(req, msg_sender) { |
174 | let req = match handle_shutdown(req, msg_sender) { | 169 | Some(req) => req, |
175 | Some(req) => req, | 170 | None => return Ok(()), |
176 | None => return Ok(()), | 171 | }; |
177 | }; | 172 | match on_request(state, pending_requests, pool, &task_sender, req)? { |
178 | match on_request(state, pending_requests, pool, &task_sender, req)? { | 173 | None => (), |
179 | None => (), | 174 | Some(req) => { |
180 | Some(req) => { | 175 | error!("unknown request: {:?}", req); |
181 | error!("unknown request: {:?}", req); | 176 | let resp = RawResponse::err( |
182 | let resp = RawResponse::err( | 177 | req.id, |
183 | req.id, | 178 | ErrorCode::MethodNotFound as i32, |
184 | ErrorCode::MethodNotFound as i32, | 179 | "unknown request".to_string(), |
185 | "unknown request".to_string(), | 180 | ); |
186 | ); | 181 | msg_sender.send(RawMessage::Response(resp)) |
187 | msg_sender.send(RawMessage::Response(resp)) | ||
188 | } | ||
189 | } | 182 | } |
190 | } | 183 | } |
191 | RawMessage::Notification(not) => { | ||
192 | on_notification(msg_sender, state, pending_requests, subs, not)?; | ||
193 | state_changed = true; | ||
194 | } | ||
195 | RawMessage::Response(resp) => { | ||
196 | error!("unexpected response: {:?}", resp) | ||
197 | } | ||
198 | } | 184 | } |
199 | } | 185 | RawMessage::Notification(not) => { |
186 | on_notification(msg_sender, state, pending_requests, subs, not)?; | ||
187 | state_changed = true; | ||
188 | } | ||
189 | RawMessage::Response(resp) => error!("unexpected response: {:?}", resp), | ||
190 | }, | ||
200 | }; | 191 | }; |
201 | 192 | ||
202 | if state_changed { | 193 | if state_changed { |
@@ -222,8 +213,7 @@ fn on_task( | |||
222 | } | 213 | } |
223 | msg_sender.send(RawMessage::Response(response)) | 214 | msg_sender.send(RawMessage::Response(response)) |
224 | } | 215 | } |
225 | Task::Notify(n) => | 216 | Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)), |
226 | msg_sender.send(RawMessage::Notification(n)), | ||
227 | } | 217 | } |
228 | } | 218 | } |
229 | 219 | ||
@@ -237,7 +227,9 @@ fn on_request( | |||
237 | let mut pool_dispatcher = PoolDispatcher { | 227 | let mut pool_dispatcher = PoolDispatcher { |
238 | req: Some(req), | 228 | req: Some(req), |
239 | res: None, | 229 | res: None, |
240 | pool, world, sender | 230 | pool, |
231 | world, | ||
232 | sender, | ||
241 | }; | 233 | }; |
242 | let req = pool_dispatcher | 234 | let req = pool_dispatcher |
243 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? | 235 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? |
@@ -262,7 +254,7 @@ fn on_request( | |||
262 | let inserted = pending_requests.insert(id, handle).is_none(); | 254 | let inserted = pending_requests.insert(id, handle).is_none(); |
263 | assert!(inserted, "duplicate request: {}", id); | 255 | assert!(inserted, "duplicate request: {}", id); |
264 | Ok(None) | 256 | Ok(None) |
265 | }, | 257 | } |
266 | Err(req) => Ok(Some(req)), | 258 | Err(req) => Ok(Some(req)), |
267 | } | 259 | } |
268 | } | 260 | } |
@@ -285,45 +277,53 @@ fn on_notification( | |||
285 | if let Some(handle) = pending_requests.remove(&id) { | 277 | if let Some(handle) = pending_requests.remove(&id) { |
286 | handle.cancel(); | 278 | handle.cancel(); |
287 | } | 279 | } |
288 | return Ok(()) | 280 | return Ok(()); |
289 | } | 281 | } |
290 | Err(not) => not, | 282 | Err(not) => not, |
291 | }; | 283 | }; |
292 | let not = match not.cast::<req::DidOpenTextDocument>() { | 284 | let not = match not.cast::<req::DidOpenTextDocument>() { |
293 | Ok(params) => { | 285 | Ok(params) => { |
294 | let uri = params.text_document.uri; | 286 | let uri = params.text_document.uri; |
295 | let path = uri.to_file_path() | 287 | let path = uri |
288 | .to_file_path() | ||
296 | .map_err(|()| format_err!("invalid uri: {}", uri))?; | 289 | .map_err(|()| format_err!("invalid uri: {}", uri))?; |
297 | let file_id = state.add_mem_file(path, params.text_document.text); | 290 | let file_id = state.add_mem_file(path, params.text_document.text); |
298 | subs.add_sub(file_id); | 291 | subs.add_sub(file_id); |
299 | return Ok(()) | 292 | return Ok(()); |
300 | } | 293 | } |
301 | Err(not) => not, | 294 | Err(not) => not, |
302 | }; | 295 | }; |
303 | let not = match not.cast::<req::DidChangeTextDocument>() { | 296 | let not = match not.cast::<req::DidChangeTextDocument>() { |
304 | Ok(mut params) => { | 297 | Ok(mut params) => { |
305 | let uri = params.text_document.uri; | 298 | let uri = params.text_document.uri; |
306 | let path = uri.to_file_path() | 299 | let path = uri |
300 | .to_file_path() | ||
307 | .map_err(|()| format_err!("invalid uri: {}", uri))?; | 301 | .map_err(|()| format_err!("invalid uri: {}", uri))?; |
308 | let text = params.content_changes.pop() | 302 | let text = params |
303 | .content_changes | ||
304 | .pop() | ||
309 | .ok_or_else(|| format_err!("empty changes"))? | 305 | .ok_or_else(|| format_err!("empty changes"))? |
310 | .text; | 306 | .text; |
311 | state.change_mem_file(path.as_path(), text)?; | 307 | state.change_mem_file(path.as_path(), text)?; |
312 | return Ok(()) | 308 | return Ok(()); |
313 | } | 309 | } |
314 | Err(not) => not, | 310 | Err(not) => not, |
315 | }; | 311 | }; |
316 | let not = match not.cast::<req::DidCloseTextDocument>() { | 312 | let not = match not.cast::<req::DidCloseTextDocument>() { |
317 | Ok(params) => { | 313 | Ok(params) => { |
318 | let uri = params.text_document.uri; | 314 | let uri = params.text_document.uri; |
319 | let path = uri.to_file_path() | 315 | let path = uri |
316 | .to_file_path() | ||
320 | .map_err(|()| format_err!("invalid uri: {}", uri))?; | 317 | .map_err(|()| format_err!("invalid uri: {}", uri))?; |
321 | let file_id = state.remove_mem_file(path.as_path())?; | 318 | let file_id = state.remove_mem_file(path.as_path())?; |
322 | subs.remove_sub(file_id); | 319 | subs.remove_sub(file_id); |
323 | let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() }; | 320 | let params = req::PublishDiagnosticsParams { |
321 | uri, | ||
322 | diagnostics: Vec::new(), | ||
323 | }; | ||
324 | let not = RawNotification::new::<req::PublishDiagnostics>(¶ms); | 324 | let not = RawNotification::new::<req::PublishDiagnostics>(¶ms); |
325 | msg_sender.send(RawMessage::Notification(not)); | 325 | msg_sender.send(RawMessage::Notification(not)); |
326 | return Ok(()) | 326 | return Ok(()); |
327 | } | 327 | } |
328 | Err(not) => not, | 328 | Err(not) => not, |
329 | }; | 329 | }; |
@@ -342,11 +342,12 @@ struct PoolDispatcher<'a> { | |||
342 | impl<'a> PoolDispatcher<'a> { | 342 | impl<'a> PoolDispatcher<'a> { |
343 | fn on<'b, R>( | 343 | fn on<'b, R>( |
344 | &'b mut self, | 344 | &'b mut self, |
345 | f: fn(ServerWorld, R::Params, JobToken) -> Result<R::Result> | 345 | f: fn(ServerWorld, R::Params, JobToken) -> Result<R::Result>, |
346 | ) -> Result<&'b mut Self> | 346 | ) -> Result<&'b mut Self> |
347 | where R: req::Request, | 347 | where |
348 | R::Params: DeserializeOwned + Send + 'static, | 348 | R: req::Request, |
349 | R::Result: Serialize + 'static, | 349 | R::Params: DeserializeOwned + Send + 'static, |
350 | R::Result: Serialize + 'static, | ||
350 | { | 351 | { |
351 | let req = match self.req.take() { | 352 | let req = match self.req.take() { |
352 | None => return Ok(self), | 353 | None => return Ok(self), |
@@ -360,16 +361,16 @@ impl<'a> PoolDispatcher<'a> { | |||
360 | self.pool.spawn(move || { | 361 | self.pool.spawn(move || { |
361 | let resp = match f(world, params, token) { | 362 | let resp = match f(world, params, token) { |
362 | Ok(resp) => RawResponse::ok::<R>(id, &resp), | 363 | Ok(resp) => RawResponse::ok::<R>(id, &resp), |
363 | Err(e) => RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string()), | 364 | Err(e) => { |
365 | RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string()) | ||
366 | } | ||
364 | }; | 367 | }; |
365 | let task = Task::Respond(resp); | 368 | let task = Task::Respond(resp); |
366 | sender.send(task); | 369 | sender.send(task); |
367 | }); | 370 | }); |
368 | self.res = Some((id, handle)); | 371 | self.res = Some((id, handle)); |
369 | } | 372 | } |
370 | Err(req) => { | 373 | Err(req) => self.req = Some(req), |
371 | self.req = Some(req) | ||
372 | } | ||
373 | } | 374 | } |
374 | Ok(self) | 375 | Ok(self) |
375 | } | 376 | } |
@@ -392,18 +393,14 @@ fn update_file_notifications_on_threadpool( | |||
392 | pool.spawn(move || { | 393 | pool.spawn(move || { |
393 | for file_id in subscriptions { | 394 | for file_id in subscriptions { |
394 | match handlers::publish_diagnostics(&world, file_id) { | 395 | match handlers::publish_diagnostics(&world, file_id) { |
395 | Err(e) => { | 396 | Err(e) => error!("failed to compute diagnostics: {:?}", e), |
396 | error!("failed to compute diagnostics: {:?}", e) | ||
397 | } | ||
398 | Ok(params) => { | 397 | Ok(params) => { |
399 | let not = RawNotification::new::<req::PublishDiagnostics>(¶ms); | 398 | let not = RawNotification::new::<req::PublishDiagnostics>(¶ms); |
400 | sender.send(Task::Notify(not)); | 399 | sender.send(Task::Notify(not)); |
401 | } | 400 | } |
402 | } | 401 | } |
403 | match handlers::publish_decorations(&world, file_id) { | 402 | match handlers::publish_decorations(&world, file_id) { |
404 | Err(e) => { | 403 | Err(e) => error!("failed to compute decorations: {:?}", e), |
405 | error!("failed to compute decorations: {:?}", e) | ||
406 | } | ||
407 | Ok(params) => { | 404 | Ok(params) => { |
408 | let not = RawNotification::new::<req::PublishDecorations>(¶ms); | 405 | let not = RawNotification::new::<req::PublishDecorations>(¶ms); |
409 | sender.send(Task::Notify(not)) | 406 | sender.send(Task::Notify(not)) |
diff --git a/crates/ra_lsp_server/src/main_loop/subscriptions.rs b/crates/ra_lsp_server/src/main_loop/subscriptions.rs index 310153382..03f41e870 100644 --- a/crates/ra_lsp_server/src/main_loop/subscriptions.rs +++ b/crates/ra_lsp_server/src/main_loop/subscriptions.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use rustc_hash::FxHashSet; | ||
2 | use ra_analysis::FileId; | 1 | use ra_analysis::FileId; |
2 | use rustc_hash::FxHashSet; | ||
3 | 3 | ||
4 | pub struct Subscriptions { | 4 | pub struct Subscriptions { |
5 | subs: FxHashSet<FileId>, | 5 | subs: FxHashSet<FileId>, |
@@ -7,7 +7,9 @@ pub struct Subscriptions { | |||
7 | 7 | ||
8 | impl Subscriptions { | 8 | impl Subscriptions { |
9 | pub fn new() -> Subscriptions { | 9 | pub fn new() -> Subscriptions { |
10 | Subscriptions { subs: FxHashSet::default() } | 10 | Subscriptions { |
11 | subs: FxHashSet::default(), | ||
12 | } | ||
11 | } | 13 | } |
12 | pub fn add_sub(&mut self, file_id: FileId) { | 14 | pub fn add_sub(&mut self, file_id: FileId) { |
13 | self.subs.insert(file_id); | 15 | self.subs.insert(file_id); |
diff --git a/crates/ra_lsp_server/src/path_map.rs b/crates/ra_lsp_server/src/path_map.rs index 19c3b1d3b..585013acd 100644 --- a/crates/ra_lsp_server/src/path_map.rs +++ b/crates/ra_lsp_server/src/path_map.rs | |||
@@ -1,11 +1,13 @@ | |||
1 | use std::path::{PathBuf, Path, Component}; | ||
2 | use im; | 1 | use im; |
3 | use relative_path::RelativePath; | ||
4 | use ra_analysis::{FileId, FileResolver}; | 2 | use ra_analysis::{FileId, FileResolver}; |
3 | use relative_path::RelativePath; | ||
4 | |||
5 | use std::path::{Component, Path, PathBuf}; | ||
5 | 6 | ||
6 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 7 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
7 | pub enum Root { | 8 | pub enum Root { |
8 | Workspace, Lib | 9 | Workspace, |
10 | Lib, | ||
9 | } | 11 | } |
10 | 12 | ||
11 | #[derive(Debug, Default, Clone)] | 13 | #[derive(Debug, Default, Clone)] |
@@ -21,7 +23,8 @@ impl PathMap { | |||
21 | Default::default() | 23 | Default::default() |
22 | } | 24 | } |
23 | pub fn get_or_insert(&mut self, path: PathBuf, root: Root) -> FileId { | 25 | pub fn get_or_insert(&mut self, path: PathBuf, root: Root) -> FileId { |
24 | self.path2id.get(path.as_path()) | 26 | self.path2id |
27 | .get(path.as_path()) | ||
25 | .map(|&id| id) | 28 | .map(|&id| id) |
26 | .unwrap_or_else(|| { | 29 | .unwrap_or_else(|| { |
27 | let id = self.new_file_id(); | 30 | let id = self.new_file_id(); |
@@ -33,9 +36,7 @@ impl PathMap { | |||
33 | self.path2id.get(path).map(|&id| id) | 36 | self.path2id.get(path).map(|&id| id) |
34 | } | 37 | } |
35 | pub fn get_path(&self, file_id: FileId) -> &Path { | 38 | pub fn get_path(&self, file_id: FileId) -> &Path { |
36 | self.id2path.get(&file_id) | 39 | self.id2path.get(&file_id).unwrap().as_path() |
37 | .unwrap() | ||
38 | .as_path() | ||
39 | } | 40 | } |
40 | pub fn get_root(&self, file_id: FileId) -> Root { | 41 | pub fn get_root(&self, file_id: FileId) -> Root { |
41 | self.id2root[&file_id] | 42 | self.id2root[&file_id] |
@@ -55,7 +56,12 @@ impl PathMap { | |||
55 | 56 | ||
56 | impl FileResolver for PathMap { | 57 | impl FileResolver for PathMap { |
57 | fn file_stem(&self, file_id: FileId) -> String { | 58 | fn file_stem(&self, file_id: FileId) -> String { |
58 | self.get_path(file_id).file_stem().unwrap().to_str().unwrap().to_string() | 59 | self.get_path(file_id) |
60 | .file_stem() | ||
61 | .unwrap() | ||
62 | .to_str() | ||
63 | .unwrap() | ||
64 | .to_string() | ||
59 | } | 65 | } |
60 | 66 | ||
61 | fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { | 67 | fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { |
@@ -101,10 +107,6 @@ mod test { | |||
101 | let mut m = PathMap::new(); | 107 | let mut m = PathMap::new(); |
102 | let id1 = m.get_or_insert(PathBuf::from("/foo"), Root::Workspace); | 108 | let id1 = m.get_or_insert(PathBuf::from("/foo"), Root::Workspace); |
103 | let id2 = m.get_or_insert(PathBuf::from("/foo/bar.rs"), Root::Workspace); | 109 | let id2 = m.get_or_insert(PathBuf::from("/foo/bar.rs"), Root::Workspace); |
104 | assert_eq!( | 110 | assert_eq!(m.resolve(id1, &RelativePath::new("bar.rs")), Some(id2),) |
105 | m.resolve(id1, &RelativePath::new("bar.rs")), | ||
106 | Some(id2), | ||
107 | ) | ||
108 | } | 111 | } |
109 | } | 112 | } |
110 | |||
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index c144d9596..d170ceb73 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs | |||
@@ -1,13 +1,12 @@ | |||
1 | use std::{ | ||
2 | path::{Path, PathBuf}, | ||
3 | }; | ||
4 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
5 | use cargo_metadata::{metadata_run, CargoOpt}; | 1 | use cargo_metadata::{metadata_run, CargoOpt}; |
6 | use ra_syntax::SmolStr; | 2 | use ra_syntax::SmolStr; |
3 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
4 | |||
5 | use std::path::{Path, PathBuf}; | ||
7 | 6 | ||
8 | use crate::{ | 7 | use crate::{ |
8 | thread_watcher::{ThreadWatcher, Worker}, | ||
9 | Result, | 9 | Result, |
10 | thread_watcher::{Worker, ThreadWatcher}, | ||
11 | }; | 10 | }; |
12 | 11 | ||
13 | #[derive(Debug, Clone)] | 12 | #[derive(Debug, Clone)] |
@@ -39,7 +38,12 @@ struct TargetData { | |||
39 | 38 | ||
40 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 39 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
41 | pub enum TargetKind { | 40 | pub enum TargetKind { |
42 | Bin, Lib, Example, Test, Bench, Other, | 41 | Bin, |
42 | Lib, | ||
43 | Example, | ||
44 | Test, | ||
45 | Bench, | ||
46 | Other, | ||
43 | } | 47 | } |
44 | 48 | ||
45 | impl Package { | 49 | impl Package { |
@@ -49,7 +53,7 @@ impl Package { | |||
49 | pub fn root(self, ws: &CargoWorkspace) -> &Path { | 53 | pub fn root(self, ws: &CargoWorkspace) -> &Path { |
50 | ws.pkg(self).manifest.parent().unwrap() | 54 | ws.pkg(self).manifest.parent().unwrap() |
51 | } | 55 | } |
52 | pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item=Target> + 'a { | 56 | pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a { |
53 | ws.pkg(self).targets.iter().cloned() | 57 | ws.pkg(self).targets.iter().cloned() |
54 | } | 58 | } |
55 | pub fn is_member(self, ws: &CargoWorkspace) -> bool { | 59 | pub fn is_member(self, ws: &CargoWorkspace) -> bool { |
@@ -78,13 +82,15 @@ impl CargoWorkspace { | |||
78 | let meta = metadata_run( | 82 | let meta = metadata_run( |
79 | Some(cargo_toml.as_path()), | 83 | Some(cargo_toml.as_path()), |
80 | true, | 84 | true, |
81 | Some(CargoOpt::AllFeatures) | 85 | Some(CargoOpt::AllFeatures), |
82 | ).map_err(|e| format_err!("cargo metadata failed: {}", e))?; | 86 | ) |
87 | .map_err(|e| format_err!("cargo metadata failed: {}", e))?; | ||
83 | let mut pkg_by_id = FxHashMap::default(); | 88 | let mut pkg_by_id = FxHashMap::default(); |
84 | let mut packages = Vec::new(); | 89 | let mut packages = Vec::new(); |
85 | let mut targets = Vec::new(); | 90 | let mut targets = Vec::new(); |
86 | 91 | ||
87 | let ws_members: FxHashSet<String> = meta.workspace_members | 92 | let ws_members: FxHashSet<String> = meta |
93 | .workspace_members | ||
88 | .into_iter() | 94 | .into_iter() |
89 | .map(|it| it.raw) | 95 | .map(|it| it.raw) |
90 | .collect(); | 96 | .collect(); |
@@ -114,7 +120,7 @@ impl CargoWorkspace { | |||
114 | 120 | ||
115 | Ok(CargoWorkspace { packages, targets }) | 121 | Ok(CargoWorkspace { packages, targets }) |
116 | } | 122 | } |
117 | pub fn packages<'a>(&'a self) -> impl Iterator<Item=Package> + 'a { | 123 | pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a { |
118 | (0..self.packages.len()).map(Package) | 124 | (0..self.packages.len()).map(Package) |
119 | } | 125 | } |
120 | pub fn target_by_root(&self, root: &Path) -> Option<Target> { | 126 | pub fn target_by_root(&self, root: &Path) -> Option<Target> { |
@@ -155,7 +161,7 @@ impl TargetKind { | |||
155 | "example" => TargetKind::Example, | 161 | "example" => TargetKind::Example, |
156 | _ if kind.contains("lib") => TargetKind::Lib, | 162 | _ if kind.contains("lib") => TargetKind::Lib, |
157 | _ => continue, | 163 | _ => continue, |
158 | } | 164 | }; |
159 | } | 165 | } |
160 | TargetKind::Other | 166 | TargetKind::Other |
161 | } | 167 | } |
@@ -170,6 +176,6 @@ pub fn workspace_loader() -> (Worker<PathBuf, Result<CargoWorkspace>>, ThreadWat | |||
170 | .into_iter() | 176 | .into_iter() |
171 | .map(|path| CargoWorkspace::from_cargo_metadata(path.as_path())) | 177 | .map(|path| CargoWorkspace::from_cargo_metadata(path.as_path())) |
172 | .for_each(|it| output_sender.send(it)) | 178 | .for_each(|it| output_sender.send(it)) |
173 | } | 179 | }, |
174 | ) | 180 | ) |
175 | } | 181 | } |
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index 1630edf7f..b76bfbcbc 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs | |||
@@ -1,20 +1,13 @@ | |||
1 | use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url}; | ||
1 | use rustc_hash::FxHashMap; | 2 | use rustc_hash::FxHashMap; |
2 | use languageserver_types::{TextDocumentIdentifier, Range, Url, Position, Location}; | ||
3 | use url_serde; | 3 | use url_serde; |
4 | 4 | ||
5 | pub use languageserver_types::{ | 5 | pub use languageserver_types::{ |
6 | request::*, notification::*, | 6 | notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CompletionParams, |
7 | InitializeResult, PublishDiagnosticsParams, | 7 | CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, |
8 | DocumentSymbolParams, DocumentSymbolResponse, | 8 | DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, |
9 | CodeActionParams, ApplyWorkspaceEditParams, | 9 | PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, |
10 | ExecuteCommandParams, | 10 | TextEdit, WorkspaceSymbolParams, |
11 | WorkspaceSymbolParams, | ||
12 | TextDocumentPositionParams, | ||
13 | TextEdit, | ||
14 | CompletionParams, CompletionResponse, | ||
15 | DocumentOnTypeFormattingParams, | ||
16 | TextDocumentEdit, | ||
17 | SignatureHelp, Hover | ||
18 | }; | 11 | }; |
19 | 12 | ||
20 | pub enum SyntaxTree {} | 13 | pub enum SyntaxTree {} |
@@ -28,7 +21,7 @@ impl Request for SyntaxTree { | |||
28 | #[derive(Deserialize, Debug)] | 21 | #[derive(Deserialize, Debug)] |
29 | #[serde(rename_all = "camelCase")] | 22 | #[serde(rename_all = "camelCase")] |
30 | pub struct SyntaxTreeParams { | 23 | pub struct SyntaxTreeParams { |
31 | pub text_document: TextDocumentIdentifier | 24 | pub text_document: TextDocumentIdentifier, |
32 | } | 25 | } |
33 | 26 | ||
34 | pub enum ExtendSelection {} | 27 | pub enum ExtendSelection {} |
@@ -94,7 +87,7 @@ pub struct PublishDecorationsParams { | |||
94 | #[serde(rename_all = "camelCase")] | 87 | #[serde(rename_all = "camelCase")] |
95 | pub struct Decoration { | 88 | pub struct Decoration { |
96 | pub range: Range, | 89 | pub range: Range, |
97 | pub tag: &'static str | 90 | pub tag: &'static str, |
98 | } | 91 | } |
99 | 92 | ||
100 | pub enum ParentModule {} | 93 | pub enum ParentModule {} |
@@ -167,14 +160,14 @@ pub struct SourceChange { | |||
167 | pub enum FileSystemEdit { | 160 | pub enum FileSystemEdit { |
168 | CreateFile { | 161 | CreateFile { |
169 | #[serde(with = "url_serde")] | 162 | #[serde(with = "url_serde")] |
170 | uri: Url | 163 | uri: Url, |
171 | }, | 164 | }, |
172 | MoveFile { | 165 | MoveFile { |
173 | #[serde(with = "url_serde")] | 166 | #[serde(with = "url_serde")] |
174 | src: Url, | 167 | src: Url, |
175 | #[serde(with = "url_serde")] | 168 | #[serde(with = "url_serde")] |
176 | dst: Url, | 169 | dst: Url, |
177 | } | 170 | }, |
178 | } | 171 | } |
179 | 172 | ||
180 | pub enum InternalFeedback {} | 173 | pub enum InternalFeedback {} |
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 9b3013ae8..35ff65ea1 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs | |||
@@ -1,18 +1,18 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | fs, | 2 | fs, |
3 | path::{PathBuf, Path}, | 3 | path::{Path, PathBuf}, |
4 | sync::Arc, | 4 | sync::Arc, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use rustc_hash::FxHashMap; | ||
8 | use languageserver_types::Url; | 7 | use languageserver_types::Url; |
9 | use ra_analysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData, FileResolver}; | 8 | use ra_analysis::{Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, LibraryData}; |
9 | use rustc_hash::FxHashMap; | ||
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | Result, | ||
13 | path_map::{PathMap, Root}, | 12 | path_map::{PathMap, Root}, |
14 | vfs::{FileEvent, FileEventKind}, | ||
15 | project_model::CargoWorkspace, | 13 | project_model::CargoWorkspace, |
14 | vfs::{FileEvent, FileEventKind}, | ||
15 | Result, | ||
16 | }; | 16 | }; |
17 | 17 | ||
18 | #[derive(Debug)] | 18 | #[derive(Debug)] |
@@ -42,16 +42,15 @@ impl ServerWorldState { | |||
42 | { | 42 | { |
43 | let pm = &mut self.path_map; | 43 | let pm = &mut self.path_map; |
44 | let mm = &mut self.mem_map; | 44 | let mm = &mut self.mem_map; |
45 | let changes = events.into_iter() | 45 | let changes = events |
46 | .into_iter() | ||
46 | .map(|event| { | 47 | .map(|event| { |
47 | let text = match event.kind { | 48 | let text = match event.kind { |
48 | FileEventKind::Add(text) => Some(text), | 49 | FileEventKind::Add(text) => Some(text), |
49 | }; | 50 | }; |
50 | (event.path, text) | 51 | (event.path, text) |
51 | }) | 52 | }) |
52 | .map(|(path, text)| { | 53 | .map(|(path, text)| (pm.get_or_insert(path, Root::Workspace), text)) |
53 | (pm.get_or_insert(path, Root::Workspace), text) | ||
54 | }) | ||
55 | .filter_map(|(id, text)| { | 54 | .filter_map(|(id, text)| { |
56 | if mm.contains_key(&id) { | 55 | if mm.contains_key(&id) { |
57 | mm.insert(id, text); | 56 | mm.insert(id, text); |
@@ -62,12 +61,17 @@ impl ServerWorldState { | |||
62 | }); | 61 | }); |
63 | self.analysis_host.change_files(changes); | 62 | self.analysis_host.change_files(changes); |
64 | } | 63 | } |
65 | self.analysis_host.set_file_resolver(Arc::new(self.path_map.clone())); | 64 | self.analysis_host |
65 | .set_file_resolver(Arc::new(self.path_map.clone())); | ||
66 | } | 66 | } |
67 | pub fn events_to_files(&mut self, events: Vec<FileEvent>) -> (Vec<(FileId, String)>, Arc<FileResolver>) { | 67 | pub fn events_to_files( |
68 | &mut self, | ||
69 | events: Vec<FileEvent>, | ||
70 | ) -> (Vec<(FileId, String)>, Arc<FileResolver>) { | ||
68 | let files = { | 71 | let files = { |
69 | let pm = &mut self.path_map; | 72 | let pm = &mut self.path_map; |
70 | events.into_iter() | 73 | events |
74 | .into_iter() | ||
71 | .map(|event| { | 75 | .map(|event| { |
72 | let text = match event.kind { | 76 | let text = match event.kind { |
73 | FileEventKind::Add(text) => text, | 77 | FileEventKind::Add(text) => text, |
@@ -86,7 +90,8 @@ impl ServerWorldState { | |||
86 | 90 | ||
87 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { | 91 | pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { |
88 | let file_id = self.path_map.get_or_insert(path, Root::Workspace); | 92 | let file_id = self.path_map.get_or_insert(path, Root::Workspace); |
89 | self.analysis_host.set_file_resolver(Arc::new(self.path_map.clone())); | 93 | self.analysis_host |
94 | .set_file_resolver(Arc::new(self.path_map.clone())); | ||
90 | self.mem_map.insert(file_id, None); | 95 | self.mem_map.insert(file_id, None); |
91 | if self.path_map.get_root(file_id) != Root::Lib { | 96 | if self.path_map.get_root(file_id) != Root::Lib { |
92 | self.analysis_host.change_file(file_id, Some(text)); | 97 | self.analysis_host.change_file(file_id, Some(text)); |
@@ -95,9 +100,10 @@ impl ServerWorldState { | |||
95 | } | 100 | } |
96 | 101 | ||
97 | pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> { | 102 | pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> { |
98 | let file_id = self.path_map.get_id(path).ok_or_else(|| { | 103 | let file_id = self |
99 | format_err!("change to unknown file: {}", path.display()) | 104 | .path_map |
100 | })?; | 105 | .get_id(path) |
106 | .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?; | ||
101 | if self.path_map.get_root(file_id) != Root::Lib { | 107 | if self.path_map.get_root(file_id) != Root::Lib { |
102 | self.analysis_host.change_file(file_id, Some(text)); | 108 | self.analysis_host.change_file(file_id, Some(text)); |
103 | } | 109 | } |
@@ -105,9 +111,10 @@ impl ServerWorldState { | |||
105 | } | 111 | } |
106 | 112 | ||
107 | pub fn remove_mem_file(&mut self, path: &Path) -> Result<FileId> { | 113 | pub fn remove_mem_file(&mut self, path: &Path) -> Result<FileId> { |
108 | let file_id = self.path_map.get_id(path).ok_or_else(|| { | 114 | let file_id = self |
109 | format_err!("change to unknown file: {}", path.display()) | 115 | .path_map |
110 | })?; | 116 | .get_id(path) |
117 | .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?; | ||
111 | match self.mem_map.remove(&file_id) { | 118 | match self.mem_map.remove(&file_id) { |
112 | Some(_) => (), | 119 | Some(_) => (), |
113 | None => bail!("unmatched close notification"), | 120 | None => bail!("unmatched close notification"), |
@@ -122,17 +129,17 @@ impl ServerWorldState { | |||
122 | pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { | 129 | pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) { |
123 | let mut crate_roots = FxHashMap::default(); | 130 | let mut crate_roots = FxHashMap::default(); |
124 | ws.iter() | 131 | ws.iter() |
125 | .flat_map(|ws| { | 132 | .flat_map(|ws| { |
126 | ws.packages() | 133 | ws.packages() |
127 | .flat_map(move |pkg| pkg.targets(ws)) | 134 | .flat_map(move |pkg| pkg.targets(ws)) |
128 | .map(move |tgt| tgt.root(ws)) | 135 | .map(move |tgt| tgt.root(ws)) |
129 | }) | 136 | }) |
130 | .for_each(|root| { | 137 | .for_each(|root| { |
131 | if let Some(file_id) = self.path_map.get_id(root) { | 138 | if let Some(file_id) = self.path_map.get_id(root) { |
132 | let crate_id = CrateId(crate_roots.len() as u32); | 139 | let crate_id = CrateId(crate_roots.len() as u32); |
133 | crate_roots.insert(crate_id, file_id); | 140 | crate_roots.insert(crate_id, file_id); |
134 | } | 141 | } |
135 | }); | 142 | }); |
136 | let crate_graph = CrateGraph { crate_roots }; | 143 | let crate_graph = CrateGraph { crate_roots }; |
137 | self.workspaces = Arc::new(ws); | 144 | self.workspaces = Arc::new(ws); |
138 | self.analysis_host.set_crate_graph(crate_graph); | 145 | self.analysis_host.set_crate_graph(crate_graph); |
@@ -141,7 +148,7 @@ impl ServerWorldState { | |||
141 | ServerWorld { | 148 | ServerWorld { |
142 | workspaces: Arc::clone(&self.workspaces), | 149 | workspaces: Arc::clone(&self.workspaces), |
143 | analysis: self.analysis_host.analysis(), | 150 | analysis: self.analysis_host.analysis(), |
144 | path_map: self.path_map.clone() | 151 | path_map: self.path_map.clone(), |
145 | } | 152 | } |
146 | } | 153 | } |
147 | } | 154 | } |
@@ -152,9 +159,12 @@ impl ServerWorld { | |||
152 | } | 159 | } |
153 | 160 | ||
154 | pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> { | 161 | pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> { |
155 | let path = uri.to_file_path() | 162 | let path = uri |
163 | .to_file_path() | ||
156 | .map_err(|()| format_err!("invalid uri: {}", uri))?; | 164 | .map_err(|()| format_err!("invalid uri: {}", uri))?; |
157 | self.path_map.get_id(&path).ok_or_else(|| format_err!("unknown file: {}", path.display())) | 165 | self.path_map |
166 | .get_id(&path) | ||
167 | .ok_or_else(|| format_err!("unknown file: {}", path.display())) | ||
158 | } | 168 | } |
159 | 169 | ||
160 | pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { | 170 | pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { |
diff --git a/crates/ra_lsp_server/src/thread_watcher.rs b/crates/ra_lsp_server/src/thread_watcher.rs index 3257effcb..67952eb74 100644 --- a/crates/ra_lsp_server/src/thread_watcher.rs +++ b/crates/ra_lsp_server/src/thread_watcher.rs | |||
@@ -1,7 +1,8 @@ | |||
1 | use std::thread; | ||
2 | use crossbeam_channel::{bounded, unbounded, Sender, Receiver}; | ||
3 | use drop_bomb::DropBomb; | ||
4 | use crate::Result; | 1 | use crate::Result; |
2 | use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; | ||
3 | use drop_bomb::DropBomb; | ||
4 | |||
5 | use std::thread; | ||
5 | 6 | ||
6 | pub struct Worker<I, O> { | 7 | pub struct Worker<I, O> { |
7 | pub inp: Sender<I>, | 8 | pub inp: Sender<I>, |
@@ -50,11 +51,13 @@ impl ThreadWatcher { | |||
50 | info!("waiting for {} to finish ...", self.name); | 51 | info!("waiting for {} to finish ...", self.name); |
51 | let name = self.name; | 52 | let name = self.name; |
52 | self.bomb.defuse(); | 53 | self.bomb.defuse(); |
53 | let res = self.thread.join() | 54 | let res = self |
55 | .thread | ||
56 | .join() | ||
54 | .map_err(|_| format_err!("ThreadWatcher {} died", name)); | 57 | .map_err(|_| format_err!("ThreadWatcher {} died", name)); |
55 | match &res { | 58 | match &res { |
56 | Ok(()) => info!("... {} terminated with ok", name), | 59 | Ok(()) => info!("... {} terminated with ok", name), |
57 | Err(_) => error!("... {} terminated with err", name) | 60 | Err(_) => error!("... {} terminated with err", name), |
58 | } | 61 | } |
59 | res | 62 | res |
60 | } | 63 | } |
@@ -66,5 +69,9 @@ impl ThreadWatcher { | |||
66 | fn worker_chan<I, O>(buf: usize) -> ((Sender<I>, Receiver<O>), Receiver<I>, Sender<O>) { | 69 | fn worker_chan<I, O>(buf: usize) -> ((Sender<I>, Receiver<O>), Receiver<I>, Sender<O>) { |
67 | let (input_sender, input_receiver) = bounded::<I>(buf); | 70 | let (input_sender, input_receiver) = bounded::<I>(buf); |
68 | let (output_sender, output_receiver) = unbounded::<O>(); | 71 | let (output_sender, output_receiver) = unbounded::<O>(); |
69 | ((input_sender, output_receiver), input_receiver, output_sender) | 72 | ( |
73 | (input_sender, output_receiver), | ||
74 | input_receiver, | ||
75 | output_sender, | ||
76 | ) | ||
70 | } | 77 | } |
diff --git a/crates/ra_lsp_server/src/vfs.rs b/crates/ra_lsp_server/src/vfs.rs index d8f9b1aac..417a3c19a 100644 --- a/crates/ra_lsp_server/src/vfs.rs +++ b/crates/ra_lsp_server/src/vfs.rs | |||
@@ -1,14 +1,11 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | path::{PathBuf, Path}, | ||
3 | fs, | 2 | fs, |
3 | path::{Path, PathBuf}, | ||
4 | }; | 4 | }; |
5 | 5 | ||
6 | use walkdir::WalkDir; | 6 | use walkdir::WalkDir; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::thread_watcher::{ThreadWatcher, Worker}; |
9 | thread_watcher::{Worker, ThreadWatcher}, | ||
10 | }; | ||
11 | |||
12 | 9 | ||
13 | #[derive(Debug)] | 10 | #[derive(Debug)] |
14 | pub struct FileEvent { | 11 | pub struct FileEvent { |
@@ -24,7 +21,8 @@ pub enum FileEventKind { | |||
24 | pub fn roots_loader() -> (Worker<PathBuf, (PathBuf, Vec<FileEvent>)>, ThreadWatcher) { | 21 | pub fn roots_loader() -> (Worker<PathBuf, (PathBuf, Vec<FileEvent>)>, ThreadWatcher) { |
25 | Worker::<PathBuf, (PathBuf, Vec<FileEvent>)>::spawn( | 22 | Worker::<PathBuf, (PathBuf, Vec<FileEvent>)>::spawn( |
26 | "roots loader", | 23 | "roots loader", |
27 | 128, |input_receiver, output_sender| { | 24 | 128, |
25 | |input_receiver, output_sender| { | ||
28 | input_receiver | 26 | input_receiver |
29 | .into_iter() | 27 | .into_iter() |
30 | .map(|path| { | 28 | .map(|path| { |
@@ -34,7 +32,7 @@ pub fn roots_loader() -> (Worker<PathBuf, (PathBuf, Vec<FileEvent>)>, ThreadWatc | |||
34 | (path, events) | 32 | (path, events) |
35 | }) | 33 | }) |
36 | .for_each(|it| output_sender.send(it)) | 34 | .for_each(|it| output_sender.send(it)) |
37 | } | 35 | }, |
38 | ) | 36 | ) |
39 | } | 37 | } |
40 | 38 | ||
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index 7265b5999..8e566d3c8 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs | |||
@@ -1,12 +1,12 @@ | |||
1 | #[macro_use] | 1 | #[macro_use] |
2 | extern crate crossbeam_channel; | 2 | extern crate crossbeam_channel; |
3 | extern crate tempdir; | 3 | extern crate flexi_logger; |
4 | extern crate gen_lsp_server; | ||
4 | extern crate languageserver_types; | 5 | extern crate languageserver_types; |
6 | extern crate ra_lsp_server; | ||
5 | extern crate serde; | 7 | extern crate serde; |
6 | extern crate serde_json; | 8 | extern crate serde_json; |
7 | extern crate gen_lsp_server; | 9 | extern crate tempdir; |
8 | extern crate flexi_logger; | ||
9 | extern crate ra_lsp_server; | ||
10 | 10 | ||
11 | mod support; | 11 | mod support; |
12 | 12 | ||
@@ -14,17 +14,18 @@ use ra_lsp_server::req::{Runnables, RunnablesParams}; | |||
14 | 14 | ||
15 | use crate::support::project; | 15 | use crate::support::project; |
16 | 16 | ||
17 | |||
18 | const LOG: &'static str = ""; | 17 | const LOG: &'static str = ""; |
19 | 18 | ||
20 | #[test] | 19 | #[test] |
21 | fn test_runnables_no_project() { | 20 | fn test_runnables_no_project() { |
22 | let server = project(r" | 21 | let server = project( |
22 | r" | ||
23 | //- lib.rs | 23 | //- lib.rs |
24 | #[test] | 24 | #[test] |
25 | fn foo() { | 25 | fn foo() { |
26 | } | 26 | } |
27 | "); | 27 | ", |
28 | ); | ||
28 | server.request::<Runnables>( | 29 | server.request::<Runnables>( |
29 | RunnablesParams { | 30 | RunnablesParams { |
30 | text_document: server.doc_id("lib.rs"), | 31 | text_document: server.doc_id("lib.rs"), |
@@ -41,13 +42,14 @@ fn foo() { | |||
41 | "start": { "character": 0, "line": 0 } | 42 | "start": { "character": 0, "line": 0 } |
42 | } | 43 | } |
43 | } | 44 | } |
44 | ]"# | 45 | ]"#, |
45 | ); | 46 | ); |
46 | } | 47 | } |
47 | 48 | ||
48 | #[test] | 49 | #[test] |
49 | fn test_runnables_project() { | 50 | fn test_runnables_project() { |
50 | let server = project(r#" | 51 | let server = project( |
52 | r#" | ||
51 | //- Cargo.toml | 53 | //- Cargo.toml |
52 | [package] | 54 | [package] |
53 | name = "foo" | 55 | name = "foo" |
@@ -59,7 +61,8 @@ pub fn foo() {} | |||
59 | //- tests/spam.rs | 61 | //- tests/spam.rs |
60 | #[test] | 62 | #[test] |
61 | fn test_eggs() {} | 63 | fn test_eggs() {} |
62 | "#); | 64 | "#, |
65 | ); | ||
63 | server.wait_for_feedback("workspace loaded"); | 66 | server.wait_for_feedback("workspace loaded"); |
64 | server.request::<Runnables>( | 67 | server.request::<Runnables>( |
65 | RunnablesParams { | 68 | RunnablesParams { |
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs index d1339f62f..004d7e8ad 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/support.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs | |||
@@ -1,34 +1,33 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | fs, | ||
3 | cell::{Cell, RefCell}, | 2 | cell::{Cell, RefCell}, |
3 | fs, | ||
4 | path::PathBuf, | 4 | path::PathBuf, |
5 | time::Duration, | ||
6 | sync::Once, | 5 | sync::Once, |
6 | time::Duration, | ||
7 | }; | 7 | }; |
8 | 8 | ||
9 | use tempdir::TempDir; | ||
10 | use crossbeam_channel::{after, Receiver}; | 9 | use crossbeam_channel::{after, Receiver}; |
11 | use flexi_logger::Logger; | 10 | use flexi_logger::Logger; |
11 | use gen_lsp_server::{RawMessage, RawNotification, RawRequest}; | ||
12 | use languageserver_types::{ | 12 | use languageserver_types::{ |
13 | Url, | ||
14 | TextDocumentIdentifier, | ||
15 | request::{Request, Shutdown}, | ||
16 | notification::DidOpenTextDocument, | 13 | notification::DidOpenTextDocument, |
17 | DidOpenTextDocumentParams, | 14 | request::{Request, Shutdown}, |
18 | TextDocumentItem, | 15 | DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url, |
19 | }; | 16 | }; |
20 | use serde::Serialize; | 17 | use serde::Serialize; |
21 | use serde_json::{Value, from_str, to_string_pretty}; | 18 | use serde_json::{from_str, to_string_pretty, Value}; |
22 | use gen_lsp_server::{RawMessage, RawRequest, RawNotification}; | 19 | use tempdir::TempDir; |
23 | 20 | ||
24 | use ra_lsp_server::{main_loop, req, thread_watcher::{ThreadWatcher, Worker}}; | 21 | use ra_lsp_server::{ |
22 | main_loop, req, | ||
23 | thread_watcher::{ThreadWatcher, Worker}, | ||
24 | }; | ||
25 | 25 | ||
26 | pub fn project(fixture: &str) -> Server { | 26 | pub fn project(fixture: &str) -> Server { |
27 | static INIT: Once = Once::new(); | 27 | static INIT: Once = Once::new(); |
28 | INIT.call_once(|| Logger::with_env_or_str(crate::LOG).start().unwrap()); | 28 | INIT.call_once(|| Logger::with_env_or_str(crate::LOG).start().unwrap()); |
29 | 29 | ||
30 | let tmp_dir = TempDir::new("test-project") | 30 | let tmp_dir = TempDir::new("test-project").unwrap(); |
31 | .unwrap(); | ||
32 | let mut buf = String::new(); | 31 | let mut buf = String::new(); |
33 | let mut file_name = None; | 32 | let mut file_name = None; |
34 | let mut paths = vec![]; | 33 | let mut paths = vec![]; |
@@ -40,7 +39,7 @@ pub fn project(fixture: &str) -> Server { | |||
40 | fs::write(path.as_path(), buf.as_bytes()).unwrap(); | 39 | fs::write(path.as_path(), buf.as_bytes()).unwrap(); |
41 | paths.push((path, buf.clone())); | 40 | paths.push((path, buf.clone())); |
42 | } | 41 | } |
43 | } | 42 | }; |
44 | }; | 43 | }; |
45 | for line in fixture.lines() { | 44 | for line in fixture.lines() { |
46 | if line.starts_with("//-") { | 45 | if line.starts_with("//-") { |
@@ -71,9 +70,8 @@ impl Server { | |||
71 | "test server", | 70 | "test server", |
72 | 128, | 71 | 128, |
73 | move |mut msg_receiver, mut msg_sender| { | 72 | move |mut msg_receiver, mut msg_sender| { |
74 | main_loop(true, path, &mut msg_receiver, &mut msg_sender) | 73 | main_loop(true, path, &mut msg_receiver, &mut msg_sender).unwrap() |
75 | .unwrap() | 74 | }, |
76 | } | ||
77 | ); | 75 | ); |
78 | let res = Server { | 76 | let res = Server { |
79 | req_id: Cell::new(1), | 77 | req_id: Cell::new(1), |
@@ -91,8 +89,8 @@ impl Server { | |||
91 | language_id: "rust".to_string(), | 89 | language_id: "rust".to_string(), |
92 | version: 0, | 90 | version: 0, |
93 | text, | 91 | text, |
94 | } | 92 | }, |
95 | } | 93 | }, |
96 | )) | 94 | )) |
97 | } | 95 | } |
98 | res | 96 | res |
@@ -105,11 +103,7 @@ impl Server { | |||
105 | } | 103 | } |
106 | } | 104 | } |
107 | 105 | ||
108 | pub fn request<R>( | 106 | pub fn request<R>(&self, params: R::Params, expected_resp: &str) |
109 | &self, | ||
110 | params: R::Params, | ||
111 | expected_resp: &str, | ||
112 | ) | ||
113 | where | 107 | where |
114 | R: Request, | 108 | R: Request, |
115 | R::Params: Serialize, | 109 | R::Params: Serialize, |
@@ -119,7 +113,8 @@ impl Server { | |||
119 | let expected_resp: Value = from_str(expected_resp).unwrap(); | 113 | let expected_resp: Value = from_str(expected_resp).unwrap(); |
120 | let actual = self.send_request::<R>(id, params); | 114 | let actual = self.send_request::<R>(id, params); |
121 | assert_eq!( | 115 | assert_eq!( |
122 | expected_resp, actual, | 116 | expected_resp, |
117 | actual, | ||
123 | "Expected:\n{}\n\ | 118 | "Expected:\n{}\n\ |
124 | Actual:\n{}\n", | 119 | Actual:\n{}\n", |
125 | to_string_pretty(&expected_resp).unwrap(), | 120 | to_string_pretty(&expected_resp).unwrap(), |
@@ -135,12 +130,9 @@ impl Server { | |||
135 | let r = RawRequest::new::<R>(id, ¶ms); | 130 | let r = RawRequest::new::<R>(id, ¶ms); |
136 | self.send_request_(r) | 131 | self.send_request_(r) |
137 | } | 132 | } |
138 | fn send_request_(&self, r: RawRequest) -> Value | 133 | fn send_request_(&self, r: RawRequest) -> Value { |
139 | { | ||
140 | let id = r.id; | 134 | let id = r.id; |
141 | self.worker.as_ref() | 135 | self.worker.as_ref().unwrap().send(RawMessage::Request(r)); |
142 | .unwrap() | ||
143 | .send(RawMessage::Request(r)); | ||
144 | while let Some(msg) = self.recv() { | 136 | while let Some(msg) = self.recv() { |
145 | match msg { | 137 | match msg { |
146 | RawMessage::Request(req) => panic!("unexpected request: {:?}", req), | 138 | RawMessage::Request(req) => panic!("unexpected request: {:?}", req), |
@@ -161,11 +153,10 @@ impl Server { | |||
161 | } | 153 | } |
162 | pub fn wait_for_feedback_n(&self, feedback: &str, n: usize) { | 154 | pub fn wait_for_feedback_n(&self, feedback: &str, n: usize) { |
163 | let f = |msg: &RawMessage| match msg { | 155 | let f = |msg: &RawMessage| match msg { |
164 | RawMessage::Notification(n) if n.method == "internalFeedback" => { | 156 | RawMessage::Notification(n) if n.method == "internalFeedback" => { |
165 | return n.clone().cast::<req::InternalFeedback>() | 157 | return n.clone().cast::<req::InternalFeedback>().unwrap() == feedback |
166 | .unwrap() == feedback | 158 | } |
167 | } | 159 | _ => false, |
168 | _ => false, | ||
169 | }; | 160 | }; |
170 | let mut total = 0; | 161 | let mut total = 0; |
171 | for msg in self.messages.borrow().iter() { | 162 | for msg in self.messages.borrow().iter() { |
@@ -181,14 +172,14 @@ impl Server { | |||
181 | } | 172 | } |
182 | } | 173 | } |
183 | fn recv(&self) -> Option<RawMessage> { | 174 | fn recv(&self) -> Option<RawMessage> { |
184 | recv_timeout(&self.worker.as_ref().unwrap().out) | 175 | recv_timeout(&self.worker.as_ref().unwrap().out).map(|msg| { |
185 | .map(|msg| { | 176 | self.messages.borrow_mut().push(msg.clone()); |
186 | self.messages.borrow_mut().push(msg.clone()); | 177 | msg |
187 | msg | 178 | }) |
188 | }) | ||
189 | } | 179 | } |
190 | fn send_notification(&self, not: RawNotification) { | 180 | fn send_notification(&self, not: RawNotification) { |
191 | self.worker.as_ref() | 181 | self.worker |
182 | .as_ref() | ||
192 | .unwrap() | 183 | .unwrap() |
193 | .send(RawMessage::Notification(not)); | 184 | .send(RawMessage::Notification(not)); |
194 | } | 185 | } |
@@ -201,10 +192,7 @@ impl Drop for Server { | |||
201 | while let Some(msg) = recv_timeout(&receiver) { | 192 | while let Some(msg) = recv_timeout(&receiver) { |
202 | drop(msg); | 193 | drop(msg); |
203 | } | 194 | } |
204 | self.watcher.take() | 195 | self.watcher.take().unwrap().stop().unwrap(); |
205 | .unwrap() | ||
206 | .stop() | ||
207 | .unwrap(); | ||
208 | } | 196 | } |
209 | } | 197 | } |
210 | 198 | ||
diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs index e686a5704..b4896c482 100644 --- a/crates/ra_syntax/src/algo/mod.rs +++ b/crates/ra_syntax/src/algo/mod.rs | |||
@@ -1,16 +1,18 @@ | |||
1 | pub mod walk; | ||
2 | pub mod visit; | 1 | pub mod visit; |
2 | pub mod walk; | ||
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | SyntaxNodeRef, TextUnit, TextRange, | ||
6 | text_utils::{contains_offset_nonstrict, is_subrange}, | 5 | text_utils::{contains_offset_nonstrict, is_subrange}, |
6 | SyntaxNodeRef, TextRange, TextUnit, | ||
7 | }; | 7 | }; |
8 | 8 | ||
9 | pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset { | 9 | pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset { |
10 | let range = node.range(); | 10 | let range = node.range(); |
11 | assert!( | 11 | assert!( |
12 | contains_offset_nonstrict(range, offset), | 12 | contains_offset_nonstrict(range, offset), |
13 | "Bad offset: range {:?} offset {:?}", range, offset | 13 | "Bad offset: range {:?} offset {:?}", |
14 | range, | ||
15 | offset | ||
14 | ); | 16 | ); |
15 | if range.is_empty() { | 17 | if range.is_empty() { |
16 | return LeafAtOffset::None; | 18 | return LeafAtOffset::None; |
@@ -20,20 +22,23 @@ pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffse | |||
20 | return LeafAtOffset::Single(node); | 22 | return LeafAtOffset::Single(node); |
21 | } | 23 | } |
22 | 24 | ||
23 | let mut children = node.children() | 25 | let mut children = node.children().filter(|child| { |
24 | .filter(|child| { | 26 | let child_range = child.range(); |
25 | let child_range = child.range(); | 27 | !child_range.is_empty() && contains_offset_nonstrict(child_range, offset) |
26 | !child_range.is_empty() && contains_offset_nonstrict(child_range, offset) | 28 | }); |
27 | }); | ||
28 | 29 | ||
29 | let left = children.next().unwrap(); | 30 | let left = children.next().unwrap(); |
30 | let right = children.next(); | 31 | let right = children.next(); |
31 | assert!(children.next().is_none()); | 32 | assert!(children.next().is_none()); |
32 | return if let Some(right) = right { | 33 | return if let Some(right) = right { |
33 | match (find_leaf_at_offset(left, offset), find_leaf_at_offset(right, offset)) { | 34 | match ( |
34 | (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => | 35 | find_leaf_at_offset(left, offset), |
35 | LeafAtOffset::Between(left, right), | 36 | find_leaf_at_offset(right, offset), |
36 | _ => unreachable!() | 37 | ) { |
38 | (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => { | ||
39 | LeafAtOffset::Between(left, right) | ||
40 | } | ||
41 | _ => unreachable!(), | ||
37 | } | 42 | } |
38 | } else { | 43 | } else { |
39 | find_leaf_at_offset(left, offset) | 44 | find_leaf_at_offset(left, offset) |
@@ -44,7 +49,7 @@ pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffse | |||
44 | pub enum LeafAtOffset<'a> { | 49 | pub enum LeafAtOffset<'a> { |
45 | None, | 50 | None, |
46 | Single(SyntaxNodeRef<'a>), | 51 | Single(SyntaxNodeRef<'a>), |
47 | Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>) | 52 | Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>), |
48 | } | 53 | } |
49 | 54 | ||
50 | impl<'a> LeafAtOffset<'a> { | 55 | impl<'a> LeafAtOffset<'a> { |
@@ -52,7 +57,7 @@ impl<'a> LeafAtOffset<'a> { | |||
52 | match self { | 57 | match self { |
53 | LeafAtOffset::None => None, | 58 | LeafAtOffset::None => None, |
54 | LeafAtOffset::Single(node) => Some(node), | 59 | LeafAtOffset::Single(node) => Some(node), |
55 | LeafAtOffset::Between(_, right) => Some(right) | 60 | LeafAtOffset::Between(_, right) => Some(right), |
56 | } | 61 | } |
57 | } | 62 | } |
58 | 63 | ||
@@ -60,7 +65,7 @@ impl<'a> LeafAtOffset<'a> { | |||
60 | match self { | 65 | match self { |
61 | LeafAtOffset::None => None, | 66 | LeafAtOffset::None => None, |
62 | LeafAtOffset::Single(node) => Some(node), | 67 | LeafAtOffset::Single(node) => Some(node), |
63 | LeafAtOffset::Between(left, _) => Some(left) | 68 | LeafAtOffset::Between(left, _) => Some(left), |
64 | } | 69 | } |
65 | } | 70 | } |
66 | } | 71 | } |
@@ -71,8 +76,14 @@ impl<'f> Iterator for LeafAtOffset<'f> { | |||
71 | fn next(&mut self) -> Option<SyntaxNodeRef<'f>> { | 76 | fn next(&mut self) -> Option<SyntaxNodeRef<'f>> { |
72 | match *self { | 77 | match *self { |
73 | LeafAtOffset::None => None, | 78 | LeafAtOffset::None => None, |
74 | LeafAtOffset::Single(node) => { *self = LeafAtOffset::None; Some(node) } | 79 | LeafAtOffset::Single(node) => { |
75 | LeafAtOffset::Between(left, right) => { *self = LeafAtOffset::Single(right); Some(left) } | 80 | *self = LeafAtOffset::None; |
81 | Some(node) | ||
82 | } | ||
83 | LeafAtOffset::Between(left, right) => { | ||
84 | *self = LeafAtOffset::Single(right); | ||
85 | Some(left) | ||
86 | } | ||
76 | } | 87 | } |
77 | } | 88 | } |
78 | } | 89 | } |
@@ -81,14 +92,15 @@ pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRe | |||
81 | assert!( | 92 | assert!( |
82 | is_subrange(root.range(), range), | 93 | is_subrange(root.range(), range), |
83 | "node range: {:?}, target range: {:?}", | 94 | "node range: {:?}, target range: {:?}", |
84 | root.range(), range, | 95 | root.range(), |
96 | range, | ||
85 | ); | 97 | ); |
86 | let (left, right) = match ( | 98 | let (left, right) = match ( |
87 | find_leaf_at_offset(root, range.start()).right_biased(), | 99 | find_leaf_at_offset(root, range.start()).right_biased(), |
88 | find_leaf_at_offset(root, range.end()).left_biased() | 100 | find_leaf_at_offset(root, range.end()).left_biased(), |
89 | ) { | 101 | ) { |
90 | (Some(l), Some(r)) => (l, r), | 102 | (Some(l), Some(r)) => (l, r), |
91 | _ => return root | 103 | _ => return root, |
92 | }; | 104 | }; |
93 | 105 | ||
94 | common_ancestor(left, right) | 106 | common_ancestor(left, right) |
@@ -103,7 +115,7 @@ fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNo | |||
103 | panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) | 115 | panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) |
104 | } | 116 | } |
105 | 117 | ||
106 | pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> { | 118 | pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> { |
107 | ::itertools::unfold(seed, move |slot| { | 119 | ::itertools::unfold(seed, move |slot| { |
108 | slot.take().map(|curr| { | 120 | slot.take().map(|curr| { |
109 | *slot = step(&curr); | 121 | *slot = step(&curr); |
diff --git a/crates/ra_syntax/src/algo/visit.rs b/crates/ra_syntax/src/algo/visit.rs index 1ae988a87..c021f464c 100644 --- a/crates/ra_syntax/src/algo/visit.rs +++ b/crates/ra_syntax/src/algo/visit.rs | |||
@@ -1,23 +1,31 @@ | |||
1 | use std::marker::PhantomData; | 1 | use crate::{AstNode, SyntaxNodeRef}; |
2 | use crate::{SyntaxNodeRef, AstNode}; | ||
3 | 2 | ||
3 | use std::marker::PhantomData; | ||
4 | 4 | ||
5 | pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { | 5 | pub fn visitor<'a, T>() -> impl Visitor<'a, Output = T> { |
6 | EmptyVisitor { ph: PhantomData } | 6 | EmptyVisitor { ph: PhantomData } |
7 | } | 7 | } |
8 | 8 | ||
9 | pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output=T, Ctx=C> { | 9 | pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output = T, Ctx = C> { |
10 | EmptyVisitorCtx { ph: PhantomData, ctx } | 10 | EmptyVisitorCtx { |
11 | ph: PhantomData, | ||
12 | ctx, | ||
13 | } | ||
11 | } | 14 | } |
12 | 15 | ||
13 | pub trait Visitor<'a>: Sized { | 16 | pub trait Visitor<'a>: Sized { |
14 | type Output; | 17 | type Output; |
15 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; | 18 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; |
16 | fn visit<N, F>(self, f: F) -> Vis<Self, N, F> | 19 | fn visit<N, F>(self, f: F) -> Vis<Self, N, F> |
17 | where N: AstNode<'a>, | 20 | where |
18 | F: FnOnce(N) -> Self::Output, | 21 | N: AstNode<'a>, |
22 | F: FnOnce(N) -> Self::Output, | ||
19 | { | 23 | { |
20 | Vis { inner: self, f, ph: PhantomData } | 24 | Vis { |
25 | inner: self, | ||
26 | f, | ||
27 | ph: PhantomData, | ||
28 | } | ||
21 | } | 29 | } |
22 | } | 30 | } |
23 | 31 | ||
@@ -26,16 +34,21 @@ pub trait VisitorCtx<'a>: Sized { | |||
26 | type Ctx; | 34 | type Ctx; |
27 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx>; | 35 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx>; |
28 | fn visit<N, F>(self, f: F) -> VisCtx<Self, N, F> | 36 | fn visit<N, F>(self, f: F) -> VisCtx<Self, N, F> |
29 | where N: AstNode<'a>, | 37 | where |
30 | F: FnOnce(N, Self::Ctx) -> Self::Output, | 38 | N: AstNode<'a>, |
39 | F: FnOnce(N, Self::Ctx) -> Self::Output, | ||
31 | { | 40 | { |
32 | VisCtx { inner: self, f, ph: PhantomData } | 41 | VisCtx { |
42 | inner: self, | ||
43 | f, | ||
44 | ph: PhantomData, | ||
45 | } | ||
33 | } | 46 | } |
34 | } | 47 | } |
35 | 48 | ||
36 | #[derive(Debug)] | 49 | #[derive(Debug)] |
37 | struct EmptyVisitor<T> { | 50 | struct EmptyVisitor<T> { |
38 | ph: PhantomData<fn() -> T> | 51 | ph: PhantomData<fn() -> T>, |
39 | } | 52 | } |
40 | 53 | ||
41 | impl<'a, T> Visitor<'a> for EmptyVisitor<T> { | 54 | impl<'a, T> Visitor<'a> for EmptyVisitor<T> { |
@@ -69,10 +82,10 @@ pub struct Vis<V, N, F> { | |||
69 | } | 82 | } |
70 | 83 | ||
71 | impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> | 84 | impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> |
72 | where | 85 | where |
73 | V: Visitor<'a>, | 86 | V: Visitor<'a>, |
74 | N: AstNode<'a>, | 87 | N: AstNode<'a>, |
75 | F: FnOnce(N) -> <V as Visitor<'a>>::Output, | 88 | F: FnOnce(N) -> <V as Visitor<'a>>::Output, |
76 | { | 89 | { |
77 | type Output = <V as Visitor<'a>>::Output; | 90 | type Output = <V as Visitor<'a>>::Output; |
78 | 91 | ||
@@ -90,21 +103,19 @@ pub struct VisCtx<V, N, F> { | |||
90 | } | 103 | } |
91 | 104 | ||
92 | impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F> | 105 | impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F> |
93 | where | 106 | where |
94 | V: VisitorCtx<'a>, | 107 | V: VisitorCtx<'a>, |
95 | N: AstNode<'a>, | 108 | N: AstNode<'a>, |
96 | F: FnOnce(N, <V as VisitorCtx<'a>>::Ctx) -> <V as VisitorCtx<'a>>::Output, | 109 | F: FnOnce(N, <V as VisitorCtx<'a>>::Ctx) -> <V as VisitorCtx<'a>>::Output, |
97 | { | 110 | { |
98 | type Output = <V as VisitorCtx<'a>>::Output; | 111 | type Output = <V as VisitorCtx<'a>>::Output; |
99 | type Ctx = <V as VisitorCtx<'a>>::Ctx; | 112 | type Ctx = <V as VisitorCtx<'a>>::Ctx; |
100 | 113 | ||
101 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx> { | 114 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx> { |
102 | let VisCtx { inner, f, .. } = self; | 115 | let VisCtx { inner, f, .. } = self; |
103 | inner.accept(node).or_else(|ctx| | 116 | inner.accept(node).or_else(|ctx| match N::cast(node) { |
104 | match N::cast(node) { | 117 | None => Err(ctx), |
105 | None => Err(ctx), | 118 | Some(node) => Ok(f(node, ctx)), |
106 | Some(node) => Ok(f(node, ctx)) | 119 | }) |
107 | } | ||
108 | ) | ||
109 | } | 120 | } |
110 | } | 121 | } |
diff --git a/crates/ra_syntax/src/algo/walk.rs b/crates/ra_syntax/src/algo/walk.rs index d34415626..9afa86401 100644 --- a/crates/ra_syntax/src/algo/walk.rs +++ b/crates/ra_syntax/src/algo/walk.rs | |||
@@ -1,8 +1,4 @@ | |||
1 | use crate::{ | 1 | use crate::{algo::generate, SyntaxNodeRef}; |
2 | SyntaxNodeRef, | ||
3 | algo::generate, | ||
4 | }; | ||
5 | |||
6 | 2 | ||
7 | #[derive(Debug, Copy, Clone)] | 3 | #[derive(Debug, Copy, Clone)] |
8 | pub enum WalkEvent<'a> { | 4 | pub enum WalkEvent<'a> { |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 160d186b8..a15e00176 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | // This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run | 1 | // This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run |
2 | // Do not edit manually | 2 | // Do not edit manually |
3 | 3 | ||
4 | #![cfg_attr(rustfmt, rustfmt_skip)] | ||
5 | |||
4 | use crate::{ | 6 | use crate::{ |
5 | ast, | 7 | ast, |
6 | SyntaxNodeRef, AstNode, | 8 | SyntaxNodeRef, AstNode, |
diff --git a/crates/ra_syntax/src/ast/generated.rs.tera b/crates/ra_syntax/src/ast/generated.rs.tera index 5cb7a35ed..d2a281137 100644 --- a/crates/ra_syntax/src/ast/generated.rs.tera +++ b/crates/ra_syntax/src/ast/generated.rs.tera | |||
@@ -3,6 +3,8 @@ the below applies to the result of this template | |||
3 | #}// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run | 3 | #}// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run |
4 | // Do not edit manually | 4 | // Do not edit manually |
5 | 5 | ||
6 | #![cfg_attr(rustfmt, rustfmt_skip)] | ||
7 | |||
6 | use crate::{ | 8 | use crate::{ |
7 | ast, | 9 | ast, |
8 | SyntaxNodeRef, AstNode, | 10 | SyntaxNodeRef, AstNode, |
diff --git a/crates/ra_syntax/src/ast/mod.rs b/crates/ra_syntax/src/ast/mod.rs index 88193a1ed..34958b6cb 100644 --- a/crates/ra_syntax/src/ast/mod.rs +++ b/crates/ra_syntax/src/ast/mod.rs | |||
@@ -4,15 +4,18 @@ use std::marker::PhantomData; | |||
4 | 4 | ||
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | 6 | ||
7 | pub use self::generated::*; | ||
7 | use crate::{ | 8 | use crate::{ |
8 | SmolStr, SyntaxNodeRef, SyntaxKind::*, | ||
9 | yellow::{RefRoot, SyntaxNodeChildren}, | 9 | yellow::{RefRoot, SyntaxNodeChildren}, |
10 | SmolStr, | ||
11 | SyntaxKind::*, | ||
12 | SyntaxNodeRef, | ||
10 | }; | 13 | }; |
11 | pub use self::generated::*; | ||
12 | 14 | ||
13 | pub trait AstNode<'a>: Clone + Copy + 'a { | 15 | pub trait AstNode<'a>: Clone + Copy + 'a { |
14 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> | 16 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> |
15 | where Self: Sized; | 17 | where |
18 | Self: Sized; | ||
16 | fn syntax(self) -> SyntaxNodeRef<'a>; | 19 | fn syntax(self) -> SyntaxNodeRef<'a>; |
17 | } | 20 | } |
18 | 21 | ||
@@ -64,9 +67,7 @@ pub trait AttrsOwner<'a>: AstNode<'a> { | |||
64 | 67 | ||
65 | impl<'a> FnDef<'a> { | 68 | impl<'a> FnDef<'a> { |
66 | pub fn has_atom_attr(&self, atom: &str) -> bool { | 69 | pub fn has_atom_attr(&self, atom: &str) -> bool { |
67 | self.attrs() | 70 | self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom) |
68 | .filter_map(|x| x.as_atom()) | ||
69 | .any(|x| x == atom) | ||
70 | } | 71 | } |
71 | } | 72 | } |
72 | 73 | ||
@@ -135,7 +136,7 @@ pub enum CommentFlavor { | |||
135 | Line, | 136 | Line, |
136 | Doc, | 137 | Doc, |
137 | ModuleDoc, | 138 | ModuleDoc, |
138 | Multiline | 139 | Multiline, |
139 | } | 140 | } |
140 | 141 | ||
141 | impl CommentFlavor { | 142 | impl CommentFlavor { |
@@ -145,7 +146,7 @@ impl CommentFlavor { | |||
145 | Line => "//", | 146 | Line => "//", |
146 | Doc => "///", | 147 | Doc => "///", |
147 | ModuleDoc => "//!", | 148 | ModuleDoc => "//!", |
148 | Multiline => "/*" | 149 | Multiline => "/*", |
149 | } | 150 | } |
150 | } | 151 | } |
151 | } | 152 | } |
@@ -166,16 +167,14 @@ impl<'a> Whitespace<'a> { | |||
166 | 167 | ||
167 | impl<'a> Name<'a> { | 168 | impl<'a> Name<'a> { |
168 | pub fn text(&self) -> SmolStr { | 169 | pub fn text(&self) -> SmolStr { |
169 | let ident = self.syntax().first_child() | 170 | let ident = self.syntax().first_child().unwrap(); |
170 | .unwrap(); | ||
171 | ident.leaf_text().unwrap().clone() | 171 | ident.leaf_text().unwrap().clone() |
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | impl<'a> NameRef<'a> { | 175 | impl<'a> NameRef<'a> { |
176 | pub fn text(&self) -> SmolStr { | 176 | pub fn text(&self) -> SmolStr { |
177 | let ident = self.syntax().first_child() | 177 | let ident = self.syntax().first_child().unwrap(); |
178 | .unwrap(); | ||
179 | ident.leaf_text().unwrap().clone() | 178 | ident.leaf_text().unwrap().clone() |
180 | } | 179 | } |
181 | } | 180 | } |
@@ -241,7 +240,6 @@ fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstChildren<'a, C> | |||
241 | AstChildren::new(parent.syntax()) | 240 | AstChildren::new(parent.syntax()) |
242 | } | 241 | } |
243 | 242 | ||
244 | |||
245 | #[derive(Debug)] | 243 | #[derive(Debug)] |
246 | pub struct AstChildren<'a, N> { | 244 | pub struct AstChildren<'a, N> { |
247 | inner: SyntaxNodeChildren<RefRoot<'a>>, | 245 | inner: SyntaxNodeChildren<RefRoot<'a>>, |
diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs index e21de68c5..11f766d33 100644 --- a/crates/ra_syntax/src/grammar/expressions/atom.rs +++ b/crates/ra_syntax/src/grammar/expressions/atom.rs | |||
@@ -13,9 +13,18 @@ use super::*; | |||
13 | // let _ = b"e"; | 13 | // let _ = b"e"; |
14 | // let _ = br"f"; | 14 | // let _ = br"f"; |
15 | // } | 15 | // } |
16 | pub(crate) const LITERAL_FIRST: TokenSet = | 16 | pub(crate) const LITERAL_FIRST: TokenSet = token_set![ |
17 | token_set![TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR, | 17 | TRUE_KW, |
18 | STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING]; | 18 | FALSE_KW, |
19 | INT_NUMBER, | ||
20 | FLOAT_NUMBER, | ||
21 | BYTE, | ||
22 | CHAR, | ||
23 | STRING, | ||
24 | RAW_STRING, | ||
25 | BYTE_STRING, | ||
26 | RAW_BYTE_STRING | ||
27 | ]; | ||
19 | 28 | ||
20 | pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { | 29 | pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { |
21 | if !p.at_ts(LITERAL_FIRST) { | 30 | if !p.at_ts(LITERAL_FIRST) { |
@@ -26,15 +35,31 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { | |||
26 | Some(m.complete(p, LITERAL)) | 35 | Some(m.complete(p, LITERAL)) |
27 | } | 36 | } |
28 | 37 | ||
29 | pub(super) const ATOM_EXPR_FIRST: TokenSet = | 38 | pub(super) const ATOM_EXPR_FIRST: TokenSet = token_set_union![ |
30 | token_set_union![ | 39 | LITERAL_FIRST, |
31 | LITERAL_FIRST, | 40 | token_set![ |
32 | token_set![L_CURLY, L_PAREN, L_BRACK, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW, | 41 | L_CURLY, |
33 | RETURN_KW, IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ], | 42 | L_PAREN, |
34 | ]; | 43 | L_BRACK, |
44 | PIPE, | ||
45 | MOVE_KW, | ||
46 | IF_KW, | ||
47 | WHILE_KW, | ||
48 | MATCH_KW, | ||
49 | UNSAFE_KW, | ||
50 | RETURN_KW, | ||
51 | IDENT, | ||
52 | SELF_KW, | ||
53 | SUPER_KW, | ||
54 | CRATE_KW, | ||
55 | COLONCOLON, | ||
56 | BREAK_KW, | ||
57 | CONTINUE_KW, | ||
58 | LIFETIME | ||
59 | ], | ||
60 | ]; | ||
35 | 61 | ||
36 | const EXPR_RECOVERY_SET: TokenSet = | 62 | const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; |
37 | token_set![LET_KW]; | ||
38 | 63 | ||
39 | pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { | 64 | pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { |
40 | match literal(p) { | 65 | match literal(p) { |
@@ -80,7 +105,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMark | |||
80 | let m = p.start(); | 105 | let m = p.start(); |
81 | p.bump(); | 106 | p.bump(); |
82 | block_expr(p, Some(m)) | 107 | block_expr(p, Some(m)) |
83 | }, | 108 | } |
84 | L_CURLY => block_expr(p, None), | 109 | L_CURLY => block_expr(p, None), |
85 | RETURN_KW => return_expr(p), | 110 | RETURN_KW => return_expr(p), |
86 | CONTINUE_KW => continue_expr(p), | 111 | CONTINUE_KW => continue_expr(p), |
@@ -119,7 +144,14 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker { | |||
119 | } | 144 | } |
120 | } | 145 | } |
121 | p.expect(R_PAREN); | 146 | p.expect(R_PAREN); |
122 | m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR }) | 147 | m.complete( |
148 | p, | ||
149 | if saw_expr && !saw_comma { | ||
150 | PAREN_EXPR | ||
151 | } else { | ||
152 | TUPLE_EXPR | ||
153 | }, | ||
154 | ) | ||
123 | } | 155 | } |
124 | 156 | ||
125 | // test array_expr | 157 | // test array_expr |
diff --git a/crates/ra_syntax/src/grammar/expressions/mod.rs b/crates/ra_syntax/src/grammar/expressions/mod.rs index 20e0fa328..60c8602f9 100644 --- a/crates/ra_syntax/src/grammar/expressions/mod.rs +++ b/crates/ra_syntax/src/grammar/expressions/mod.rs | |||
@@ -1,23 +1,32 @@ | |||
1 | mod atom; | 1 | mod atom; |
2 | 2 | ||
3 | use super::*; | ||
4 | pub(super) use self::atom::{literal, LITERAL_FIRST}; | ||
5 | pub(crate) use self::atom::match_arm_list; | 3 | pub(crate) use self::atom::match_arm_list; |
4 | pub(super) use self::atom::{literal, LITERAL_FIRST}; | ||
5 | use super::*; | ||
6 | 6 | ||
7 | const EXPR_FIRST: TokenSet = LHS_FIRST; | 7 | const EXPR_FIRST: TokenSet = LHS_FIRST; |
8 | 8 | ||
9 | pub(super) fn expr(p: &mut Parser) -> BlockLike { | 9 | pub(super) fn expr(p: &mut Parser) -> BlockLike { |
10 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; | 10 | let r = Restrictions { |
11 | forbid_structs: false, | ||
12 | prefer_stmt: false, | ||
13 | }; | ||
11 | expr_bp(p, r, 1) | 14 | expr_bp(p, r, 1) |
12 | } | 15 | } |
13 | 16 | ||
14 | pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike { | 17 | pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike { |
15 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; | 18 | let r = Restrictions { |
19 | forbid_structs: false, | ||
20 | prefer_stmt: true, | ||
21 | }; | ||
16 | expr_bp(p, r, 1) | 22 | expr_bp(p, r, 1) |
17 | } | 23 | } |
18 | 24 | ||
19 | fn expr_no_struct(p: &mut Parser) { | 25 | fn expr_no_struct(p: &mut Parser) { |
20 | let r = Restrictions { forbid_structs: true, prefer_stmt: false }; | 26 | let r = Restrictions { |
27 | forbid_structs: true, | ||
28 | prefer_stmt: false, | ||
29 | }; | ||
21 | expr_bp(p, r, 1); | 30 | expr_bp(p, r, 1); |
22 | } | 31 | } |
23 | 32 | ||
@@ -107,10 +116,8 @@ enum Op { | |||
107 | fn current_op(p: &Parser) -> (u8, Op) { | 116 | fn current_op(p: &Parser) -> (u8, Op) { |
108 | if let Some(t) = p.next3() { | 117 | if let Some(t) = p.next3() { |
109 | match t { | 118 | match t { |
110 | (L_ANGLE, L_ANGLE, EQ) => | 119 | (L_ANGLE, L_ANGLE, EQ) => return (1, Op::Composite(SHLEQ, 3)), |
111 | return (1, Op::Composite(SHLEQ, 3)), | 120 | (R_ANGLE, R_ANGLE, EQ) => return (1, Op::Composite(SHREQ, 3)), |
112 | (R_ANGLE, R_ANGLE, EQ) => | ||
113 | return (1, Op::Composite(SHREQ, 3)), | ||
114 | _ => (), | 121 | _ => (), |
115 | } | 122 | } |
116 | } | 123 | } |
@@ -201,11 +208,10 @@ fn is_block(kind: SyntaxKind) -> bool { | |||
201 | } | 208 | } |
202 | } | 209 | } |
203 | 210 | ||
204 | const LHS_FIRST: TokenSet = | 211 | const LHS_FIRST: TokenSet = token_set_union![ |
205 | token_set_union![ | 212 | token_set![AMP, STAR, EXCL, DOTDOT, MINUS], |
206 | token_set![AMP, STAR, EXCL, DOTDOT, MINUS], | 213 | atom::ATOM_EXPR_FIRST, |
207 | atom::ATOM_EXPR_FIRST, | 214 | ]; |
208 | ]; | ||
209 | 215 | ||
210 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { | 216 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { |
211 | let m; | 217 | let m; |
@@ -265,11 +271,13 @@ fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> Co | |||
265 | // } | 271 | // } |
266 | L_PAREN if allow_calls => call_expr(p, lhs), | 272 | L_PAREN if allow_calls => call_expr(p, lhs), |
267 | L_BRACK if allow_calls => index_expr(p, lhs), | 273 | L_BRACK if allow_calls => index_expr(p, lhs), |
268 | DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON { | 274 | DOT if p.nth(1) == IDENT => { |
269 | method_call_expr(p, lhs) | 275 | if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON { |
270 | } else { | 276 | method_call_expr(p, lhs) |
271 | field_expr(p, lhs) | 277 | } else { |
272 | }, | 278 | field_expr(p, lhs) |
279 | } | ||
280 | } | ||
273 | DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs), | 281 | DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs), |
274 | // test postfix_range | 282 | // test postfix_range |
275 | // fn foo() { let x = 1..; } | 283 | // fn foo() { let x = 1..; } |
@@ -318,10 +326,7 @@ fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
318 | // y.bar::<T>(1, 2,); | 326 | // y.bar::<T>(1, 2,); |
319 | // } | 327 | // } |
320 | fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 328 | fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
321 | assert!( | 329 | assert!(p.at(DOT) && p.nth(1) == IDENT && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON)); |
322 | p.at(DOT) && p.nth(1) == IDENT | ||
323 | && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON) | ||
324 | ); | ||
325 | let m = lhs.precede(p); | 330 | let m = lhs.precede(p); |
326 | p.bump(); | 331 | p.bump(); |
327 | name_ref(p); | 332 | name_ref(p); |
@@ -410,7 +415,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { | |||
410 | items::macro_call_after_excl(p); | 415 | items::macro_call_after_excl(p); |
411 | m.complete(p, MACRO_CALL) | 416 | m.complete(p, MACRO_CALL) |
412 | } | 417 | } |
413 | _ => m.complete(p, PATH_EXPR) | 418 | _ => m.complete(p, PATH_EXPR), |
414 | } | 419 | } |
415 | } | 420 | } |
416 | 421 | ||
diff --git a/crates/ra_syntax/src/grammar/items/mod.rs b/crates/ra_syntax/src/grammar/items/mod.rs index 2567313ab..dc4742bce 100644 --- a/crates/ra_syntax/src/grammar/items/mod.rs +++ b/crates/ra_syntax/src/grammar/items/mod.rs | |||
@@ -1,16 +1,15 @@ | |||
1 | |||
2 | mod consts; | 1 | mod consts; |
3 | mod nominal; | 2 | mod nominal; |
4 | mod traits; | 3 | mod traits; |
5 | mod use_item; | 4 | mod use_item; |
6 | 5 | ||
7 | use super::*; | ||
8 | pub(crate) use self::{ | 6 | pub(crate) use self::{ |
9 | expressions::{named_field_list, match_arm_list}, | 7 | expressions::{match_arm_list, named_field_list}, |
10 | nominal::{enum_variant_list, named_field_def_list}, | 8 | nominal::{enum_variant_list, named_field_def_list}, |
11 | traits::{trait_item_list, impl_item_list}, | 9 | traits::{impl_item_list, trait_item_list}, |
12 | use_item::use_tree_list, | 10 | use_item::use_tree_list, |
13 | }; | 11 | }; |
12 | use super::*; | ||
14 | 13 | ||
15 | // test mod_contents | 14 | // test mod_contents |
16 | // fn foo() {} | 15 | // fn foo() {} |
@@ -26,12 +25,14 @@ pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { | |||
26 | } | 25 | } |
27 | 26 | ||
28 | pub(super) enum ItemFlavor { | 27 | pub(super) enum ItemFlavor { |
29 | Mod, Trait | 28 | Mod, |
29 | Trait, | ||
30 | } | 30 | } |
31 | 31 | ||
32 | const ITEM_RECOVERY_SET: TokenSet = | 32 | const ITEM_RECOVERY_SET: TokenSet = token_set![ |
33 | token_set![FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, | 33 | FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, |
34 | MOD_KW, PUB_KW, CRATE_KW]; | 34 | CRATE_KW |
35 | ]; | ||
35 | 36 | ||
36 | pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { | 37 | pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { |
37 | let m = p.start(); | 38 | let m = p.start(); |
@@ -153,10 +154,12 @@ pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem { | |||
153 | traits::impl_item(p); | 154 | traits::impl_item(p); |
154 | IMPL_ITEM | 155 | IMPL_ITEM |
155 | } | 156 | } |
156 | _ => return if has_mods { | 157 | _ => { |
157 | MaybeItem::Modifiers | 158 | return if has_mods { |
158 | } else { | 159 | MaybeItem::Modifiers |
159 | MaybeItem::None | 160 | } else { |
161 | MaybeItem::None | ||
162 | } | ||
160 | } | 163 | } |
161 | }; | 164 | }; |
162 | 165 | ||
@@ -194,7 +197,7 @@ fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> { | |||
194 | if p.at(SEMI) { | 197 | if p.at(SEMI) { |
195 | p.err_and_bump( | 198 | p.err_and_bump( |
196 | "expected item, found `;`\n\ | 199 | "expected item, found `;`\n\ |
197 | consider removing this semicolon" | 200 | consider removing this semicolon", |
198 | ); | 201 | ); |
199 | } | 202 | } |
200 | STRUCT_DEF | 203 | STRUCT_DEF |
@@ -227,7 +230,9 @@ fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> { | |||
227 | } | 230 | } |
228 | // test extern_block | 231 | // test extern_block |
229 | // extern {} | 232 | // extern {} |
230 | EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => { | 233 | EXTERN_KW |
234 | if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => | ||
235 | { | ||
231 | abi(p); | 236 | abi(p); |
232 | extern_item_list(p); | 237 | extern_item_list(p); |
233 | EXTERN_BLOCK | 238 | EXTERN_BLOCK |
@@ -267,10 +272,8 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) { | |||
267 | 272 | ||
268 | if p.at(L_PAREN) { | 273 | if p.at(L_PAREN) { |
269 | match flavor { | 274 | match flavor { |
270 | ItemFlavor::Mod => | 275 | ItemFlavor::Mod => params::param_list(p), |
271 | params::param_list(p), | 276 | ItemFlavor::Trait => params::param_list_opt_patterns(p), |
272 | ItemFlavor::Trait => | ||
273 | params::param_list_opt_patterns(p), | ||
274 | } | 277 | } |
275 | } else { | 278 | } else { |
276 | p.error("expected function arguments"); | 279 | p.error("expected function arguments"); |
@@ -361,7 +364,7 @@ pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike { | |||
361 | _ => { | 364 | _ => { |
362 | p.error("expected `{`, `[`, `(`"); | 365 | p.error("expected `{`, `[`, `(`"); |
363 | BlockLike::NotBlock | 366 | BlockLike::NotBlock |
364 | }, | 367 | } |
365 | }; | 368 | }; |
366 | 369 | ||
367 | flavor | 370 | flavor |
@@ -385,9 +388,9 @@ pub(crate) fn token_tree(p: &mut Parser) { | |||
385 | return; | 388 | return; |
386 | } | 389 | } |
387 | R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"), | 390 | R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"), |
388 | _ => p.bump() | 391 | _ => p.bump(), |
389 | } | 392 | } |
390 | }; | 393 | } |
391 | p.expect(closing_paren_kind); | 394 | p.expect(closing_paren_kind); |
392 | m.complete(p, TOKEN_TREE); | 395 | m.complete(p, TOKEN_TREE); |
393 | } | 396 | } |
diff --git a/crates/ra_syntax/src/grammar/items/traits.rs b/crates/ra_syntax/src/grammar/items/traits.rs index 5dfdb470c..31258c253 100644 --- a/crates/ra_syntax/src/grammar/items/traits.rs +++ b/crates/ra_syntax/src/grammar/items/traits.rs | |||
@@ -128,4 +128,3 @@ pub(crate) fn impl_type(p: &mut Parser) { | |||
128 | } | 128 | } |
129 | types::type_(p); | 129 | types::type_(p); |
130 | } | 130 | } |
131 | |||
diff --git a/crates/ra_syntax/src/grammar/mod.rs b/crates/ra_syntax/src/grammar/mod.rs index 1199ba230..c87564073 100644 --- a/crates/ra_syntax/src/grammar/mod.rs +++ b/crates/ra_syntax/src/grammar/mod.rs | |||
@@ -31,28 +31,18 @@ mod type_args; | |||
31 | mod type_params; | 31 | mod type_params; |
32 | mod types; | 32 | mod types; |
33 | 33 | ||
34 | use crate::{ | ||
35 | token_set::TokenSet, | ||
36 | parser_api::{Marker, CompletedMarker, Parser}, | ||
37 | SyntaxKind::{self, *}, | ||
38 | }; | ||
39 | pub(crate) use self::{ | 34 | pub(crate) use self::{ |
40 | expressions::{ | 35 | expressions::block, |
41 | block, | ||
42 | }, | ||
43 | items::{ | 36 | items::{ |
44 | enum_variant_list, | 37 | enum_variant_list, extern_item_list, impl_item_list, match_arm_list, mod_item_list, |
45 | extern_item_list, | 38 | named_field_def_list, named_field_list, token_tree, trait_item_list, use_tree_list, |
46 | impl_item_list, | ||
47 | match_arm_list, | ||
48 | mod_item_list, | ||
49 | named_field_def_list, | ||
50 | named_field_list, | ||
51 | token_tree, | ||
52 | trait_item_list, | ||
53 | use_tree_list, | ||
54 | }, | 39 | }, |
55 | }; | 40 | }; |
41 | use crate::{ | ||
42 | parser_api::{CompletedMarker, Marker, Parser}, | ||
43 | token_set::TokenSet, | ||
44 | SyntaxKind::{self, *}, | ||
45 | }; | ||
56 | 46 | ||
57 | pub(crate) fn root(p: &mut Parser) { | 47 | pub(crate) fn root(p: &mut Parser) { |
58 | let m = p.start(); | 48 | let m = p.start(); |
@@ -61,7 +51,6 @@ pub(crate) fn root(p: &mut Parser) { | |||
61 | m.complete(p, ROOT); | 51 | m.complete(p, ROOT); |
62 | } | 52 | } |
63 | 53 | ||
64 | |||
65 | #[derive(Clone, Copy, PartialEq, Eq)] | 54 | #[derive(Clone, Copy, PartialEq, Eq)] |
66 | enum BlockLike { | 55 | enum BlockLike { |
67 | Block, | 56 | Block, |
@@ -69,7 +58,9 @@ enum BlockLike { | |||
69 | } | 58 | } |
70 | 59 | ||
71 | impl BlockLike { | 60 | impl BlockLike { |
72 | fn is_block(self) -> bool { self == BlockLike::Block } | 61 | fn is_block(self) -> bool { |
62 | self == BlockLike::Block | ||
63 | } | ||
73 | } | 64 | } |
74 | 65 | ||
75 | fn opt_visibility(p: &mut Parser) { | 66 | fn opt_visibility(p: &mut Parser) { |
diff --git a/crates/ra_syntax/src/grammar/params.rs b/crates/ra_syntax/src/grammar/params.rs index 903c25939..b71a72ca3 100644 --- a/crates/ra_syntax/src/grammar/params.rs +++ b/crates/ra_syntax/src/grammar/params.rs | |||
@@ -61,12 +61,8 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
61 | m.complete(p, PARAM_LIST); | 61 | m.complete(p, PARAM_LIST); |
62 | } | 62 | } |
63 | 63 | ||
64 | |||
65 | const VALUE_PARAMETER_FIRST: TokenSet = | 64 | const VALUE_PARAMETER_FIRST: TokenSet = |
66 | token_set_union![ | 65 | token_set_union![patterns::PATTERN_FIRST, types::TYPE_FIRST,]; |
67 | patterns::PATTERN_FIRST, | ||
68 | types::TYPE_FIRST, | ||
69 | ]; | ||
70 | 66 | ||
71 | fn value_parameter(p: &mut Parser, flavor: Flavor) { | 67 | fn value_parameter(p: &mut Parser, flavor: Flavor) { |
72 | let m = p.start(); | 68 | let m = p.start(); |
@@ -76,7 +72,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) { | |||
76 | if p.at(COLON) || flavor.type_required() { | 72 | if p.at(COLON) || flavor.type_required() { |
77 | types::ascription(p) | 73 | types::ascription(p) |
78 | } | 74 | } |
79 | }, | 75 | } |
80 | // test value_parameters_no_patterns | 76 | // test value_parameters_no_patterns |
81 | // type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>; | 77 | // type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>; |
82 | Flavor::OptionalPattern => { | 78 | Flavor::OptionalPattern => { |
@@ -86,13 +82,14 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) { | |||
86 | let la3 = p.nth(3); | 82 | let la3 = p.nth(3); |
87 | if la0 == IDENT && la1 == COLON | 83 | if la0 == IDENT && la1 == COLON |
88 | || la0 == AMP && la1 == IDENT && la2 == COLON | 84 | || la0 == AMP && la1 == IDENT && la2 == COLON |
89 | || la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON { | 85 | || la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON |
86 | { | ||
90 | patterns::pattern(p); | 87 | patterns::pattern(p); |
91 | types::ascription(p); | 88 | types::ascription(p); |
92 | } else { | 89 | } else { |
93 | types::type_(p); | 90 | types::type_(p); |
94 | } | 91 | } |
95 | }, | 92 | } |
96 | } | 93 | } |
97 | m.complete(p, PARAM); | 94 | m.complete(p, PARAM); |
98 | } | 95 | } |
diff --git a/crates/ra_syntax/src/grammar/paths.rs b/crates/ra_syntax/src/grammar/paths.rs index b6d44d53a..a35a339cc 100644 --- a/crates/ra_syntax/src/grammar/paths.rs +++ b/crates/ra_syntax/src/grammar/paths.rs | |||
@@ -97,7 +97,7 @@ fn opt_path_type_args(p: &mut Parser, mode: Mode) { | |||
97 | } else { | 97 | } else { |
98 | type_args::opt_type_arg_list(p, false) | 98 | type_args::opt_type_arg_list(p, false) |
99 | } | 99 | } |
100 | }, | 100 | } |
101 | Mode::Expr => type_args::opt_type_arg_list(p, true), | 101 | Mode::Expr => type_args::opt_type_arg_list(p, true), |
102 | } | 102 | } |
103 | } | 103 | } |
diff --git a/crates/ra_syntax/src/grammar/patterns.rs b/crates/ra_syntax/src/grammar/patterns.rs index 420bae7a7..9d35dbb3d 100644 --- a/crates/ra_syntax/src/grammar/patterns.rs +++ b/crates/ra_syntax/src/grammar/patterns.rs | |||
@@ -1,11 +1,10 @@ | |||
1 | use super::*; | 1 | use super::*; |
2 | 2 | ||
3 | pub(super) const PATTERN_FIRST: TokenSet = | 3 | pub(super) const PATTERN_FIRST: TokenSet = token_set_union![ |
4 | token_set_union![ | 4 | token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE], |
5 | token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE], | 5 | expressions::LITERAL_FIRST, |
6 | expressions::LITERAL_FIRST, | 6 | paths::PATH_FIRST, |
7 | paths::PATH_FIRST, | 7 | ]; |
8 | ]; | ||
9 | 8 | ||
10 | pub(super) fn pattern(p: &mut Parser) { | 9 | pub(super) fn pattern(p: &mut Parser) { |
11 | pattern_r(p, PAT_RECOVERY_SET) | 10 | pattern_r(p, PAT_RECOVERY_SET) |
@@ -29,12 +28,13 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) { | |||
29 | const PAT_RECOVERY_SET: TokenSet = | 28 | const PAT_RECOVERY_SET: TokenSet = |
30 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; | 29 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; |
31 | 30 | ||
32 | |||
33 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | 31 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { |
34 | let la0 = p.nth(0); | 32 | let la0 = p.nth(0); |
35 | let la1 = p.nth(1); | 33 | let la1 = p.nth(1); |
36 | if la0 == REF_KW || la0 == MUT_KW | 34 | if la0 == REF_KW |
37 | || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY)) { | 35 | || la0 == MUT_KW |
36 | || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY)) | ||
37 | { | ||
38 | return Some(bind_pat(p, true)); | 38 | return Some(bind_pat(p, true)); |
39 | } | 39 | } |
40 | if paths::is_path_start(p) { | 40 | if paths::is_path_start(p) { |
@@ -87,7 +87,7 @@ fn path_pat(p: &mut Parser) -> CompletedMarker { | |||
87 | field_pat_list(p); | 87 | field_pat_list(p); |
88 | STRUCT_PAT | 88 | STRUCT_PAT |
89 | } | 89 | } |
90 | _ => PATH_PAT | 90 | _ => PATH_PAT, |
91 | }; | 91 | }; |
92 | m.complete(p, kind) | 92 | m.complete(p, kind) |
93 | } | 93 | } |
@@ -195,7 +195,7 @@ fn pat_list(p: &mut Parser, ket: SyntaxKind) { | |||
195 | break; | 195 | break; |
196 | } | 196 | } |
197 | pattern(p) | 197 | pattern(p) |
198 | }, | 198 | } |
199 | } | 199 | } |
200 | if !p.at(ket) { | 200 | if !p.at(ket) { |
201 | p.expect(COMMA); | 201 | p.expect(COMMA); |
diff --git a/crates/ra_syntax/src/grammar/type_params.rs b/crates/ra_syntax/src/grammar/type_params.rs index 79bc95ce4..79f5036b4 100644 --- a/crates/ra_syntax/src/grammar/type_params.rs +++ b/crates/ra_syntax/src/grammar/type_params.rs | |||
@@ -72,12 +72,8 @@ pub(super) fn bounds_without_colon(p: &mut Parser) { | |||
72 | p.eat(QUESTION); | 72 | p.eat(QUESTION); |
73 | match p.current() { | 73 | match p.current() { |
74 | LIFETIME => p.bump(), | 74 | LIFETIME => p.bump(), |
75 | FOR_KW => { | 75 | FOR_KW => types::for_type(p), |
76 | types::for_type(p) | 76 | _ if paths::is_path_start(p) => types::path_type(p), |
77 | } | ||
78 | _ if paths::is_path_start(p) => { | ||
79 | types::path_type(p) | ||
80 | } | ||
81 | _ => break, | 77 | _ => break, |
82 | } | 78 | } |
83 | if has_paren { | 79 | if has_paren { |
@@ -104,7 +100,7 @@ pub(super) fn opt_where_clause(p: &mut Parser) { | |||
104 | p.bump(); | 100 | p.bump(); |
105 | loop { | 101 | loop { |
106 | if !(paths::is_path_start(p) || p.current() == LIFETIME) { | 102 | if !(paths::is_path_start(p) || p.current() == LIFETIME) { |
107 | break | 103 | break; |
108 | } | 104 | } |
109 | where_predicate(p); | 105 | where_predicate(p); |
110 | if p.current() != L_CURLY && p.current() != SEMI { | 106 | if p.current() != L_CURLY && p.current() != SEMI { |
@@ -130,7 +126,6 @@ fn where_predicate(p: &mut Parser) { | |||
130 | } else { | 126 | } else { |
131 | p.error("expected colon") | 127 | p.error("expected colon") |
132 | } | 128 | } |
133 | |||
134 | } | 129 | } |
135 | m.complete(p, WHERE_PRED); | 130 | m.complete(p, WHERE_PRED); |
136 | } | 131 | } |
diff --git a/crates/ra_syntax/src/grammar/types.rs b/crates/ra_syntax/src/grammar/types.rs index 27e5b086e..f308aef89 100644 --- a/crates/ra_syntax/src/grammar/types.rs +++ b/crates/ra_syntax/src/grammar/types.rs | |||
@@ -1,15 +1,14 @@ | |||
1 | use super::*; | 1 | use super::*; |
2 | 2 | ||
3 | pub(super) const TYPE_FIRST: TokenSet = | 3 | pub(super) const TYPE_FIRST: TokenSet = token_set_union![ |
4 | token_set_union![ | 4 | token_set![ |
5 | token_set![ | 5 | L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, |
6 | L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, IMPL_KW, DYN_KW, L_ANGLE, | 6 | IMPL_KW, DYN_KW, L_ANGLE, |
7 | ], | 7 | ], |
8 | paths::PATH_FIRST, | 8 | paths::PATH_FIRST, |
9 | ]; | 9 | ]; |
10 | 10 | ||
11 | const TYPE_RECOVERY_SET: TokenSet = | 11 | const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA]; |
12 | token_set![R_PAREN, COMMA]; | ||
13 | 12 | ||
14 | pub(super) fn type_(p: &mut Parser) { | 13 | pub(super) fn type_(p: &mut Parser) { |
15 | match p.current() { | 14 | match p.current() { |
@@ -200,7 +199,6 @@ pub(super) fn for_type(p: &mut Parser) { | |||
200 | FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p), | 199 | FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p), |
201 | _ if paths::is_path_start(p) => path_type_(p, false), | 200 | _ if paths::is_path_start(p) => path_type_(p, false), |
202 | _ => p.error("expected a path"), | 201 | _ => p.error("expected a path"), |
203 | |||
204 | } | 202 | } |
205 | m.complete(p, FOR_TYPE); | 203 | m.complete(p, FOR_TYPE); |
206 | } | 204 | } |
diff --git a/crates/ra_syntax/src/lexer/mod.rs b/crates/ra_syntax/src/lexer/mod.rs index 9dc0b63d6..f388da273 100644 --- a/crates/ra_syntax/src/lexer/mod.rs +++ b/crates/ra_syntax/src/lexer/mod.rs | |||
@@ -58,12 +58,16 @@ fn next_token_inner(c: char, ptr: &mut Ptr) -> SyntaxKind { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | match c { | 60 | match c { |
61 | '#' => if scan_shebang(ptr) { | 61 | '#' => { |
62 | return SHEBANG; | 62 | if scan_shebang(ptr) { |
63 | }, | 63 | return SHEBANG; |
64 | '/' => if let Some(kind) = scan_comment(ptr) { | 64 | } |
65 | return kind; | 65 | } |
66 | }, | 66 | '/' => { |
67 | if let Some(kind) = scan_comment(ptr) { | ||
68 | return kind; | ||
69 | } | ||
70 | } | ||
67 | _ => (), | 71 | _ => (), |
68 | } | 72 | } |
69 | 73 | ||
diff --git a/crates/ra_syntax/src/lexer/ptr.rs b/crates/ra_syntax/src/lexer/ptr.rs index c4708cb1c..fa79d8862 100644 --- a/crates/ra_syntax/src/lexer/ptr.rs +++ b/crates/ra_syntax/src/lexer/ptr.rs | |||
@@ -134,10 +134,10 @@ mod tests { | |||
134 | #[test] | 134 | #[test] |
135 | fn test_nth_is_p() { | 135 | fn test_nth_is_p() { |
136 | let ptr = Ptr::new("test"); | 136 | let ptr = Ptr::new("test"); |
137 | assert!(ptr.nth_is_p(0,|c| c == 't')); | 137 | assert!(ptr.nth_is_p(0, |c| c == 't')); |
138 | assert!(!ptr.nth_is_p(1,|c| c == 't')); | 138 | assert!(!ptr.nth_is_p(1, |c| c == 't')); |
139 | assert!(ptr.nth_is_p(3,|c| c == 't')); | 139 | assert!(ptr.nth_is_p(3, |c| c == 't')); |
140 | assert!(!ptr.nth_is_p(150,|c| c == 't')); | 140 | assert!(!ptr.nth_is_p(150, |c| c == 't')); |
141 | } | 141 | } |
142 | 142 | ||
143 | #[test] | 143 | #[test] |
diff --git a/crates/ra_syntax/src/lexer/strings.rs b/crates/ra_syntax/src/lexer/strings.rs index bceacdcac..5090feae6 100644 --- a/crates/ra_syntax/src/lexer/strings.rs +++ b/crates/ra_syntax/src/lexer/strings.rs | |||
@@ -71,7 +71,7 @@ pub(crate) fn scan_string(ptr: &mut Ptr) { | |||
71 | } | 71 | } |
72 | _ => { | 72 | _ => { |
73 | ptr.bump(); | 73 | ptr.bump(); |
74 | }, | 74 | } |
75 | } | 75 | } |
76 | } | 76 | } |
77 | } | 77 | } |
@@ -90,7 +90,7 @@ pub(crate) fn scan_raw_string(ptr: &mut Ptr) { | |||
90 | while let Some(c) = ptr.bump() { | 90 | while let Some(c) = ptr.bump() { |
91 | if c == '"' { | 91 | if c == '"' { |
92 | let mut hashes_left = hashes; | 92 | let mut hashes_left = hashes; |
93 | while ptr.at('#') && hashes_left > 0{ | 93 | while ptr.at('#') && hashes_left > 0 { |
94 | hashes_left -= 1; | 94 | hashes_left -= 1; |
95 | ptr.bump(); | 95 | ptr.bump(); |
96 | } | 96 | } |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 7eba5ee61..7a9718aad 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -20,11 +20,11 @@ | |||
20 | #![allow(missing_docs)] | 20 | #![allow(missing_docs)] |
21 | //#![warn(unreachable_pub)] // rust-lang/rust#47816 | 21 | //#![warn(unreachable_pub)] // rust-lang/rust#47816 |
22 | 22 | ||
23 | extern crate itertools; | ||
24 | extern crate unicode_xid; | ||
25 | extern crate drop_bomb; | 23 | extern crate drop_bomb; |
24 | extern crate itertools; | ||
26 | extern crate parking_lot; | 25 | extern crate parking_lot; |
27 | extern crate rowan; | 26 | extern crate rowan; |
27 | extern crate unicode_xid; | ||
28 | 28 | ||
29 | #[cfg(test)] | 29 | #[cfg(test)] |
30 | #[macro_use] | 30 | #[macro_use] |
@@ -35,33 +35,31 @@ pub mod ast; | |||
35 | mod lexer; | 35 | mod lexer; |
36 | #[macro_use] | 36 | #[macro_use] |
37 | mod token_set; | 37 | mod token_set; |
38 | mod parser_api; | ||
39 | mod grammar; | 38 | mod grammar; |
39 | mod parser_api; | ||
40 | mod parser_impl; | 40 | mod parser_impl; |
41 | mod reparsing; | 41 | mod reparsing; |
42 | 42 | ||
43 | mod syntax_kinds; | 43 | mod syntax_kinds; |
44 | mod yellow; | 44 | pub mod text_utils; |
45 | /// Utilities for simple uses of the parser. | 45 | /// Utilities for simple uses of the parser. |
46 | pub mod utils; | 46 | pub mod utils; |
47 | pub mod text_utils; | 47 | mod yellow; |
48 | 48 | ||
49 | pub use crate::{ | 49 | pub use crate::{ |
50 | rowan::{SmolStr, TextRange, TextUnit}, | ||
51 | ast::AstNode, | 50 | ast::AstNode, |
52 | lexer::{tokenize, Token}, | 51 | lexer::{tokenize, Token}, |
53 | syntax_kinds::SyntaxKind, | ||
54 | yellow::{SyntaxNode, SyntaxNodeRef, OwnedRoot, RefRoot, TreeRoot, SyntaxError, Direction}, | ||
55 | reparsing::AtomEdit, | 52 | reparsing::AtomEdit, |
53 | rowan::{SmolStr, TextRange, TextUnit}, | ||
54 | syntax_kinds::SyntaxKind, | ||
55 | yellow::{Direction, OwnedRoot, RefRoot, SyntaxError, SyntaxNode, SyntaxNodeRef, TreeRoot}, | ||
56 | }; | 56 | }; |
57 | 57 | ||
58 | use crate::{ | 58 | use crate::yellow::GreenNode; |
59 | yellow::{GreenNode}, | ||
60 | }; | ||
61 | 59 | ||
62 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 60 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
63 | pub struct File { | 61 | pub struct File { |
64 | root: SyntaxNode | 62 | root: SyntaxNode, |
65 | } | 63 | } |
66 | 64 | ||
67 | impl File { | 65 | impl File { |
@@ -74,21 +72,21 @@ impl File { | |||
74 | } | 72 | } |
75 | pub fn parse(text: &str) -> File { | 73 | pub fn parse(text: &str) -> File { |
76 | let tokens = tokenize(&text); | 74 | let tokens = tokenize(&text); |
77 | let (green, errors) = parser_impl::parse_with( | 75 | let (green, errors) = |
78 | yellow::GreenBuilder::new(), | 76 | parser_impl::parse_with(yellow::GreenBuilder::new(), text, &tokens, grammar::root); |
79 | text, &tokens, grammar::root, | ||
80 | ); | ||
81 | File::new(green, errors) | 77 | File::new(green, errors) |
82 | } | 78 | } |
83 | pub fn reparse(&self, edit: &AtomEdit) -> File { | 79 | pub fn reparse(&self, edit: &AtomEdit) -> File { |
84 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | 80 | self.incremental_reparse(edit) |
81 | .unwrap_or_else(|| self.full_reparse(edit)) | ||
85 | } | 82 | } |
86 | pub fn incremental_reparse(&self, edit: &AtomEdit) -> Option<File> { | 83 | pub fn incremental_reparse(&self, edit: &AtomEdit) -> Option<File> { |
87 | reparsing::incremental_reparse(self.syntax(), edit, self.errors()) | 84 | reparsing::incremental_reparse(self.syntax(), edit, self.errors()) |
88 | .map(|(green_node, errors)| File::new(green_node, errors)) | 85 | .map(|(green_node, errors)| File::new(green_node, errors)) |
89 | } | 86 | } |
90 | fn full_reparse(&self, edit: &AtomEdit) -> File { | 87 | fn full_reparse(&self, edit: &AtomEdit) -> File { |
91 | let text = text_utils::replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert); | 88 | let text = |
89 | text_utils::replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert); | ||
92 | File::parse(&text) | 90 | File::parse(&text) |
93 | } | 91 | } |
94 | pub fn ast(&self) -> ast::Root { | 92 | pub fn ast(&self) -> ast::Root { |
diff --git a/crates/ra_syntax/src/parser_api.rs b/crates/ra_syntax/src/parser_api.rs index cc23bb75e..42046d36f 100644 --- a/crates/ra_syntax/src/parser_api.rs +++ b/crates/ra_syntax/src/parser_api.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | token_set::TokenSet, | 2 | drop_bomb::DropBomb, |
3 | parser_impl::ParserImpl, | 3 | parser_impl::ParserImpl, |
4 | token_set::TokenSet, | ||
4 | SyntaxKind::{self, ERROR}, | 5 | SyntaxKind::{self, ERROR}, |
5 | drop_bomb::DropBomb, | ||
6 | }; | 6 | }; |
7 | 7 | ||
8 | /// `Parser` struct provides the low-level API for | 8 | /// `Parser` struct provides the low-level API for |
@@ -116,9 +116,7 @@ impl<'t> Parser<'t> { | |||
116 | 116 | ||
117 | /// Create an error node and consume the next token. | 117 | /// Create an error node and consume the next token. |
118 | pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { | 118 | pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { |
119 | if self.at(SyntaxKind::L_CURLY) | 119 | if self.at(SyntaxKind::L_CURLY) || self.at(SyntaxKind::R_CURLY) || self.at_ts(recovery) { |
120 | || self.at(SyntaxKind::R_CURLY) | ||
121 | || self.at_ts(recovery) { | ||
122 | self.error(message); | 120 | self.error(message); |
123 | } else { | 121 | } else { |
124 | let m = self.start(); | 122 | let m = self.start(); |
diff --git a/crates/ra_syntax/src/parser_impl/event.rs b/crates/ra_syntax/src/parser_impl/event.rs index 928d2cc7a..79fa21389 100644 --- a/crates/ra_syntax/src/parser_impl/event.rs +++ b/crates/ra_syntax/src/parser_impl/event.rs | |||
@@ -7,14 +7,14 @@ | |||
7 | //! tree builder: the parser produces a stream of events like | 7 | //! tree builder: the parser produces a stream of events like |
8 | //! `start node`, `finish node`, and `FileBuilder` converts | 8 | //! `start node`, `finish node`, and `FileBuilder` converts |
9 | //! this stream to a real tree. | 9 | //! this stream to a real tree. |
10 | use std::mem; | ||
11 | use crate::{ | 10 | use crate::{ |
12 | TextUnit, TextRange, SmolStr, | ||
13 | lexer::Token, | 11 | lexer::Token, |
14 | parser_impl::Sink, | 12 | parser_impl::Sink, |
13 | SmolStr, | ||
15 | SyntaxKind::{self, *}, | 14 | SyntaxKind::{self, *}, |
15 | TextRange, TextUnit, | ||
16 | }; | 16 | }; |
17 | 17 | use std::mem; | |
18 | 18 | ||
19 | /// `Parser` produces a flat list of `Event`s. | 19 | /// `Parser` produces a flat list of `Event`s. |
20 | /// They are converted to a tree-structure in | 20 | /// They are converted to a tree-structure in |
@@ -89,20 +89,28 @@ pub(super) struct EventProcessor<'a, S: Sink> { | |||
89 | } | 89 | } |
90 | 90 | ||
91 | impl<'a, S: Sink> EventProcessor<'a, S> { | 91 | impl<'a, S: Sink> EventProcessor<'a, S> { |
92 | pub(super) fn new(sink: S, text: &'a str, tokens: &'a[Token], events: &'a mut [Event]) -> EventProcessor<'a, S> { | 92 | pub(super) fn new( |
93 | sink: S, | ||
94 | text: &'a str, | ||
95 | tokens: &'a [Token], | ||
96 | events: &'a mut [Event], | ||
97 | ) -> EventProcessor<'a, S> { | ||
93 | EventProcessor { | 98 | EventProcessor { |
94 | sink, | 99 | sink, |
95 | text_pos: 0.into(), | 100 | text_pos: 0.into(), |
96 | text, | 101 | text, |
97 | token_pos: 0, | 102 | token_pos: 0, |
98 | tokens, | 103 | tokens, |
99 | events | 104 | events, |
100 | } | 105 | } |
101 | } | 106 | } |
102 | 107 | ||
103 | pub(super) fn process(mut self) -> S { | 108 | pub(super) fn process(mut self) -> S { |
104 | fn tombstone() -> Event { | 109 | fn tombstone() -> Event { |
105 | Event::Start { kind: TOMBSTONE, forward_parent: None } | 110 | Event::Start { |
111 | kind: TOMBSTONE, | ||
112 | forward_parent: None, | ||
113 | } | ||
106 | } | 114 | } |
107 | let mut forward_parents = Vec::new(); | 115 | let mut forward_parents = Vec::new(); |
108 | 116 | ||
@@ -112,7 +120,10 @@ impl<'a, S: Sink> EventProcessor<'a, S> { | |||
112 | kind: TOMBSTONE, .. | 120 | kind: TOMBSTONE, .. |
113 | } => (), | 121 | } => (), |
114 | 122 | ||
115 | Event::Start { kind, forward_parent } => { | 123 | Event::Start { |
124 | kind, | ||
125 | forward_parent, | ||
126 | } => { | ||
116 | forward_parents.push(kind); | 127 | forward_parents.push(kind); |
117 | let mut idx = i; | 128 | let mut idx = i; |
118 | let mut fp = forward_parent; | 129 | let mut fp = forward_parent; |
@@ -125,7 +136,7 @@ impl<'a, S: Sink> EventProcessor<'a, S> { | |||
125 | } => { | 136 | } => { |
126 | forward_parents.push(kind); | 137 | forward_parents.push(kind); |
127 | forward_parent | 138 | forward_parent |
128 | }, | 139 | } |
129 | _ => unreachable!(), | 140 | _ => unreachable!(), |
130 | }; | 141 | }; |
131 | } | 142 | } |
@@ -136,7 +147,7 @@ impl<'a, S: Sink> EventProcessor<'a, S> { | |||
136 | Event::Finish => { | 147 | Event::Finish => { |
137 | let last = i == self.events.len() - 1; | 148 | let last = i == self.events.len() - 1; |
138 | self.finish(last); | 149 | self.finish(last); |
139 | }, | 150 | } |
140 | Event::Token { kind, n_raw_tokens } => { | 151 | Event::Token { kind, n_raw_tokens } => { |
141 | self.eat_ws(); | 152 | self.eat_ws(); |
142 | let n_raw_tokens = n_raw_tokens as usize; | 153 | let n_raw_tokens = n_raw_tokens as usize; |
@@ -162,19 +173,16 @@ impl<'a, S: Sink> EventProcessor<'a, S> { | |||
162 | .take_while(|it| it.kind.is_trivia()) | 173 | .take_while(|it| it.kind.is_trivia()) |
163 | .count(); | 174 | .count(); |
164 | let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias]; | 175 | let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias]; |
165 | let mut trivia_end = self.text_pos + leading_trivias | 176 | let mut trivia_end = |
166 | .iter() | 177 | self.text_pos + leading_trivias.iter().map(|it| it.len).sum::<TextUnit>(); |
167 | .map(|it| it.len) | ||
168 | .sum::<TextUnit>(); | ||
169 | 178 | ||
170 | let n_attached_trivias = { | 179 | let n_attached_trivias = { |
171 | let leading_trivias = leading_trivias.iter().rev() | 180 | let leading_trivias = leading_trivias.iter().rev().map(|it| { |
172 | .map(|it| { | 181 | let next_end = trivia_end - it.len; |
173 | let next_end = trivia_end - it.len; | 182 | let range = TextRange::from_to(next_end, trivia_end); |
174 | let range = TextRange::from_to(next_end, trivia_end); | 183 | trivia_end = next_end; |
175 | trivia_end = next_end; | 184 | (it.kind, &self.text[range]) |
176 | (it.kind, &self.text[range]) | 185 | }); |
177 | }); | ||
178 | n_attached_trivias(kind, leading_trivias) | 186 | n_attached_trivias(kind, leading_trivias) |
179 | }; | 187 | }; |
180 | self.eat_n_trivias(n_trivias - n_attached_trivias); | 188 | self.eat_n_trivias(n_trivias - n_attached_trivias); |
@@ -215,7 +223,10 @@ impl<'a, S: Sink> EventProcessor<'a, S> { | |||
215 | } | 223 | } |
216 | } | 224 | } |
217 | 225 | ||
218 | fn n_attached_trivias<'a>(kind: SyntaxKind, trivias: impl Iterator<Item=(SyntaxKind, &'a str)>) -> usize { | 226 | fn n_attached_trivias<'a>( |
227 | kind: SyntaxKind, | ||
228 | trivias: impl Iterator<Item = (SyntaxKind, &'a str)>, | ||
229 | ) -> usize { | ||
219 | match kind { | 230 | match kind { |
220 | STRUCT_DEF | ENUM_DEF | FN_DEF | TRAIT_DEF | MODULE => { | 231 | STRUCT_DEF | ENUM_DEF | FN_DEF | TRAIT_DEF | MODULE => { |
221 | let mut res = 0; | 232 | let mut res = 0; |
@@ -236,5 +247,4 @@ fn n_attached_trivias<'a>(kind: SyntaxKind, trivias: impl Iterator<Item=(SyntaxK | |||
236 | } | 247 | } |
237 | _ => 0, | 248 | _ => 0, |
238 | } | 249 | } |
239 | |||
240 | } | 250 | } |
diff --git a/crates/ra_syntax/src/parser_impl/mod.rs b/crates/ra_syntax/src/parser_impl/mod.rs index c2a6448e7..2b026d61e 100644 --- a/crates/ra_syntax/src/parser_impl/mod.rs +++ b/crates/ra_syntax/src/parser_impl/mod.rs | |||
@@ -4,13 +4,13 @@ mod input; | |||
4 | use std::cell::Cell; | 4 | use std::cell::Cell; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | TextUnit, SmolStr, | ||
8 | lexer::Token, | 7 | lexer::Token, |
9 | parser_api::Parser, | 8 | parser_api::Parser, |
10 | parser_impl::{ | 9 | parser_impl::{ |
11 | event::{EventProcessor, Event}, | 10 | event::{Event, EventProcessor}, |
12 | input::{InputPosition, ParserInput}, | 11 | input::{InputPosition, ParserInput}, |
13 | }, | 12 | }, |
13 | SmolStr, TextUnit, | ||
14 | }; | 14 | }; |
15 | 15 | ||
16 | use crate::SyntaxKind::{self, EOF, TOMBSTONE}; | 16 | use crate::SyntaxKind::{self, EOF, TOMBSTONE}; |
@@ -86,7 +86,9 @@ impl<'t> ParserImpl<'t> { | |||
86 | let c2 = self.inp.kind(self.pos + 1); | 86 | let c2 = self.inp.kind(self.pos + 1); |
87 | let c3 = self.inp.kind(self.pos + 2); | 87 | let c3 = self.inp.kind(self.pos + 2); |
88 | if self.inp.start(self.pos + 1) == self.inp.start(self.pos) + self.inp.len(self.pos) | 88 | if self.inp.start(self.pos + 1) == self.inp.start(self.pos) + self.inp.len(self.pos) |
89 | && self.inp.start(self.pos + 2) == self.inp.start(self.pos + 1) + self.inp.len(self.pos + 1){ | 89 | && self.inp.start(self.pos + 2) |
90 | == self.inp.start(self.pos + 1) + self.inp.len(self.pos + 1) | ||
91 | { | ||
90 | Some((c1, c2, c3)) | 92 | Some((c1, c2, c3)) |
91 | } else { | 93 | } else { |
92 | None | 94 | None |
@@ -138,10 +140,7 @@ impl<'t> ParserImpl<'t> { | |||
138 | 140 | ||
139 | fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { | 141 | fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { |
140 | self.pos += u32::from(n_raw_tokens); | 142 | self.pos += u32::from(n_raw_tokens); |
141 | self.event(Event::Token { | 143 | self.event(Event::Token { kind, n_raw_tokens }); |
142 | kind, | ||
143 | n_raw_tokens, | ||
144 | }); | ||
145 | } | 144 | } |
146 | 145 | ||
147 | pub(super) fn error(&mut self, msg: String) { | 146 | pub(super) fn error(&mut self, msg: String) { |
diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs index 16272fe88..a0014e016 100644 --- a/crates/ra_syntax/src/reparsing.rs +++ b/crates/ra_syntax/src/reparsing.rs | |||
@@ -1,14 +1,11 @@ | |||
1 | use crate::algo; | 1 | use crate::algo; |
2 | use crate::grammar; | 2 | use crate::grammar; |
3 | use crate::lexer::{tokenize, Token}; | 3 | use crate::lexer::{tokenize, Token}; |
4 | use crate::yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError}; | ||
5 | use crate::parser_impl; | ||
6 | use crate::parser_api::Parser; | 4 | use crate::parser_api::Parser; |
7 | use crate::{ | 5 | use crate::parser_impl; |
8 | TextUnit, TextRange, | ||
9 | SyntaxKind::*, | ||
10 | }; | ||
11 | use crate::text_utils::replace_range; | 6 | use crate::text_utils::replace_range; |
7 | use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNodeRef}; | ||
8 | use crate::{SyntaxKind::*, TextRange, TextUnit}; | ||
12 | 9 | ||
13 | #[derive(Debug, Clone)] | 10 | #[derive(Debug, Clone)] |
14 | pub struct AtomEdit { | 11 | pub struct AtomEdit { |
@@ -18,7 +15,10 @@ pub struct AtomEdit { | |||
18 | 15 | ||
19 | impl AtomEdit { | 16 | impl AtomEdit { |
20 | pub fn replace(range: TextRange, replace_with: String) -> AtomEdit { | 17 | pub fn replace(range: TextRange, replace_with: String) -> AtomEdit { |
21 | AtomEdit { delete: range, insert: replace_with } | 18 | AtomEdit { |
19 | delete: range, | ||
20 | insert: replace_with, | ||
21 | } | ||
22 | } | 22 | } |
23 | 23 | ||
24 | pub fn delete(range: TextRange) -> AtomEdit { | 24 | pub fn delete(range: TextRange) -> AtomEdit { |
@@ -48,12 +48,7 @@ fn reparse_leaf<'node>( | |||
48 | ) -> Option<(SyntaxNodeRef<'node>, GreenNode, Vec<SyntaxError>)> { | 48 | ) -> Option<(SyntaxNodeRef<'node>, GreenNode, Vec<SyntaxError>)> { |
49 | let node = algo::find_covering_node(node, edit.delete); | 49 | let node = algo::find_covering_node(node, edit.delete); |
50 | match node.kind() { | 50 | match node.kind() { |
51 | | WHITESPACE | 51 | WHITESPACE | COMMENT | DOC_COMMENT | IDENT | STRING | RAW_STRING => { |
52 | | COMMENT | ||
53 | | DOC_COMMENT | ||
54 | | IDENT | ||
55 | | STRING | ||
56 | | RAW_STRING => { | ||
57 | let text = get_text_after_edit(node, &edit); | 52 | let text = get_text_after_edit(node, &edit); |
58 | let tokens = tokenize(&text); | 53 | let tokens = tokenize(&text); |
59 | let token = match tokens[..] { | 54 | let token = match tokens[..] { |
@@ -84,10 +79,7 @@ fn reparse_block<'node>( | |||
84 | return None; | 79 | return None; |
85 | } | 80 | } |
86 | let (green, new_errors) = | 81 | let (green, new_errors) = |
87 | parser_impl::parse_with( | 82 | parser_impl::parse_with(yellow::GreenBuilder::new(), &text, &tokens, reparser); |
88 | yellow::GreenBuilder::new(), | ||
89 | &text, &tokens, reparser, | ||
90 | ); | ||
91 | Some((node, green, new_errors)) | 83 | Some((node, green, new_errors)) |
92 | } | 84 | } |
93 | 85 | ||
@@ -101,9 +93,7 @@ fn get_text_after_edit(node: SyntaxNodeRef, edit: &AtomEdit) -> String { | |||
101 | 93 | ||
102 | fn is_contextual_kw(text: &str) -> bool { | 94 | fn is_contextual_kw(text: &str) -> bool { |
103 | match text { | 95 | match text { |
104 | | "auto" | 96 | "auto" | "default" | "union" => true, |
105 | | "default" | ||
106 | | "union" => true, | ||
107 | _ => false, | 97 | _ => false, |
108 | } | 98 | } |
109 | } | 99 | } |
@@ -113,7 +103,8 @@ fn find_reparsable_node<'node>( | |||
113 | range: TextRange, | 103 | range: TextRange, |
114 | ) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> { | 104 | ) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> { |
115 | let node = algo::find_covering_node(node, range); | 105 | let node = algo::find_covering_node(node, range); |
116 | return node.ancestors() | 106 | return node |
107 | .ancestors() | ||
117 | .filter_map(|node| reparser(node).map(|r| (node, r))) | 108 | .filter_map(|node| reparser(node).map(|r| (node, r))) |
118 | .next(); | 109 | .next(); |
119 | 110 | ||
@@ -145,17 +136,20 @@ fn find_reparsable_node<'node>( | |||
145 | fn is_balanced(tokens: &[Token]) -> bool { | 136 | fn is_balanced(tokens: &[Token]) -> bool { |
146 | if tokens.len() == 0 | 137 | if tokens.len() == 0 |
147 | || tokens.first().unwrap().kind != L_CURLY | 138 | || tokens.first().unwrap().kind != L_CURLY |
148 | || tokens.last().unwrap().kind != R_CURLY { | 139 | || tokens.last().unwrap().kind != R_CURLY |
140 | { | ||
149 | return false; | 141 | return false; |
150 | } | 142 | } |
151 | let mut balance = 0usize; | 143 | let mut balance = 0usize; |
152 | for t in tokens.iter() { | 144 | for t in tokens.iter() { |
153 | match t.kind { | 145 | match t.kind { |
154 | L_CURLY => balance += 1, | 146 | L_CURLY => balance += 1, |
155 | R_CURLY => balance = match balance.checked_sub(1) { | 147 | R_CURLY => { |
156 | Some(b) => b, | 148 | balance = match balance.checked_sub(1) { |
157 | None => return false, | 149 | Some(b) => b, |
158 | }, | 150 | None => return false, |
151 | } | ||
152 | } | ||
159 | _ => (), | 153 | _ => (), |
160 | } | 154 | } |
161 | } | 155 | } |
@@ -191,24 +185,14 @@ fn merge_errors( | |||
191 | #[cfg(test)] | 185 | #[cfg(test)] |
192 | mod tests { | 186 | mod tests { |
193 | use super::{ | 187 | use super::{ |
194 | super::{ | 188 | super::{test_utils::extract_range, text_utils::replace_range, utils::dump_tree, File}, |
195 | File, | 189 | reparse_block, reparse_leaf, AtomEdit, GreenNode, SyntaxError, SyntaxNodeRef, |
196 | test_utils::extract_range, | ||
197 | text_utils::replace_range, | ||
198 | utils::dump_tree, | ||
199 | }, | ||
200 | reparse_leaf, reparse_block, AtomEdit, GreenNode, SyntaxError, SyntaxNodeRef, | ||
201 | }; | 190 | }; |
202 | 191 | ||
203 | fn do_check<F>( | 192 | fn do_check<F>(before: &str, replace_with: &str, reparser: F) |
204 | before: &str, | 193 | where |
205 | replace_with: &str, | 194 | for<'a> F: Fn(SyntaxNodeRef<'a>, &AtomEdit) |
206 | reparser: F, | 195 | -> Option<(SyntaxNodeRef<'a>, GreenNode, Vec<SyntaxError>)>, |
207 | ) where | ||
208 | for<'a> F: Fn( | ||
209 | SyntaxNodeRef<'a>, | ||
210 | &AtomEdit, | ||
211 | ) -> Option<(SyntaxNodeRef<'a>, GreenNode, Vec<SyntaxError>)> | ||
212 | { | 196 | { |
213 | let (range, before) = extract_range(before); | 197 | let (range, before) = extract_range(before); |
214 | let after = replace_range(before.clone(), range, replace_with); | 198 | let after = replace_range(before.clone(), range, replace_with); |
@@ -216,7 +200,10 @@ mod tests { | |||
216 | let fully_reparsed = File::parse(&after); | 200 | let fully_reparsed = File::parse(&after); |
217 | let incrementally_reparsed = { | 201 | let incrementally_reparsed = { |
218 | let f = File::parse(&before); | 202 | let f = File::parse(&before); |
219 | let edit = AtomEdit { delete: range, insert: replace_with.to_string() }; | 203 | let edit = AtomEdit { |
204 | delete: range, | ||
205 | insert: replace_with.to_string(), | ||
206 | }; | ||
220 | let (node, green, new_errors) = | 207 | let (node, green, new_errors) = |
221 | reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); | 208 | reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); |
222 | let green_root = node.replace_with(green); | 209 | let green_root = node.replace_with(green); |
@@ -232,113 +219,183 @@ mod tests { | |||
232 | 219 | ||
233 | #[test] | 220 | #[test] |
234 | fn reparse_block_tests() { | 221 | fn reparse_block_tests() { |
235 | let do_check = |before, replace_to| | 222 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_block); |
236 | do_check(before, replace_to, reparse_block); | ||
237 | 223 | ||
238 | do_check(r" | 224 | do_check( |
225 | r" | ||
239 | fn foo() { | 226 | fn foo() { |
240 | let x = foo + <|>bar<|> | 227 | let x = foo + <|>bar<|> |
241 | } | 228 | } |
242 | ", "baz"); | 229 | ", |
243 | do_check(r" | 230 | "baz", |
231 | ); | ||
232 | do_check( | ||
233 | r" | ||
244 | fn foo() { | 234 | fn foo() { |
245 | let x = foo<|> + bar<|> | 235 | let x = foo<|> + bar<|> |
246 | } | 236 | } |
247 | ", "baz"); | 237 | ", |
248 | do_check(r" | 238 | "baz", |
239 | ); | ||
240 | do_check( | ||
241 | r" | ||
249 | struct Foo { | 242 | struct Foo { |
250 | f: foo<|><|> | 243 | f: foo<|><|> |
251 | } | 244 | } |
252 | ", ",\n g: (),"); | 245 | ", |
253 | do_check(r" | 246 | ",\n g: (),", |
247 | ); | ||
248 | do_check( | ||
249 | r" | ||
254 | fn foo { | 250 | fn foo { |
255 | let; | 251 | let; |
256 | 1 + 1; | 252 | 1 + 1; |
257 | <|>92<|>; | 253 | <|>92<|>; |
258 | } | 254 | } |
259 | ", "62"); | 255 | ", |
260 | do_check(r" | 256 | "62", |
257 | ); | ||
258 | do_check( | ||
259 | r" | ||
261 | mod foo { | 260 | mod foo { |
262 | fn <|><|> | 261 | fn <|><|> |
263 | } | 262 | } |
264 | ", "bar"); | 263 | ", |
265 | do_check(r" | 264 | "bar", |
265 | ); | ||
266 | do_check( | ||
267 | r" | ||
266 | trait Foo { | 268 | trait Foo { |
267 | type <|>Foo<|>; | 269 | type <|>Foo<|>; |
268 | } | 270 | } |
269 | ", "Output"); | 271 | ", |
270 | do_check(r" | 272 | "Output", |
273 | ); | ||
274 | do_check( | ||
275 | r" | ||
271 | impl IntoIterator<Item=i32> for Foo { | 276 | impl IntoIterator<Item=i32> for Foo { |
272 | f<|><|> | 277 | f<|><|> |
273 | } | 278 | } |
274 | ", "n next("); | 279 | ", |
275 | do_check(r" | 280 | "n next(", |
281 | ); | ||
282 | do_check( | ||
283 | r" | ||
276 | use a::b::{foo,<|>,bar<|>}; | 284 | use a::b::{foo,<|>,bar<|>}; |
277 | ", "baz"); | 285 | ", |
278 | do_check(r" | 286 | "baz", |
287 | ); | ||
288 | do_check( | ||
289 | r" | ||
279 | pub enum A { | 290 | pub enum A { |
280 | Foo<|><|> | 291 | Foo<|><|> |
281 | } | 292 | } |
282 | ", "\nBar;\n"); | 293 | ", |
283 | do_check(r" | 294 | "\nBar;\n", |
295 | ); | ||
296 | do_check( | ||
297 | r" | ||
284 | foo!{a, b<|><|> d} | 298 | foo!{a, b<|><|> d} |
285 | ", ", c[3]"); | 299 | ", |
286 | do_check(r" | 300 | ", c[3]", |
301 | ); | ||
302 | do_check( | ||
303 | r" | ||
287 | fn foo() { | 304 | fn foo() { |
288 | vec![<|><|>] | 305 | vec![<|><|>] |
289 | } | 306 | } |
290 | ", "123"); | 307 | ", |
291 | do_check(r" | 308 | "123", |
309 | ); | ||
310 | do_check( | ||
311 | r" | ||
292 | extern { | 312 | extern { |
293 | fn<|>;<|> | 313 | fn<|>;<|> |
294 | } | 314 | } |
295 | ", " exit(code: c_int)"); | 315 | ", |
316 | " exit(code: c_int)", | ||
317 | ); | ||
296 | } | 318 | } |
297 | 319 | ||
298 | #[test] | 320 | #[test] |
299 | fn reparse_leaf_tests() { | 321 | fn reparse_leaf_tests() { |
300 | let do_check = |before, replace_to| | 322 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf); |
301 | do_check(before, replace_to, reparse_leaf); | ||
302 | 323 | ||
303 | do_check(r"<|><|> | 324 | do_check( |
325 | r"<|><|> | ||
304 | fn foo() -> i32 { 1 } | 326 | fn foo() -> i32 { 1 } |
305 | ", "\n\n\n \n"); | 327 | ", |
306 | do_check(r" | 328 | "\n\n\n \n", |
329 | ); | ||
330 | do_check( | ||
331 | r" | ||
307 | fn foo() -> <|><|> {} | 332 | fn foo() -> <|><|> {} |
308 | ", " \n"); | 333 | ", |
309 | do_check(r" | 334 | " \n", |
335 | ); | ||
336 | do_check( | ||
337 | r" | ||
310 | fn <|>foo<|>() -> i32 { 1 } | 338 | fn <|>foo<|>() -> i32 { 1 } |
311 | ", "bar"); | 339 | ", |
312 | do_check(r" | 340 | "bar", |
341 | ); | ||
342 | do_check( | ||
343 | r" | ||
313 | fn foo<|><|>foo() { } | 344 | fn foo<|><|>foo() { } |
314 | ", "bar"); | 345 | ", |
315 | do_check(r" | 346 | "bar", |
347 | ); | ||
348 | do_check( | ||
349 | r" | ||
316 | fn foo /* <|><|> */ () {} | 350 | fn foo /* <|><|> */ () {} |
317 | ", "some comment"); | 351 | ", |
318 | do_check(r" | 352 | "some comment", |
353 | ); | ||
354 | do_check( | ||
355 | r" | ||
319 | fn baz <|><|> () {} | 356 | fn baz <|><|> () {} |
320 | ", " \t\t\n\n"); | 357 | ", |
321 | do_check(r" | 358 | " \t\t\n\n", |
359 | ); | ||
360 | do_check( | ||
361 | r" | ||
322 | fn baz <|><|> () {} | 362 | fn baz <|><|> () {} |
323 | ", " \t\t\n\n"); | 363 | ", |
324 | do_check(r" | 364 | " \t\t\n\n", |
365 | ); | ||
366 | do_check( | ||
367 | r" | ||
325 | /// foo <|><|>omment | 368 | /// foo <|><|>omment |
326 | mod { } | 369 | mod { } |
327 | ", "c"); | 370 | ", |
328 | do_check(r#" | 371 | "c", |
372 | ); | ||
373 | do_check( | ||
374 | r#" | ||
329 | fn -> &str { "Hello<|><|>" } | 375 | fn -> &str { "Hello<|><|>" } |
330 | "#, ", world"); | 376 | "#, |
331 | do_check(r#" | 377 | ", world", |
378 | ); | ||
379 | do_check( | ||
380 | r#" | ||
332 | fn -> &str { // "Hello<|><|>" | 381 | fn -> &str { // "Hello<|><|>" |
333 | "#, ", world"); | 382 | "#, |
334 | do_check(r##" | 383 | ", world", |
384 | ); | ||
385 | do_check( | ||
386 | r##" | ||
335 | fn -> &str { r#"Hello<|><|>"# | 387 | fn -> &str { r#"Hello<|><|>"# |
336 | "##, ", world"); | 388 | "##, |
337 | do_check(r" | 389 | ", world", |
390 | ); | ||
391 | do_check( | ||
392 | r" | ||
338 | #[derive(<|>Copy<|>)] | 393 | #[derive(<|>Copy<|>)] |
339 | enum Foo { | 394 | enum Foo { |
340 | 395 | ||
341 | } | 396 | } |
342 | ", "Clone"); | 397 | ", |
398 | "Clone", | ||
399 | ); | ||
343 | } | 400 | } |
344 | } | 401 | } |
diff --git a/crates/ra_syntax/src/syntax_kinds/mod.rs b/crates/ra_syntax/src/syntax_kinds/mod.rs index 3041e5633..0fcd07cbf 100644 --- a/crates/ra_syntax/src/syntax_kinds/mod.rs +++ b/crates/ra_syntax/src/syntax_kinds/mod.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | mod generated; | 1 | mod generated; |
2 | 2 | ||
3 | use std::fmt; | ||
4 | use crate::SyntaxKind::*; | 3 | use crate::SyntaxKind::*; |
4 | use std::fmt; | ||
5 | 5 | ||
6 | pub use self::generated::SyntaxKind; | 6 | pub use self::generated::SyntaxKind; |
7 | 7 | ||
diff --git a/crates/ra_syntax/src/text_utils.rs b/crates/ra_syntax/src/text_utils.rs index adf26ef30..abda5ec39 100644 --- a/crates/ra_syntax/src/text_utils.rs +++ b/crates/ra_syntax/src/text_utils.rs | |||
@@ -23,4 +23,4 @@ pub fn replace_range(mut text: String, range: TextRange, replace_with: &str) -> | |||
23 | let end = u32::from(range.end()) as usize; | 23 | let end = u32::from(range.end()) as usize; |
24 | text.replace_range(start..end, replace_with); | 24 | text.replace_range(start..end, replace_with); |
25 | text | 25 | text |
26 | } \ No newline at end of file | 26 | } |
diff --git a/crates/ra_syntax/src/utils.rs b/crates/ra_syntax/src/utils.rs index df1f4b372..27248ff32 100644 --- a/crates/ra_syntax/src/utils.rs +++ b/crates/ra_syntax/src/utils.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use std::fmt::Write; | ||
2 | use crate::{ | 1 | use crate::{ |
3 | algo::walk::{walk, WalkEvent}, | 2 | algo::walk::{walk, WalkEvent}, |
4 | SyntaxKind, File, SyntaxNodeRef | 3 | File, SyntaxKind, SyntaxNodeRef, |
5 | }; | 4 | }; |
5 | use std::fmt::Write; | ||
6 | 6 | ||
7 | /// Parse a file and create a string representation of the resulting parse tree. | 7 | /// Parse a file and create a string representation of the resulting parse tree. |
8 | pub fn dump_tree(syntax: SyntaxNodeRef) -> String { | 8 | pub fn dump_tree(syntax: SyntaxNodeRef) -> String { |
@@ -58,9 +58,7 @@ pub(crate) fn validate_block_structure(root: SyntaxNodeRef) { | |||
58 | let mut stack = Vec::new(); | 58 | let mut stack = Vec::new(); |
59 | for node in root.descendants() { | 59 | for node in root.descendants() { |
60 | match node.kind() { | 60 | match node.kind() { |
61 | SyntaxKind::L_CURLY => { | 61 | SyntaxKind::L_CURLY => stack.push(node), |
62 | stack.push(node) | ||
63 | } | ||
64 | SyntaxKind::R_CURLY => { | 62 | SyntaxKind::R_CURLY => { |
65 | if let Some(pair) = stack.pop() { | 63 | if let Some(pair) = stack.pop() { |
66 | assert_eq!( | 64 | assert_eq!( |
diff --git a/crates/ra_syntax/src/yellow/builder.rs b/crates/ra_syntax/src/yellow/builder.rs index 67a1a382b..d64053409 100644 --- a/crates/ra_syntax/src/yellow/builder.rs +++ b/crates/ra_syntax/src/yellow/builder.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | use rowan::GreenNodeBuilder; | ||
2 | use crate::{ | 1 | use crate::{ |
3 | TextUnit, SmolStr, | ||
4 | parser_impl::Sink, | 2 | parser_impl::Sink, |
5 | yellow::{GreenNode, SyntaxError, RaTypes}, | 3 | yellow::{GreenNode, RaTypes, SyntaxError}, |
6 | SyntaxKind, | 4 | SmolStr, SyntaxKind, TextUnit, |
7 | }; | 5 | }; |
6 | use rowan::GreenNodeBuilder; | ||
8 | 7 | ||
9 | pub(crate) struct GreenBuilder { | 8 | pub(crate) struct GreenBuilder { |
10 | errors: Vec<SyntaxError>, | 9 | errors: Vec<SyntaxError>, |
@@ -36,7 +35,10 @@ impl Sink for GreenBuilder { | |||
36 | } | 35 | } |
37 | 36 | ||
38 | fn error(&mut self, message: String, offset: TextUnit) { | 37 | fn error(&mut self, message: String, offset: TextUnit) { |
39 | let error = SyntaxError { msg: message, offset }; | 38 | let error = SyntaxError { |
39 | msg: message, | ||
40 | offset, | ||
41 | }; | ||
40 | self.errors.push(error) | 42 | self.errors.push(error) |
41 | } | 43 | } |
42 | 44 | ||
diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs index ab9bca0f0..b5c9da813 100644 --- a/crates/ra_syntax/src/yellow/mod.rs +++ b/crates/ra_syntax/src/yellow/mod.rs | |||
@@ -1,16 +1,16 @@ | |||
1 | mod builder; | 1 | mod builder; |
2 | mod syntax_text; | 2 | mod syntax_text; |
3 | 3 | ||
4 | use self::syntax_text::SyntaxText; | ||
5 | use crate::{SmolStr, SyntaxKind, TextRange, TextUnit}; | ||
6 | use rowan::Types; | ||
4 | use std::{ | 7 | use std::{ |
5 | fmt, | 8 | fmt, |
6 | hash::{Hash, Hasher}, | 9 | hash::{Hash, Hasher}, |
7 | }; | 10 | }; |
8 | use rowan::Types; | ||
9 | use crate::{SyntaxKind, TextUnit, TextRange, SmolStr}; | ||
10 | use self::syntax_text::SyntaxText; | ||
11 | 11 | ||
12 | pub use rowan::{TreeRoot}; | ||
13 | pub(crate) use self::builder::GreenBuilder; | 12 | pub(crate) use self::builder::GreenBuilder; |
13 | pub use rowan::TreeRoot; | ||
14 | 14 | ||
15 | #[derive(Debug, Clone, Copy)] | 15 | #[derive(Debug, Clone, Copy)] |
16 | pub enum RaTypes {} | 16 | pub enum RaTypes {} |
@@ -31,9 +31,7 @@ pub struct SyntaxError { | |||
31 | } | 31 | } |
32 | 32 | ||
33 | #[derive(Clone, Copy)] | 33 | #[derive(Clone, Copy)] |
34 | pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>( | 34 | pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(::rowan::SyntaxNode<RaTypes, R>); |
35 | ::rowan::SyntaxNode<RaTypes, R>, | ||
36 | ); | ||
37 | pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; | 35 | pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; |
38 | 36 | ||
39 | impl<R1, R2> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> | 37 | impl<R1, R2> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> |
@@ -69,16 +67,16 @@ impl<'a> SyntaxNodeRef<'a> { | |||
69 | pub fn leaf_text(self) -> Option<&'a SmolStr> { | 67 | pub fn leaf_text(self) -> Option<&'a SmolStr> { |
70 | self.0.leaf_text() | 68 | self.0.leaf_text() |
71 | } | 69 | } |
72 | pub fn ancestors(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> { | 70 | pub fn ancestors(self) -> impl Iterator<Item = SyntaxNodeRef<'a>> { |
73 | crate::algo::generate(Some(self), |&node| node.parent()) | 71 | crate::algo::generate(Some(self), |&node| node.parent()) |
74 | } | 72 | } |
75 | pub fn descendants(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> { | 73 | pub fn descendants(self) -> impl Iterator<Item = SyntaxNodeRef<'a>> { |
76 | crate::algo::walk::walk(self).filter_map(|event| match event { | 74 | crate::algo::walk::walk(self).filter_map(|event| match event { |
77 | crate::algo::walk::WalkEvent::Enter(node) => Some(node), | 75 | crate::algo::walk::WalkEvent::Enter(node) => Some(node), |
78 | crate::algo::walk::WalkEvent::Exit(_) => None, | 76 | crate::algo::walk::WalkEvent::Exit(_) => None, |
79 | }) | 77 | }) |
80 | } | 78 | } |
81 | pub fn siblings(self, direction: Direction) -> impl Iterator<Item=SyntaxNodeRef<'a>> { | 79 | pub fn siblings(self, direction: Direction) -> impl Iterator<Item = SyntaxNodeRef<'a>> { |
82 | crate::algo::generate(Some(self), move |&node| match direction { | 80 | crate::algo::generate(Some(self), move |&node| match direction { |
83 | Direction::Next => node.next_sibling(), | 81 | Direction::Next => node.next_sibling(), |
84 | Direction::Prev => node.prev_sibling(), | 82 | Direction::Prev => node.prev_sibling(), |
@@ -142,9 +140,7 @@ impl<R: TreeRoot<RaTypes>> fmt::Debug for SyntaxNode<R> { | |||
142 | } | 140 | } |
143 | 141 | ||
144 | #[derive(Debug)] | 142 | #[derive(Debug)] |
145 | pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>( | 143 | pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>(::rowan::SyntaxNodeChildren<RaTypes, R>); |
146 | ::rowan::SyntaxNodeChildren<RaTypes, R> | ||
147 | ); | ||
148 | 144 | ||
149 | impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> { | 145 | impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> { |
150 | type Item = SyntaxNode<R>; | 146 | type Item = SyntaxNode<R>; |
@@ -154,7 +150,6 @@ impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> { | |||
154 | } | 150 | } |
155 | } | 151 | } |
156 | 152 | ||
157 | |||
158 | fn has_short_text(kind: SyntaxKind) -> bool { | 153 | fn has_short_text(kind: SyntaxKind) -> bool { |
159 | use crate::SyntaxKind::*; | 154 | use crate::SyntaxKind::*; |
160 | match kind { | 155 | match kind { |
diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs index ae33b993d..5395ca90b 100644 --- a/crates/ra_syntax/src/yellow/syntax_text.rs +++ b/crates/ra_syntax/src/yellow/syntax_text.rs | |||
@@ -1,10 +1,8 @@ | |||
1 | use std::{ | 1 | use std::{fmt, ops}; |
2 | fmt, ops, | ||
3 | }; | ||
4 | 2 | ||
5 | use crate::{ | 3 | use crate::{ |
4 | text_utils::{contains_offset_nonstrict, intersect}, | ||
6 | SyntaxNodeRef, TextRange, TextUnit, | 5 | SyntaxNodeRef, TextRange, TextUnit, |
7 | text_utils::{intersect, contains_offset_nonstrict}, | ||
8 | }; | 6 | }; |
9 | 7 | ||
10 | #[derive(Clone)] | 8 | #[derive(Clone)] |
@@ -17,19 +15,17 @@ impl<'a> SyntaxText<'a> { | |||
17 | pub(crate) fn new(node: SyntaxNodeRef<'a>) -> SyntaxText<'a> { | 15 | pub(crate) fn new(node: SyntaxNodeRef<'a>) -> SyntaxText<'a> { |
18 | SyntaxText { | 16 | SyntaxText { |
19 | node, | 17 | node, |
20 | range: node.range() | 18 | range: node.range(), |
21 | } | 19 | } |
22 | } | 20 | } |
23 | pub fn chunks(&self) -> impl Iterator<Item=&'a str> { | 21 | pub fn chunks(&self) -> impl Iterator<Item = &'a str> { |
24 | let range = self.range; | 22 | let range = self.range; |
25 | self.node | 23 | self.node.descendants().filter_map(move |node| { |
26 | .descendants() | 24 | let text = node.leaf_text()?; |
27 | .filter_map(move |node| { | 25 | let range = intersect(range, node.range())?; |
28 | let text = node.leaf_text()?; | 26 | let range = range - node.range().start(); |
29 | let range = intersect(range, node.range())?; | 27 | Some(&text[range]) |
30 | let range = range - node.range().start(); | 28 | }) |
31 | Some(&text[range]) | ||
32 | }) | ||
33 | } | 29 | } |
34 | pub fn push_to(&self, buf: &mut String) { | 30 | pub fn push_to(&self, buf: &mut String) { |
35 | self.chunks().for_each(|it| buf.push_str(it)); | 31 | self.chunks().for_each(|it| buf.push_str(it)); |
@@ -55,11 +51,13 @@ impl<'a> SyntaxText<'a> { | |||
55 | self.range.len() | 51 | self.range.len() |
56 | } | 52 | } |
57 | pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> { | 53 | pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> { |
58 | let range = range.restrict(self.range) | 54 | let range = range.restrict(self.range).unwrap_or_else(|| { |
59 | .unwrap_or_else(|| { | 55 | panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range) |
60 | panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range) | 56 | }); |
61 | }); | 57 | SyntaxText { |
62 | SyntaxText { node: self.node, range } | 58 | node: self.node, |
59 | range, | ||
60 | } | ||
63 | } | 61 | } |
64 | pub fn char_at(&self, offset: TextUnit) -> Option<char> { | 62 | pub fn char_at(&self, offset: TextUnit) -> Option<char> { |
65 | let mut start: TextUnit = 0.into(); | 63 | let mut start: TextUnit = 0.into(); |
diff --git a/crates/ra_syntax/tests/test.rs b/crates/ra_syntax/tests/test.rs index 27380efef..9d1ded093 100644 --- a/crates/ra_syntax/tests/test.rs +++ b/crates/ra_syntax/tests/test.rs | |||
@@ -4,14 +4,14 @@ extern crate test_utils; | |||
4 | extern crate walkdir; | 4 | extern crate walkdir; |
5 | 5 | ||
6 | use std::{ | 6 | use std::{ |
7 | fmt::Write, | ||
7 | fs, | 8 | fs, |
8 | path::{Path, PathBuf}, | 9 | path::{Path, PathBuf}, |
9 | fmt::Write, | ||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use ra_syntax::{ | 12 | use ra_syntax::{ |
13 | utils::{check_fuzz_invariants, dump_tree}, | ||
13 | File, | 14 | File, |
14 | utils::{dump_tree, check_fuzz_invariants}, | ||
15 | }; | 15 | }; |
16 | 16 | ||
17 | #[test] | 17 | #[test] |
@@ -37,7 +37,6 @@ fn parser_fuzz_tests() { | |||
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
40 | |||
41 | /// Read file and normalize newlines. | 40 | /// Read file and normalize newlines. |
42 | /// | 41 | /// |
43 | /// `rustc` seems to always normalize `\r\n` newlines to `\n`: | 42 | /// `rustc` seems to always normalize `\r\n` newlines to `\n`: |
@@ -54,8 +53,8 @@ fn read_text(path: &Path) -> String { | |||
54 | } | 53 | } |
55 | 54 | ||
56 | pub fn dir_tests<F>(paths: &[&str], f: F) | 55 | pub fn dir_tests<F>(paths: &[&str], f: F) |
57 | where | 56 | where |
58 | F: Fn(&str) -> String, | 57 | F: Fn(&str) -> String, |
59 | { | 58 | { |
60 | for (path, input_code) in collect_tests(paths) { | 59 | for (path, input_code) in collect_tests(paths) { |
61 | let parse_tree = f(&input_code); | 60 | let parse_tree = f(&input_code); |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index ee73153f0..dbe2997eb 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -2,9 +2,9 @@ extern crate difference; | |||
2 | extern crate itertools; | 2 | extern crate itertools; |
3 | extern crate text_unit; | 3 | extern crate text_unit; |
4 | 4 | ||
5 | use std::fmt; | ||
6 | use itertools::Itertools; | 5 | use itertools::Itertools; |
7 | use text_unit::{TextUnit, TextRange}; | 6 | use std::fmt; |
7 | use text_unit::{TextRange, TextUnit}; | ||
8 | 8 | ||
9 | pub use self::difference::Changeset as __Changeset; | 9 | pub use self::difference::Changeset as __Changeset; |
10 | 10 | ||
diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs index 9a1b12a16..5d5d372bb 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs | |||
@@ -1,17 +1,17 @@ | |||
1 | extern crate itertools; | 1 | extern crate itertools; |
2 | #[macro_use] | 2 | #[macro_use] |
3 | extern crate failure; | 3 | extern crate failure; |
4 | extern crate heck; | ||
4 | extern crate ron; | 5 | extern crate ron; |
5 | extern crate tera; | 6 | extern crate tera; |
6 | extern crate heck; | ||
7 | 7 | ||
8 | use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; | ||
9 | use itertools::Itertools; | ||
8 | use std::{ | 10 | use std::{ |
9 | collections::HashMap, | 11 | collections::HashMap, |
10 | fs, | 12 | fs, |
11 | path::{Path, PathBuf}, | 13 | path::{Path, PathBuf}, |
12 | }; | 14 | }; |
13 | use itertools::Itertools; | ||
14 | use heck::{CamelCase, ShoutySnakeCase, SnakeCase}; | ||
15 | 15 | ||
16 | pub type Result<T> = ::std::result::Result<T, failure::Error>; | 16 | pub type Result<T> = ::std::result::Result<T, failure::Error>; |
17 | 17 | ||
@@ -61,7 +61,6 @@ pub fn collect_tests(s: &str) -> Vec<(usize, Test)> { | |||
61 | res | 61 | res |
62 | } | 62 | } |
63 | 63 | ||
64 | |||
65 | pub fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { | 64 | pub fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { |
66 | match fs::read_to_string(path) { | 65 | match fs::read_to_string(path) { |
67 | Ok(ref old_contents) if old_contents == contents => { | 66 | Ok(ref old_contents) if old_contents == contents => { |
@@ -116,5 +115,8 @@ pub fn render_template(template: &Path) -> Result<String> { | |||
116 | } | 115 | } |
117 | 116 | ||
118 | pub fn project_root() -> PathBuf { | 117 | pub fn project_root() -> PathBuf { |
119 | Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap()).parent().unwrap().to_path_buf() | 118 | Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap()) |
119 | .parent() | ||
120 | .unwrap() | ||
121 | .to_path_buf() | ||
120 | } | 122 | } |
diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs index 6eacfc190..b662d78df 100644 --- a/crates/tools/src/main.rs +++ b/crates/tools/src/main.rs | |||
@@ -11,7 +11,10 @@ use std::{ | |||
11 | path::{Path, PathBuf}, | 11 | path::{Path, PathBuf}, |
12 | process::Command, | 12 | process::Command, |
13 | }; | 13 | }; |
14 | use tools::{AST, AST_TEMPLATE, Result, SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, Test, collect_tests, render_template, update, project_root}; | 14 | use tools::{ |
15 | collect_tests, project_root, render_template, update, Result, Test, AST, AST_TEMPLATE, | ||
16 | SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, | ||
17 | }; | ||
15 | 18 | ||
16 | const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar"; | 19 | const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar"; |
17 | const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline"; | 20 | const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline"; |
@@ -40,18 +43,23 @@ fn main() -> Result<()> { | |||
40 | fn run_gen_command(name: &str, verify: bool) -> Result<()> { | 43 | fn run_gen_command(name: &str, verify: bool) -> Result<()> { |
41 | match name { | 44 | match name { |
42 | "gen-kinds" => { | 45 | "gen-kinds" => { |
43 | update(&project_root().join(SYNTAX_KINDS), &render_template(&project_root().join(SYNTAX_KINDS_TEMPLATE))?, verify)?; | 46 | update( |
44 | update(&project_root().join(AST), &render_template(&project_root().join(AST_TEMPLATE))?, verify)?; | 47 | &project_root().join(SYNTAX_KINDS), |
45 | }, | 48 | &render_template(&project_root().join(SYNTAX_KINDS_TEMPLATE))?, |
46 | "gen-tests" => { | 49 | verify, |
47 | gen_tests(verify)? | 50 | )?; |
48 | }, | 51 | update( |
52 | &project_root().join(AST), | ||
53 | &render_template(&project_root().join(AST_TEMPLATE))?, | ||
54 | verify, | ||
55 | )?; | ||
56 | } | ||
57 | "gen-tests" => gen_tests(verify)?, | ||
49 | _ => unreachable!(), | 58 | _ => unreachable!(), |
50 | } | 59 | } |
51 | Ok(()) | 60 | Ok(()) |
52 | } | 61 | } |
53 | 62 | ||
54 | |||
55 | fn gen_tests(verify: bool) -> Result<()> { | 63 | fn gen_tests(verify: bool) -> Result<()> { |
56 | let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?; | 64 | let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?; |
57 | 65 | ||
@@ -133,11 +141,20 @@ fn install_code_extension() -> Result<()> { | |||
133 | } else { | 141 | } else { |
134 | run(r"npm install", "./editors/code")?; | 142 | run(r"npm install", "./editors/code")?; |
135 | } | 143 | } |
136 | run(r"node ./node_modules/vsce/out/vsce package", "./editors/code")?; | 144 | run( |
145 | r"node ./node_modules/vsce/out/vsce package", | ||
146 | "./editors/code", | ||
147 | )?; | ||
137 | if cfg!(windows) { | 148 | if cfg!(windows) { |
138 | run(r"cmd.exe /c code.cmd --install-extension ./ra-lsp-0.0.1.vsix", "./editors/code")?; | 149 | run( |
150 | r"cmd.exe /c code.cmd --install-extension ./ra-lsp-0.0.1.vsix", | ||
151 | "./editors/code", | ||
152 | )?; | ||
139 | } else { | 153 | } else { |
140 | run(r"code --install-extension ./ra-lsp-0.0.1.vsix", "./editors/code")?; | 154 | run( |
155 | r"code --install-extension ./ra-lsp-0.0.1.vsix", | ||
156 | "./editors/code", | ||
157 | )?; | ||
141 | } | 158 | } |
142 | Ok(()) | 159 | Ok(()) |
143 | } | 160 | } |
@@ -145,7 +162,11 @@ fn install_code_extension() -> Result<()> { | |||
145 | fn run(cmdline: &'static str, dir: &str) -> Result<()> { | 162 | fn run(cmdline: &'static str, dir: &str) -> Result<()> { |
146 | eprintln!("\nwill run: {}", cmdline); | 163 | eprintln!("\nwill run: {}", cmdline); |
147 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); | 164 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); |
148 | let project_dir = Path::new(manifest_dir).ancestors().nth(2).unwrap().join(dir); | 165 | let project_dir = Path::new(manifest_dir) |
166 | .ancestors() | ||
167 | .nth(2) | ||
168 | .unwrap() | ||
169 | .join(dir); | ||
149 | let mut args = cmdline.split_whitespace(); | 170 | let mut args = cmdline.split_whitespace(); |
150 | let exec = args.next().unwrap(); | 171 | let exec = args.next().unwrap(); |
151 | let status = Command::new(exec) | 172 | let status = Command::new(exec) |
diff --git a/crates/tools/tests/cli.rs b/crates/tools/tests/cli.rs index f507d80a2..16899bb5f 100644 --- a/crates/tools/tests/cli.rs +++ b/crates/tools/tests/cli.rs | |||
@@ -1,13 +1,23 @@ | |||
1 | extern crate tools; | 1 | extern crate tools; |
2 | 2 | ||
3 | use tools::{AST, AST_TEMPLATE, SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, render_template, update, project_root}; | 3 | use tools::{ |
4 | project_root, render_template, update, AST, AST_TEMPLATE, SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, | ||
5 | }; | ||
4 | 6 | ||
5 | #[test] | 7 | #[test] |
6 | fn verify_template_generation() { | 8 | fn verify_template_generation() { |
7 | if let Err(error) = update(&project_root().join(SYNTAX_KINDS), &render_template(&project_root().join(SYNTAX_KINDS_TEMPLATE)).unwrap(), true) { | 9 | if let Err(error) = update( |
10 | &project_root().join(SYNTAX_KINDS), | ||
11 | &render_template(&project_root().join(SYNTAX_KINDS_TEMPLATE)).unwrap(), | ||
12 | true, | ||
13 | ) { | ||
8 | panic!("{}. Please update it by running `cargo gen-kinds`", error); | 14 | panic!("{}. Please update it by running `cargo gen-kinds`", error); |
9 | } | 15 | } |
10 | if let Err(error) = update(&project_root().join(AST), &render_template(&project_root().join(AST_TEMPLATE)).unwrap(), true) { | 16 | if let Err(error) = update( |
17 | &project_root().join(AST), | ||
18 | &render_template(&project_root().join(AST_TEMPLATE)).unwrap(), | ||
19 | true, | ||
20 | ) { | ||
11 | panic!("{}. Please update it by running `cargo gen-kinds`", error); | 21 | panic!("{}. Please update it by running `cargo gen-kinds`", error); |
12 | } | 22 | } |
13 | } | 23 | } |