aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy A. Kolb <[email protected]>2018-10-15 22:44:23 +0100
committerJeremy A. Kolb <[email protected]>2018-10-16 14:41:10 +0100
commit61f3a438d3a729a6be941bca1ff4c6a97a33f221 (patch)
tree6551967cc8c6e921b66071453ad7888a9121d326
parent39cb6c6d3f78b193f5873c3492e530bbd24d5dd2 (diff)
Cargo Format
Run `cargo fmt` and ignore generated files
-rw-r--r--crates/gen_lsp_server/src/lib.rs35
-rw-r--r--crates/gen_lsp_server/src/msg.rs29
-rw-r--r--crates/gen_lsp_server/src/stdio.rs6
-rw-r--r--crates/ra_analysis/src/db.rs21
-rw-r--r--crates/ra_analysis/src/descriptors.rs108
-rw-r--r--crates/ra_analysis/src/imp.rs207
-rw-r--r--crates/ra_analysis/src/job.rs14
-rw-r--r--crates/ra_analysis/src/lib.rs78
-rw-r--r--crates/ra_analysis/src/module_map.rs13
-rw-r--r--crates/ra_analysis/src/roots.rs63
-rw-r--r--crates/ra_analysis/src/symbol_index.rs29
-rw-r--r--crates/ra_analysis/tests/tests.rs82
-rw-r--r--crates/ra_cli/src/main.rs27
-rw-r--r--crates/ra_editor/src/code_actions.rs49
-rw-r--r--crates/ra_editor/src/completion.rs178
-rw-r--r--crates/ra_editor/src/edit.rs13
-rw-r--r--crates/ra_editor/src/extend_selection.rs58
-rw-r--r--crates/ra_editor/src/folding_ranges.rs36
-rw-r--r--crates/ra_editor/src/lib.rs103
-rw-r--r--crates/ra_editor/src/line_index.rs119
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs150
-rw-r--r--crates/ra_editor/src/scope/mod.rs3
-rw-r--r--crates/ra_editor/src/scope/mod_scope.rs47
-rw-r--r--crates/ra_editor/src/symbols.rs34
-rw-r--r--crates/ra_editor/src/test_utils.rs12
-rw-r--r--crates/ra_editor/src/typing.rs205
-rw-r--r--crates/ra_lsp_server/src/caps.rs16
-rw-r--r--crates/ra_lsp_server/src/conv.rs66
-rw-r--r--crates/ra_lsp_server/src/lib.rs21
-rw-r--r--crates/ra_lsp_server/src/main.rs6
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs206
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs161
-rw-r--r--crates/ra_lsp_server/src/main_loop/subscriptions.rs6
-rw-r--r--crates/ra_lsp_server/src/path_map.rs28
-rw-r--r--crates/ra_lsp_server/src/project_model.rs32
-rw-r--r--crates/ra_lsp_server/src/req.rs27
-rw-r--r--crates/ra_lsp_server/src/server_world.rs76
-rw-r--r--crates/ra_lsp_server/src/thread_watcher.rs19
-rw-r--r--crates/ra_lsp_server/src/vfs.rs12
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs23
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs78
-rw-r--r--crates/ra_syntax/src/algo/mod.rs54
-rw-r--r--crates/ra_syntax/src/algo/visit.rs63
-rw-r--r--crates/ra_syntax/src/algo/walk.rs6
-rw-r--r--crates/ra_syntax/src/ast/generated.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs.tera2
-rw-r--r--crates/ra_syntax/src/ast/mod.rs24
-rw-r--r--crates/ra_syntax/src/grammar/expressions/atom.rs58
-rw-r--r--crates/ra_syntax/src/grammar/expressions/mod.rs53
-rw-r--r--crates/ra_syntax/src/grammar/items/mod.rs45
-rw-r--r--crates/ra_syntax/src/grammar/items/traits.rs1
-rw-r--r--crates/ra_syntax/src/grammar/mod.rs31
-rw-r--r--crates/ra_syntax/src/grammar/params.rs13
-rw-r--r--crates/ra_syntax/src/grammar/paths.rs2
-rw-r--r--crates/ra_syntax/src/grammar/patterns.rs22
-rw-r--r--crates/ra_syntax/src/grammar/type_params.rs11
-rw-r--r--crates/ra_syntax/src/grammar/types.rs18
-rw-r--r--crates/ra_syntax/src/lexer/mod.rs16
-rw-r--r--crates/ra_syntax/src/lexer/ptr.rs8
-rw-r--r--crates/ra_syntax/src/lexer/strings.rs4
-rw-r--r--crates/ra_syntax/src/lib.rs34
-rw-r--r--crates/ra_syntax/src/parser_api.rs8
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs54
-rw-r--r--crates/ra_syntax/src/parser_impl/mod.rs13
-rw-r--r--crates/ra_syntax/src/reparsing.rs247
-rw-r--r--crates/ra_syntax/src/syntax_kinds/mod.rs2
-rw-r--r--crates/ra_syntax/src/text_utils.rs2
-rw-r--r--crates/ra_syntax/src/utils.rs8
-rw-r--r--crates/ra_syntax/src/yellow/builder.rs12
-rw-r--r--crates/ra_syntax/src/yellow/mod.rs23
-rw-r--r--crates/ra_syntax/src/yellow/syntax_text.rs36
-rw-r--r--crates/ra_syntax/tests/test.rs9
-rw-r--r--crates/test_utils/src/lib.rs4
-rw-r--r--crates/tools/src/lib.rs12
-rw-r--r--crates/tools/src/main.rs45
-rw-r--r--crates/tools/tests/cli.rs16
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]
64extern crate failure; 63extern crate failure;
65#[macro_use] 64#[macro_use]
@@ -74,16 +73,16 @@ extern crate languageserver_types;
74mod msg; 73mod msg;
75mod stdio; 74mod stdio;
76 75
77use crossbeam_channel::{Sender, Receiver}; 76use crossbeam_channel::{Receiver, Sender};
78use languageserver_types::{ 77use 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
84pub type Result<T> = ::std::result::Result<T, failure::Error>; 83pub type Result<T> = ::std::result::Result<T, failure::Error>;
85pub use { 84pub 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 @@
1use std::io::{BufRead, Write}; 1use std::io::{BufRead, Write};
2 2
3use serde_json::{Value, from_str, to_string, from_value, to_value}; 3use languageserver_types::{notification::Notification, request::Request};
4use serde::{Serialize, de::DeserializeOwned}; 4use serde::{de::DeserializeOwned, Serialize};
5use languageserver_types::{ 5use serde_json::{from_str, from_value, to_string, to_value, Value};
6 request::Request,
7 notification::Notification,
8};
9 6
10use Result; 7use 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
116impl RawResponse { 116impl 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 @@
1use std::{ 1use std::{
2 io::{stdin, stdout},
2 thread, 3 thread,
3 io::{
4 stdout, stdin,
5 },
6}; 4};
7 5
8use crossbeam_channel::{Receiver, Sender, bounded}; 6use crossbeam_channel::{bounded, Receiver, Sender};
9 7
10use {RawMessage, Result}; 8use {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 @@
1use std::{
2 fmt,
3 sync::Arc,
4 hash::{Hash, Hasher},
5};
6use salsa;
7use rustc_hash::FxHashSet;
8use ra_syntax::File;
9use ra_editor::{LineIndex};
10use crate::{ 1use 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};
6use ra_editor::LineIndex;
7use ra_syntax::File;
8use rustc_hash::FxHashSet;
9use salsa;
10
11use std::{
12 fmt,
13 hash::{Hash, Hasher},
14 sync::Arc,
15};
15 16
16#[derive(Default)] 17#[derive(Default)]
17pub(crate) struct RootDatabase { 18pub(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 @@
1use std::{ 1use crate::{imp::FileResolverImp, FileId};
2 collections::BTreeMap,
3};
4use relative_path::RelativePathBuf;
5use ra_syntax::{ 2use 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};
10use crate::{
11 FileId,
12 imp::FileResolverImp,
13}; 6};
7use relative_path::RelativePathBuf;
8
9use std::collections::BTreeMap;
14 10
15#[derive(Debug, PartialEq, Eq, Hash)] 11#[derive(Debug, PartialEq, Eq, Hash)]
16pub struct ModuleDescriptor { 12pub struct ModuleDescriptor {
17 pub submodules: Vec<Submodule> 13 pub submodules: Vec<Submodule>,
18} 14}
19 15
20impl ModuleDescriptor { 16impl 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
29fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item=(SmolStr, ast::Module<'a>)> { 24fn 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);
56struct NodeData { 49struct 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)]
74pub enum Problem { 66pub 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
84impl ModuleTreeDescriptor { 76impl 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
189fn resolve_submodule( 193fn 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)]
224pub struct FnDescriptor { 228pub 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 @@
1use std::{ 1use 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
11use relative_path::RelativePath; 9use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit};
12use rustc_hash::FxHashSet;
13use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name};
14use ra_syntax::{ 10use 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};
16use relative_path::RelativePath;
17use rustc_hash::FxHashSet;
19 18
20use crate::{ 19use 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)]
28pub(crate) struct FileResolverImp { 27pub(crate) struct FileResolverImp {
29 inner: Arc<FileResolver> 28 inner: Arc<FileResolver>,
30} 29}
31 30
32impl PartialEq for FileResolverImp { 31impl PartialEq for FileResolverImp {
@@ -35,8 +34,7 @@ impl PartialEq for FileResolverImp {
35 } 34 }
36} 35}
37 36
38impl Eq for FileResolverImp { 37impl Eq for FileResolverImp {}
39}
40 38
41impl Hash for FileResolverImp { 39impl 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)]
79pub(crate) struct AnalysisHostImpl { 83pub(crate) struct AnalysisHostImpl {
80 data: WorldData 84 data: WorldData,
81} 85}
82 86
83impl AnalysisHostImpl { 87impl 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
416impl CrateGraph { 458impl 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
425enum FnCallNode<'a> { 468enum 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
430impl<'a> FnCallNode<'a> { 473impl<'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
28impl JobToken { 33impl 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 @@
1extern crate parking_lot; 1extern crate parking_lot;
2#[macro_use] 2#[macro_use]
3extern crate log; 3extern crate log;
4extern crate fst;
4extern crate once_cell; 5extern crate once_cell;
5extern crate ra_syntax;
6extern crate ra_editor; 6extern crate ra_editor;
7extern crate fst; 7extern crate ra_syntax;
8extern crate rayon; 8extern crate rayon;
9extern crate relative_path; 9extern crate relative_path;
10#[macro_use] 10#[macro_use]
11extern crate crossbeam_channel; 11extern crate crossbeam_channel;
12extern crate im; 12extern crate im;
13extern crate salsa;
14extern crate rustc_hash; 13extern crate rustc_hash;
14extern crate salsa;
15 15
16mod symbol_index; 16mod db;
17mod module_map; 17mod descriptors;
18mod imp; 18mod imp;
19mod job; 19mod job;
20mod module_map;
20mod roots; 21mod roots;
21mod db; 22mod symbol_index;
22mod descriptors;
23 23
24use std::{ 24use std::{fmt::Debug, sync::Arc};
25 sync::Arc,
26 fmt::Debug,
27};
28 25
26use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp};
27use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
29use relative_path::{RelativePath, RelativePathBuf}; 28use relative_path::{RelativePath, RelativePathBuf};
30use ra_syntax::{File, TextRange, TextUnit, AtomEdit};
31use rustc_hash::FxHashMap; 29use rustc_hash::FxHashMap;
32use crate::imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
33 30
34pub use ra_editor::{
35 StructureNode, LineIndex, FileSymbol,
36 Runnable, RunnableKind, HighlightedRange, CompletionItem,
37 Fold, FoldKind
38};
39pub use crate::{ 31pub use crate::{
40 job::{JobToken, JobHandle},
41 descriptors::FnDescriptor, 32 descriptors::FnDescriptor,
33 job::{JobHandle, JobToken},
34};
35pub 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)]
61pub struct AnalysisHost { 57pub struct AnalysisHost {
62 imp: AnalysisHostImpl 58 imp: AnalysisHostImpl,
63} 59}
64 60
65impl AnalysisHost { 61impl 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)]
165pub struct Analysis { 165pub struct Analysis {
166 imp: AnalysisImpl 166 imp: AnalysisImpl,
167} 167}
168 168
169impl Analysis { 169impl 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)]
249pub struct LibraryData { 263pub struct LibraryData {
250 root: roots::ReadonlySourceRoot 264 root: roots::ReadonlySourceRoot,
251} 265}
252 266
253impl LibraryData { 267impl 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 @@
1use std::sync::Arc;
2use crate::{ 1use crate::{
3 FileId, 2 db::SyntaxDatabase,
4 db::{SyntaxDatabase},
5 descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, 3 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
4 FileId,
6}; 5};
7 6
7use std::sync::Arc;
8
8salsa::query_group! { 9salsa::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
20fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { 20fn 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 @@
1use std::{ 1use std::{panic, sync::Arc};
2 sync::Arc,
3 panic,
4};
5 2
6use once_cell::sync::OnceCell; 3use once_cell::sync::OnceCell;
7use rayon::prelude::*;
8use salsa::Database;
9use rustc_hash::{FxHashMap, FxHashSet};
10use ra_editor::LineIndex; 4use ra_editor::LineIndex;
11use ra_syntax::File; 5use ra_syntax::File;
6use rayon::prelude::*;
7use rustc_hash::{FxHashMap, FxHashSet};
8use salsa::Database;
12 9
13use crate::{ 10use 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
22pub(crate) trait SourceRoot { 19pub(crate) trait SourceRoot {
@@ -35,7 +32,7 @@ pub(crate) struct WritableSourceRoot {
35impl WritableSourceRoot { 32impl 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
133impl ReadonlySourceRoot { 131impl 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 @@
1use std::{ 1use crate::{FileId, JobToken, Query};
2 sync::Arc, 2use fst::{self, Streamer};
3 hash::{Hash, Hasher}, 3use ra_editor::{file_symbols, FileSymbol};
4};
5use ra_editor::{FileSymbol, file_symbols};
6use ra_syntax::{ 4use ra_syntax::{
7 File, 5 File,
8 SyntaxKind::{self, *}, 6 SyntaxKind::{self, *},
9}; 7};
10use fst::{self, Streamer};
11use rayon::prelude::*; 8use rayon::prelude::*;
12use crate::{Query, FileId, JobToken}; 9
10use std::{
11 hash::{Hash, Hasher},
12 sync::Arc,
13};
13 14
14#[derive(Debug)] 15#[derive(Debug)]
15pub(crate) struct SymbolIndex { 16pub(crate) struct SymbolIndex {
@@ -23,8 +24,7 @@ impl PartialEq for SymbolIndex {
23 } 24 }
24} 25}
25 26
26impl Eq for SymbolIndex { 27impl Eq for SymbolIndex {}
27}
28 28
29impl Hash for SymbolIndex { 29impl 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
35impl SymbolIndex { 35impl 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 @@
1extern crate relative_path;
2extern crate ra_analysis; 1extern crate ra_analysis;
3extern crate rustc_hash;
4extern crate ra_editor; 2extern crate ra_editor;
5extern crate ra_syntax; 3extern crate ra_syntax;
4extern crate relative_path;
5extern crate rustc_hash;
6extern crate test_utils; 6extern crate test_utils;
7 7
8use std::{ 8use std::sync::Arc;
9 sync::Arc,
10};
11 9
12use rustc_hash::FxHashMap; 10use ra_analysis::{
11 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle,
12};
13use relative_path::{RelativePath, RelativePathBuf}; 13use relative_path::{RelativePath, RelativePathBuf};
14use ra_analysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId, FnDescriptor}; 14use rustc_hash::FxHashMap;
15use test_utils::{assert_eq_dbg, extract_offset}; 15use test_utils::{assert_eq_dbg, extract_offset};
16 16
17#[derive(Debug)] 17#[derive(Debug)]
18struct FileMap(Vec<(FileId, RelativePathBuf)>); 18struct FileMap(Vec<(FileId, RelativePathBuf)>);
19 19
20impl FileMap { 20impl 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]
73fn test_resolve_module() { 72fn 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() {
114fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 107fn 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]
124fn test_resolve_parent_module() { 114fn 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]
137fn test_resolve_crate_root() { 124fn 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]
162fn test_fn_signature_two_args_first() { 143fn test_fn_signature_two_args_first() {
163 let (desc, param) = get_signature( 144 let (desc, param) = get_signature(
164r#"fn foo(x: u32, y: u32) -> u32 {x + y} 145 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
165fn bar() { foo(<|>3, ); }"#); 146fn 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, ); }"#);
174fn test_fn_signature_two_args_second() { 156fn 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}
177fn bar() { foo(3, <|>); }"#); 159fn 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]
186fn test_fn_signature_for_impl() { 169fn test_fn_signature_for_impl() {
187 let (desc, param) = get_signature( 170 let (desc, param) = get_signature(
188r#"struct F; impl F { pub fn new() { F{}} } 171 r#"struct F; impl F { pub fn new() { F{}} }
189fn bar() {let _ : F = F::new(<|>);}"#); 172fn 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]
198fn test_fn_signature_for_method_self() { 182fn test_fn_signature_for_method_self() {
199 let (desc, param) = get_signature( 183 let (desc, param) = get_signature(
200r#"struct F; 184 r#"struct F;
201impl F { 185impl F {
202 pub fn new() -> F{ 186 pub fn new() -> F{
203 F{} 187 F{}
@@ -209,7 +193,8 @@ impl F {
209fn bar() { 193fn 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]
221fn test_fn_signature_for_method_with_arg() { 206fn test_fn_signature_for_method_with_arg() {
222 let (desc, param) = get_signature( 207 let (desc, param) = get_signature(
223r#"struct F; 208 r#"struct F;
224impl F { 209impl F {
225 pub fn new() -> F{ 210 pub fn new() -> F{
226 F{} 211 F{}
@@ -232,7 +217,8 @@ impl F {
232fn bar() { 217fn 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]
3extern crate failure; 3extern crate failure;
4extern crate join_to_string; 4extern crate join_to_string;
5extern crate ra_syntax;
6extern crate ra_editor; 5extern crate ra_editor;
6extern crate ra_syntax;
7extern crate tools; 7extern crate tools;
8 8
9use std::{ 9use std::{fs, io::Read, path::Path, time::Instant};
10 fs, io::Read, path::Path, 10
11 time::Instant
12};
13use clap::{App, Arg, SubCommand}; 11use clap::{App, Arg, SubCommand};
14use join_to_string::join; 12use join_to_string::join;
13use ra_editor::{extend_selection, file_structure, syntax_tree};
14use ra_syntax::{File, TextRange};
15use tools::collect_tests; 15use tools::collect_tests;
16use ra_syntax::{TextRange, File};
17use ra_editor::{syntax_tree, file_structure, extend_selection};
18 16
19type Result<T> = ::std::result::Result<T, failure::Error>; 17type 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 @@
1use join_to_string::join; 1use join_to_string::join;
2 2
3use ra_syntax::{ 3use 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
14use crate::{EditBuilder, Edit, find_node_at_offset}; 11use crate::{find_node_at_offset, Edit, EditBuilder};
15 12
16#[derive(Debug)] 13#[derive(Debug)]
17pub struct LocalEdit { 14pub 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
100pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl FnOnce() -> LocalEdit + 'a> { 100pub 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 "
192fn foo() { 199fn foo() {
193 foo(<|>1 + 1<|>); 200 foo(<|>1 + 1<|>);
194}", " 201}",
202 "
195fn foo() { 203fn 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() {
204check_action_range( 212 check_action_range(
205 " 213 "
206fn foo() { 214fn foo() {
207 <|>1 + 1<|>; 215 <|>1 + 1<|>;
208}", " 216}",
217 "
209fn foo() { 218fn 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 @@
1use rustc_hash::{FxHashMap, FxHashSet}; 1use rustc_hash::{FxHashMap, FxHashSet};
2 2
3use ra_syntax::{ 3use 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
12use crate::{ 12use 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
27pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> { 28pub 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 153fn complete_expr_keywords(
138fn 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
210fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) { 235fn 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
225fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { 248fn 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
234fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { 256fn 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 @@
1use crate::{TextRange, TextUnit}; 1use crate::{TextRange, TextUnit};
2use ra_syntax::{ 2use 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)]
8pub struct Edit { 5pub struct Edit {
@@ -11,7 +8,7 @@ pub struct Edit {
11 8
12#[derive(Debug)] 9#[derive(Debug)]
13pub struct EditBuilder { 10pub struct EditBuilder {
14 atoms: Vec<AtomEdit> 11 atoms: Vec<AtomEdit>,
15} 12}
16 13
17impl EditBuilder { 14impl 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 @@
1use ra_syntax::{ 1use 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
7pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { 8pub 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#"
192fn main() { foo<|>+bar;} 190fn 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#"
198fn main() { foo+<|>bar;} 196fn 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#"
223impl S { 213impl 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 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ 3use 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
56fn has_newline( 61fn 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 @@
1extern crate ra_syntax;
2extern crate superslice;
3extern crate itertools; 1extern crate itertools;
4extern crate join_to_string; 2extern crate join_to_string;
3extern crate ra_syntax;
5extern crate rustc_hash; 4extern crate rustc_hash;
5extern crate superslice;
6#[cfg(test)] 6#[cfg(test)]
7#[macro_use] 7#[macro_use]
8extern crate test_utils as _test_utils; 8extern crate test_utils as _test_utils;
9 9
10mod extend_selection;
11mod symbols;
12mod line_index;
13mod edit;
14mod folding_ranges;
15mod code_actions; 10mod code_actions;
16mod typing;
17mod completion; 11mod completion;
12mod edit;
13mod extend_selection;
14mod folding_ranges;
15mod line_index;
18mod scope; 16mod scope;
17mod symbols;
19#[cfg(test)] 18#[cfg(test)]
20mod test_utils; 19mod test_utils;
20mod typing;
21 21
22pub 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};
32pub use ra_syntax::AtomEdit;
22use ra_syntax::{ 33use 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,
28pub use ra_syntax::AtomEdit;
29pub 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
68pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { 65pub 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
110pub fn diagnostics(file: &File) -> Vec<Diagnostic> { 105pub 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
117pub fn syntax_tree(file: &File) -> String { 115pub fn syntax_tree(file: &File) -> String {
@@ -119,7 +117,8 @@ pub fn syntax_tree(file: &File) -> String {
119} 117}
120 118
121pub fn runnables(file: &File) -> Vec<Runnable> { 119pub 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
156pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef) -> Option<(SmolStr, TextRange)> { 154pub 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)]
165mod tests { 167mod 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
173fn main() {} 176fn 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#"
191fn main() {} 196fn main() {}
192 197
193#[test] 198#[test]
@@ -196,7 +201,8 @@ fn test_foo() {}
196#[test] 201#[test]
197#[ignore] 202#[ignore]
198fn test_foo() {} 203fn 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 @@
1use superslice::Ext;
2use crate::TextUnit; 1use crate::TextUnit;
2use superslice::Ext;
3 3
4#[derive(Clone, Debug, Hash, PartialEq, Eq)] 4#[derive(Clone, Debug, Hash, PartialEq, Eq)]
5pub struct LineIndex { 5pub 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 {
42fn test_line_index() { 45fn 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 @@
1use std::fmt; 1use std::fmt;
2
2use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
3 4
4use ra_syntax::{ 5use 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
10type ScopeId = usize; 11type ScopeId = usize;
@@ -19,11 +20,12 @@ pub struct FnScopes {
19impl FnScopes { 20impl 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
73pub struct ScopeEntry { 86pub struct ScopeEntry {
74 syntax: SyntaxNode 87 syntax: SyntaxNode,
75} 88}
76 89
77impl ScopeEntry { 90impl 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
96impl fmt::Debug for ScopeEntry { 108impl 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
132fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { 144fn 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)]
237struct ScopeData { 255struct ScopeData {
238 parent: Option<ScopeId>, 256 parent: Option<ScopeId>,
239 entries: Vec<ScopeEntry> 257 entries: Vec<ScopeEntry>,
240} 258}
241 259
242pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> Option<&'a ScopeEntry> { 260pub 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)]
256mod tests { 278mod 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;
2mod mod_scope; 2mod mod_scope;
3 3
4pub use self::{ 4pub 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 @@
1use ra_syntax::{ 1use ra_syntax::{
2 AstNode, SyntaxNode, SyntaxNodeRef, SmolStr,
3 ast::{self, AstChildren}, 2 ast::{self, AstChildren},
3 AstNode, SmolStr, SyntaxNode, SyntaxNodeRef,
4}; 4};
5 5
6pub struct ModuleScope { 6pub struct ModuleScope {
@@ -13,7 +13,8 @@ pub struct Entry {
13} 13}
14 14
15enum EntryKind { 15enum EntryKind {
16 Item, Import, 16 Item,
17 Import,
17} 18}
18 19
19impl ModuleScope { 20impl 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 {
52impl Entry { 52impl 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
76fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) { 78fn 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)]
87mod tests { 90mod 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 @@
1use crate::TextRange;
2
1use ra_syntax::{ 3use 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};
9use crate::TextRange;
10 11
11#[derive(Debug, Clone)] 12#[derive(Debug, Clone)]
12pub struct StructureNode { 13pub struct StructureNode {
@@ -25,9 +26,7 @@ pub struct FileSymbol {
25} 26}
26 27
27pub fn file_symbols(file: &File) -> Vec<FileSymbol> { 28pub 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
33fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { 32fn 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
55pub fn file_structure(file: &File) -> Vec<StructureNode> { 53pub 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#"
135struct Foo { 132struct Foo {
136 x: i32 133 x: i32
137} 134}
@@ -148,7 +145,8 @@ const C: i32 = 92;
148impl E {} 145impl E {}
149 146
150impl fmt::Debug for E {} 147impl 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 @@
1use ra_syntax::{File, TextUnit, TextRange};
2pub use crate::_test_utils::*;
3use crate::LocalEdit; 1use crate::LocalEdit;
2pub use crate::_test_utils::*;
3use ra_syntax::{File, TextRange, TextUnit};
4 4
5pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> ( 5pub 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
22pub fn check_action_range<F: Fn(&File, TextRange) -> Option<LocalEdit>> ( 18pub 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 @@
1use std::mem; 1use std::mem;
2 2
3use ra_syntax::{ 3use 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
13use crate::{LocalEdit, EditBuilder, find_node_at_offset}; 12use crate::{find_node_at_offset, EditBuilder, LocalEdit};
14 13
15pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { 14pub 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
60pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> { 58pub 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
128fn remove_newline( 133fn 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
190fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { 187fn 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
197fn join_single_expr_block( 194fn 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)]
245mod tests { 239mod 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"
260fn foo() { 255fn foo() {
261 <|>foo(1, 256 <|>foo(1,
262 ) 257 )
263} 258}
264", r" 259",
260 r"
265fn foo() { 261fn 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"
274pub fn reparse(&self, edit: &AtomEdit) -> File { 272pub 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"
280pub fn reparse(&self, edit: &AtomEdit) -> File { 279pub 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"
289fn foo() { 290fn foo() {
290 foo(<|>{ 291 foo(<|>{
291 92 292 92
292 }) 293 })
293}", r" 294}",
295 r"
294fn foo() { 296fn 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"
302fn foo() { 306fn foo() {
303 // Hello<|> 307 // Hello<|>
304 // world! 308 // world!
305} 309}
306", r" 310",
311 r"
307fn foo() { 312fn 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"
316fn foo() { 323fn foo() {
317 /// Hello<|> 324 /// Hello<|>
318 /// world! 325 /// world!
319} 326}
320", r" 327",
328 r"
321fn foo() { 329fn 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"
330fn foo() { 340fn foo() {
331 //! Hello<|> 341 //! Hello<|>
332 //! world! 342 //! world!
333} 343}
334", r" 344",
345 r"
335fn foo() { 346fn 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"
344fn foo() { 357fn foo() {
345 // Hello<|> 358 // Hello<|>
346 /* world! */ 359 /* world! */
347} 360}
348", r" 361",
362 r"
349fn foo() { 363fn 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"
358fn foo() { 374fn foo() {
359 // The<|> 375 // The<|>
360 /* quick 376 /* quick
361 brown 377 brown
362 fox! */ 378 fox! */
363} 379}
364", r" 380",
381 r"
365fn foo() { 382fn 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"
384fn foo() { 403fn foo() {
385 <|>foo(1, 404 <|>foo(1,
386 2, 405 2,
387 3, 406 3,
388 <|>) 407 <|>)
389} 408}
390 ", r" 409 ",
410 r"
391fn foo() { 411fn 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"
400struct Foo <|>{ 422struct Foo <|>{
401 f: u32, 423 f: u32,
402}<|> 424}<|>
403 ", r" 425 ",
426 r"
404struct Foo { f: u32 } 427struct 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"
411fn foo() { 436fn 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"
416fn foo() { 442fn 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"
424pub fn handle_find_matching_brace() { 452pub 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"
431pub fn handle_find_matching_brace() { 460pub 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"
458fn foo() { 489fn foo() {
459 let foo =<|> 1 + 1 490 let foo =<|> 1 + 1
460} 491}
461", r" 492",
493 r"
462fn foo() { 494fn 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<|>
501fn foo() { 535fn foo() {
502} 536}
503", r" 537",
538 r"
504/// Some docs 539/// Some docs
505/// <|> 540/// <|>
506fn foo() { 541fn foo() {
507} 542}
508"); 543",
509 do_check(r" 544 );
545 do_check(
546 r"
510impl S { 547impl S {
511 /// Some<|> docs. 548 /// Some<|> docs.
512 fn foo() {} 549 fn foo() {}
513} 550}
514", r" 551",
552 r"
515impl S { 553impl 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 @@
1use languageserver_types::{ 1use 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
14pub fn server_capabilities() -> ServerCapabilities { 8pub 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 @@
1use languageserver_types::{ 1use 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};
6use ra_editor::{LineIndex, LineCol, Edit, AtomEdit};
7use ra_syntax::{SyntaxKind, TextUnit, TextRange};
8use ra_analysis::{FileId, SourceChange, SourceFileEdit, FileSystemEdit};
9
10use crate::{
11 Result,
12 server_world::ServerWorld,
13 req,
14}; 4};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit};
6use ra_editor::{AtomEdit, Edit, LineCol, LineIndex};
7use ra_syntax::{SyntaxKind, TextRange, TextUnit};
8
9use crate::{req, server_world::ServerWorld, Result};
15 10
16pub trait Conv { 11pub 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
302pub trait MapConvWith<'a>: Sized + 'a { 298pub trait MapConvWith<'a>: Sized + 'a {
@@ -309,8 +305,9 @@ pub trait MapConvWith<'a>: Sized + 'a {
309} 305}
310 306
311impl<'a, I> MapConvWith<'a> for I 307impl<'a, I> MapConvWith<'a> for I
312 where I: Iterator + 'a, 308where
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
324impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx> 321impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx>
325 where 322where
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 @@
2extern crate failure; 2extern crate failure;
3#[macro_use] 3#[macro_use]
4extern crate serde_derive; 4extern crate serde_derive;
5extern crate languageserver_types;
5extern crate serde; 6extern crate serde;
6extern crate serde_json; 7extern crate serde_json;
7extern crate languageserver_types;
8#[macro_use] 8#[macro_use]
9extern crate crossbeam_channel; 9extern crate crossbeam_channel;
10extern crate rayon; 10extern crate rayon;
11#[macro_use] 11#[macro_use]
12extern crate log; 12extern crate log;
13extern crate cargo_metadata;
13extern crate drop_bomb; 14extern crate drop_bomb;
14extern crate url_serde;
15extern crate walkdir;
16extern crate im; 15extern crate im;
17extern crate relative_path; 16extern crate relative_path;
18extern crate cargo_metadata;
19extern crate rustc_hash; 17extern crate rustc_hash;
18extern crate url_serde;
19extern crate walkdir;
20 20
21extern crate gen_lsp_server; 21extern crate gen_lsp_server;
22extern crate ra_editor;
23extern crate ra_analysis; 22extern crate ra_analysis;
23extern crate ra_editor;
24extern crate ra_syntax; 24extern crate ra_syntax;
25 25
26mod caps; 26mod caps;
27pub mod req;
28mod conv; 27mod conv;
29mod main_loop; 28mod main_loop;
30mod vfs;
31mod path_map; 29mod path_map;
32mod server_world;
33mod project_model; 30mod project_model;
31pub mod req;
32mod server_world;
34pub mod thread_watcher; 33pub mod thread_watcher;
34mod vfs;
35 35
36pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 36pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
37pub use crate::{ 37pub 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;
6extern crate gen_lsp_server; 6extern crate gen_lsp_server;
7extern crate ra_lsp_server; 7extern crate ra_lsp_server;
8 8
9use flexi_logger::{Logger, Duplicate}; 9use flexi_logger::{Duplicate, Logger};
10use gen_lsp_server::{run_server, stdio_transport}; 10use gen_lsp_server::{run_server, stdio_transport};
11use ra_lsp_server::Result; 11use 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 @@
1use rustc_hash::FxHashMap; 1use rustc_hash::FxHashMap;
2 2
3use languageserver_types::{ 3use 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};
8use ra_analysis::{FileId, FoldKind, JobToken, Query, RunnableKind};
9use ra_syntax::text_utils::contains_offset_nonstrict;
10use serde_json::to_value; 10use serde_json::to_value;
11use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind};
12use ra_syntax::{
13 text_utils::contains_offset_nonstrict
14};
15 11
16use crate::{ 12use 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
23pub fn handle_syntax_tree( 20pub 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
510fn highlight(world: &ServerWorld, file_id: FileId) -> Vec<Decoration> { 529fn 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 @@
1mod handlers; 1mod handlers;
2mod subscriptions; 2mod subscriptions;
3 3
4use std::{ 4use std::path::PathBuf;
5 path::PathBuf,
6};
7 5
8use serde::{Serialize, de::DeserializeOwned}; 6use crossbeam_channel::{unbounded, Receiver, Sender};
9use crossbeam_channel::{unbounded, Sender, Receiver};
10use rayon::{self, ThreadPool};
11use languageserver_types::{NumberOrString};
12use ra_analysis::{FileId, JobHandle, JobToken, LibraryData};
13use gen_lsp_server::{ 7use gen_lsp_server::{
14 RawRequest, RawNotification, RawMessage, RawResponse, ErrorCode, 8 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
15 handle_shutdown,
16}; 9};
10use languageserver_types::NumberOrString;
11use ra_analysis::{FileId, JobHandle, JobToken, LibraryData};
12use rayon::{self, ThreadPool};
17use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
14use serde::{de::DeserializeOwned, Serialize};
18 15
19use crate::{ 16use 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>(&params); 324 let not = RawNotification::new::<req::PublishDiagnostics>(&params);
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> {
342impl<'a> PoolDispatcher<'a> { 342impl<'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>(&params); 398 let not = RawNotification::new::<req::PublishDiagnostics>(&params);
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>(&params); 405 let not = RawNotification::new::<req::PublishDecorations>(&params);
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 @@
1use rustc_hash::FxHashSet;
2use ra_analysis::FileId; 1use ra_analysis::FileId;
2use rustc_hash::FxHashSet;
3 3
4pub struct Subscriptions { 4pub struct Subscriptions {
5 subs: FxHashSet<FileId>, 5 subs: FxHashSet<FileId>,
@@ -7,7 +7,9 @@ pub struct Subscriptions {
7 7
8impl Subscriptions { 8impl 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 @@
1use std::path::{PathBuf, Path, Component};
2use im; 1use im;
3use relative_path::RelativePath;
4use ra_analysis::{FileId, FileResolver}; 2use ra_analysis::{FileId, FileResolver};
3use relative_path::RelativePath;
4
5use std::path::{Component, Path, PathBuf};
5 6
6#[derive(Debug, Clone, Copy, PartialEq, Eq)] 7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Root { 8pub 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
56impl FileResolver for PathMap { 57impl 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 @@
1use std::{
2 path::{Path, PathBuf},
3};
4use rustc_hash::{FxHashMap, FxHashSet};
5use cargo_metadata::{metadata_run, CargoOpt}; 1use cargo_metadata::{metadata_run, CargoOpt};
6use ra_syntax::SmolStr; 2use ra_syntax::SmolStr;
3use rustc_hash::{FxHashMap, FxHashSet};
4
5use std::path::{Path, PathBuf};
7 6
8use crate::{ 7use 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)]
41pub enum TargetKind { 40pub 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
45impl Package { 49impl 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 @@
1use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url};
1use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
2use languageserver_types::{TextDocumentIdentifier, Range, Url, Position, Location};
3use url_serde; 3use url_serde;
4 4
5pub use languageserver_types::{ 5pub 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
20pub enum SyntaxTree {} 13pub 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")]
30pub struct SyntaxTreeParams { 23pub struct SyntaxTreeParams {
31 pub text_document: TextDocumentIdentifier 24 pub text_document: TextDocumentIdentifier,
32} 25}
33 26
34pub enum ExtendSelection {} 27pub enum ExtendSelection {}
@@ -94,7 +87,7 @@ pub struct PublishDecorationsParams {
94#[serde(rename_all = "camelCase")] 87#[serde(rename_all = "camelCase")]
95pub struct Decoration { 88pub struct Decoration {
96 pub range: Range, 89 pub range: Range,
97 pub tag: &'static str 90 pub tag: &'static str,
98} 91}
99 92
100pub enum ParentModule {} 93pub enum ParentModule {}
@@ -167,14 +160,14 @@ pub struct SourceChange {
167pub enum FileSystemEdit { 160pub 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
180pub enum InternalFeedback {} 173pub 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 @@
1use std::{ 1use std::{
2 fs, 2 fs,
3 path::{PathBuf, Path}, 3 path::{Path, PathBuf},
4 sync::Arc, 4 sync::Arc,
5}; 5};
6 6
7use rustc_hash::FxHashMap;
8use languageserver_types::Url; 7use languageserver_types::Url;
9use ra_analysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData, FileResolver}; 8use ra_analysis::{Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, LibraryData};
9use rustc_hash::FxHashMap;
10 10
11use crate::{ 11use 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 @@
1use std::thread;
2use crossbeam_channel::{bounded, unbounded, Sender, Receiver};
3use drop_bomb::DropBomb;
4use crate::Result; 1use crate::Result;
2use crossbeam_channel::{bounded, unbounded, Receiver, Sender};
3use drop_bomb::DropBomb;
4
5use std::thread;
5 6
6pub struct Worker<I, O> { 7pub 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 {
66fn worker_chan<I, O>(buf: usize) -> ((Sender<I>, Receiver<O>), Receiver<I>, Sender<O>) { 69fn 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 @@
1use std::{ 1use std::{
2 path::{PathBuf, Path},
3 fs, 2 fs,
3 path::{Path, PathBuf},
4}; 4};
5 5
6use walkdir::WalkDir; 6use walkdir::WalkDir;
7 7
8use crate::{ 8use crate::thread_watcher::{ThreadWatcher, Worker};
9 thread_watcher::{Worker, ThreadWatcher},
10};
11
12 9
13#[derive(Debug)] 10#[derive(Debug)]
14pub struct FileEvent { 11pub struct FileEvent {
@@ -24,7 +21,8 @@ pub enum FileEventKind {
24pub fn roots_loader() -> (Worker<PathBuf, (PathBuf, Vec<FileEvent>)>, ThreadWatcher) { 21pub 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]
2extern crate crossbeam_channel; 2extern crate crossbeam_channel;
3extern crate tempdir; 3extern crate flexi_logger;
4extern crate gen_lsp_server;
4extern crate languageserver_types; 5extern crate languageserver_types;
6extern crate ra_lsp_server;
5extern crate serde; 7extern crate serde;
6extern crate serde_json; 8extern crate serde_json;
7extern crate gen_lsp_server; 9extern crate tempdir;
8extern crate flexi_logger;
9extern crate ra_lsp_server;
10 10
11mod support; 11mod support;
12 12
@@ -14,17 +14,18 @@ use ra_lsp_server::req::{Runnables, RunnablesParams};
14 14
15use crate::support::project; 15use crate::support::project;
16 16
17
18const LOG: &'static str = ""; 17const LOG: &'static str = "";
19 18
20#[test] 19#[test]
21fn test_runnables_no_project() { 20fn 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]
25fn foo() { 25fn 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]
49fn test_runnables_project() { 50fn test_runnables_project() {
50 let server = project(r#" 51 let server = project(
52 r#"
51//- Cargo.toml 53//- Cargo.toml
52[package] 54[package]
53name = "foo" 55name = "foo"
@@ -59,7 +61,8 @@ pub fn foo() {}
59//- tests/spam.rs 61//- tests/spam.rs
60#[test] 62#[test]
61fn test_eggs() {} 63fn 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 @@
1use std::{ 1use 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
9use tempdir::TempDir;
10use crossbeam_channel::{after, Receiver}; 9use crossbeam_channel::{after, Receiver};
11use flexi_logger::Logger; 10use flexi_logger::Logger;
11use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
12use languageserver_types::{ 12use 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};
20use serde::Serialize; 17use serde::Serialize;
21use serde_json::{Value, from_str, to_string_pretty}; 18use serde_json::{from_str, to_string_pretty, Value};
22use gen_lsp_server::{RawMessage, RawRequest, RawNotification}; 19use tempdir::TempDir;
23 20
24use ra_lsp_server::{main_loop, req, thread_watcher::{ThreadWatcher, Worker}}; 21use ra_lsp_server::{
22 main_loop, req,
23 thread_watcher::{ThreadWatcher, Worker},
24};
25 25
26pub fn project(fixture: &str) -> Server { 26pub 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, &params); 130 let r = RawRequest::new::<R>(id, &params);
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 @@
1pub mod walk;
2pub mod visit; 1pub mod visit;
2pub mod walk;
3 3
4use crate::{ 4use 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
9pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset { 9pub 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
44pub enum LeafAtOffset<'a> { 49pub 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
50impl<'a> LeafAtOffset<'a> { 55impl<'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
106pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> { 118pub 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 @@
1use std::marker::PhantomData; 1use crate::{AstNode, SyntaxNodeRef};
2use crate::{SyntaxNodeRef, AstNode};
3 2
3use std::marker::PhantomData;
4 4
5pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { 5pub fn visitor<'a, T>() -> impl Visitor<'a, Output = T> {
6 EmptyVisitor { ph: PhantomData } 6 EmptyVisitor { ph: PhantomData }
7} 7}
8 8
9pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output=T, Ctx=C> { 9pub 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
13pub trait Visitor<'a>: Sized { 16pub 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)]
37struct EmptyVisitor<T> { 50struct EmptyVisitor<T> {
38 ph: PhantomData<fn() -> T> 51 ph: PhantomData<fn() -> T>,
39} 52}
40 53
41impl<'a, T> Visitor<'a> for EmptyVisitor<T> { 54impl<'a, T> Visitor<'a> for EmptyVisitor<T> {
@@ -69,10 +82,10 @@ pub struct Vis<V, N, F> {
69} 82}
70 83
71impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> 84impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F>
72 where 85where
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
92impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F> 105impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F>
93 where 106where
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 @@
1use crate::{ 1use crate::{algo::generate, SyntaxNodeRef};
2 SyntaxNodeRef,
3 algo::generate,
4};
5
6 2
7#[derive(Debug, Copy, Clone)] 3#[derive(Debug, Copy, Clone)]
8pub enum WalkEvent<'a> { 4pub 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
4use crate::{ 6use 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
6use crate::{ 8use 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
5use itertools::Itertools; 5use itertools::Itertools;
6 6
7pub use self::generated::*;
7use crate::{ 8use crate::{
8 SmolStr, SyntaxNodeRef, SyntaxKind::*,
9 yellow::{RefRoot, SyntaxNodeChildren}, 9 yellow::{RefRoot, SyntaxNodeChildren},
10 SmolStr,
11 SyntaxKind::*,
12 SyntaxNodeRef,
10}; 13};
11pub use self::generated::*;
12 14
13pub trait AstNode<'a>: Clone + Copy + 'a { 15pub 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
65impl<'a> FnDef<'a> { 68impl<'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
141impl CommentFlavor { 142impl 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
167impl<'a> Name<'a> { 168impl<'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
175impl<'a> NameRef<'a> { 175impl<'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)]
246pub struct AstChildren<'a, N> { 244pub 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// }
16pub(crate) const LITERAL_FIRST: TokenSet = 16pub(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
20pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { 29pub(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
29pub(super) const ATOM_EXPR_FIRST: TokenSet = 38pub(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
36const EXPR_RECOVERY_SET: TokenSet = 62const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
37 token_set![LET_KW];
38 63
39pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { 64pub(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 @@
1mod atom; 1mod atom;
2 2
3use super::*;
4pub(super) use self::atom::{literal, LITERAL_FIRST};
5pub(crate) use self::atom::match_arm_list; 3pub(crate) use self::atom::match_arm_list;
4pub(super) use self::atom::{literal, LITERAL_FIRST};
5use super::*;
6 6
7const EXPR_FIRST: TokenSet = LHS_FIRST; 7const EXPR_FIRST: TokenSet = LHS_FIRST;
8 8
9pub(super) fn expr(p: &mut Parser) -> BlockLike { 9pub(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
14pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike { 17pub(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
19fn expr_no_struct(p: &mut Parser) { 25fn 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 {
107fn current_op(p: &Parser) -> (u8, Op) { 116fn 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
204const LHS_FIRST: TokenSet = 211const 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
210fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { 216fn 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// }
320fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 328fn 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
2mod consts; 1mod consts;
3mod nominal; 2mod nominal;
4mod traits; 3mod traits;
5mod use_item; 4mod use_item;
6 5
7use super::*;
8pub(crate) use self::{ 6pub(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};
12use 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
28pub(super) enum ItemFlavor { 27pub(super) enum ItemFlavor {
29 Mod, Trait 28 Mod,
29 Trait,
30} 30}
31 31
32const ITEM_RECOVERY_SET: TokenSet = 32const 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
36pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { 37pub(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;
31mod type_params; 31mod type_params;
32mod types; 32mod types;
33 33
34use crate::{
35 token_set::TokenSet,
36 parser_api::{Marker, CompletedMarker, Parser},
37 SyntaxKind::{self, *},
38};
39pub(crate) use self::{ 34pub(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};
41use crate::{
42 parser_api::{CompletedMarker, Marker, Parser},
43 token_set::TokenSet,
44 SyntaxKind::{self, *},
45};
56 46
57pub(crate) fn root(p: &mut Parser) { 47pub(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)]
66enum BlockLike { 55enum BlockLike {
67 Block, 56 Block,
@@ -69,7 +58,9 @@ enum BlockLike {
69} 58}
70 59
71impl BlockLike { 60impl 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
75fn opt_visibility(p: &mut Parser) { 66fn 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
65const VALUE_PARAMETER_FIRST: TokenSet = 64const 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
71fn value_parameter(p: &mut Parser, flavor: Flavor) { 67fn 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 @@
1use super::*; 1use super::*;
2 2
3pub(super) const PATTERN_FIRST: TokenSet = 3pub(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
10pub(super) fn pattern(p: &mut Parser) { 9pub(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) {
29const PAT_RECOVERY_SET: TokenSet = 28const 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
33fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { 31fn 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 @@
1use super::*; 1use super::*;
2 2
3pub(super) const TYPE_FIRST: TokenSet = 3pub(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
11const TYPE_RECOVERY_SET: TokenSet = 11const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA];
12 token_set![R_PAREN, COMMA];
13 12
14pub(super) fn type_(p: &mut Parser) { 13pub(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
23extern crate itertools;
24extern crate unicode_xid;
25extern crate drop_bomb; 23extern crate drop_bomb;
24extern crate itertools;
26extern crate parking_lot; 25extern crate parking_lot;
27extern crate rowan; 26extern crate rowan;
27extern crate unicode_xid;
28 28
29#[cfg(test)] 29#[cfg(test)]
30#[macro_use] 30#[macro_use]
@@ -35,33 +35,31 @@ pub mod ast;
35mod lexer; 35mod lexer;
36#[macro_use] 36#[macro_use]
37mod token_set; 37mod token_set;
38mod parser_api;
39mod grammar; 38mod grammar;
39mod parser_api;
40mod parser_impl; 40mod parser_impl;
41mod reparsing; 41mod reparsing;
42 42
43mod syntax_kinds; 43mod syntax_kinds;
44mod yellow; 44pub mod text_utils;
45/// Utilities for simple uses of the parser. 45/// Utilities for simple uses of the parser.
46pub mod utils; 46pub mod utils;
47pub mod text_utils; 47mod yellow;
48 48
49pub use crate::{ 49pub 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
58use crate::{ 58use crate::yellow::GreenNode;
59 yellow::{GreenNode},
60};
61 59
62#[derive(Clone, Debug, Hash, PartialEq, Eq)] 60#[derive(Clone, Debug, Hash, PartialEq, Eq)]
63pub struct File { 61pub struct File {
64 root: SyntaxNode 62 root: SyntaxNode,
65} 63}
66 64
67impl File { 65impl 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 @@
1use crate::{ 1use 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.
10use std::mem;
11use crate::{ 10use 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 17use 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
91impl<'a, S: Sink> EventProcessor<'a, S> { 91impl<'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
218fn n_attached_trivias<'a>(kind: SyntaxKind, trivias: impl Iterator<Item=(SyntaxKind, &'a str)>) -> usize { 226fn 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;
4use std::cell::Cell; 4use std::cell::Cell;
5 5
6use crate::{ 6use 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
16use crate::SyntaxKind::{self, EOF, TOMBSTONE}; 16use 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 @@
1use crate::algo; 1use crate::algo;
2use crate::grammar; 2use crate::grammar;
3use crate::lexer::{tokenize, Token}; 3use crate::lexer::{tokenize, Token};
4use crate::yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError};
5use crate::parser_impl;
6use crate::parser_api::Parser; 4use crate::parser_api::Parser;
7use crate::{ 5use crate::parser_impl;
8 TextUnit, TextRange,
9 SyntaxKind::*,
10};
11use crate::text_utils::replace_range; 6use crate::text_utils::replace_range;
7use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNodeRef};
8use crate::{SyntaxKind::*, TextRange, TextUnit};
12 9
13#[derive(Debug, Clone)] 10#[derive(Debug, Clone)]
14pub struct AtomEdit { 11pub struct AtomEdit {
@@ -18,7 +15,10 @@ pub struct AtomEdit {
18 15
19impl AtomEdit { 16impl 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
102fn is_contextual_kw(text: &str) -> bool { 94fn 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>(
145fn is_balanced(tokens: &[Token]) -> bool { 136fn 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)]
192mod tests { 186mod 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"
239fn foo() { 226fn 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"
244fn foo() { 234fn 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"
249struct Foo { 242struct 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"
254fn foo { 250fn 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"
261mod foo { 260mod foo {
262 fn <|><|> 261 fn <|><|>
263} 262}
264", "bar"); 263",
265 do_check(r" 264 "bar",
265 );
266 do_check(
267 r"
266trait Foo { 268trait Foo {
267 type <|>Foo<|>; 269 type <|>Foo<|>;
268} 270}
269", "Output"); 271",
270 do_check(r" 272 "Output",
273 );
274 do_check(
275 r"
271impl IntoIterator<Item=i32> for Foo { 276impl 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"
276use a::b::{foo,<|>,bar<|>}; 284use a::b::{foo,<|>,bar<|>};
277 ", "baz"); 285 ",
278 do_check(r" 286 "baz",
287 );
288 do_check(
289 r"
279pub enum A { 290pub 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"
284foo!{a, b<|><|> d} 298foo!{a, b<|><|> d}
285", ", c[3]"); 299",
286 do_check(r" 300 ", c[3]",
301 );
302 do_check(
303 r"
287fn foo() { 304fn foo() {
288 vec![<|><|>] 305 vec![<|><|>]
289} 306}
290", "123"); 307",
291 do_check(r" 308 "123",
309 );
310 do_check(
311 r"
292extern { 312extern {
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"<|><|>
304fn foo() -> i32 { 1 } 326fn foo() -> i32 { 1 }
305", "\n\n\n \n"); 327",
306 do_check(r" 328 "\n\n\n \n",
329 );
330 do_check(
331 r"
307fn foo() -> <|><|> {} 332fn foo() -> <|><|> {}
308", " \n"); 333",
309 do_check(r" 334 " \n",
335 );
336 do_check(
337 r"
310fn <|>foo<|>() -> i32 { 1 } 338fn <|>foo<|>() -> i32 { 1 }
311", "bar"); 339",
312 do_check(r" 340 "bar",
341 );
342 do_check(
343 r"
313fn foo<|><|>foo() { } 344fn foo<|><|>foo() { }
314", "bar"); 345",
315 do_check(r" 346 "bar",
347 );
348 do_check(
349 r"
316fn foo /* <|><|> */ () {} 350fn foo /* <|><|> */ () {}
317", "some comment"); 351",
318 do_check(r" 352 "some comment",
353 );
354 do_check(
355 r"
319fn baz <|><|> () {} 356fn baz <|><|> () {}
320", " \t\t\n\n"); 357",
321 do_check(r" 358 " \t\t\n\n",
359 );
360 do_check(
361 r"
322fn baz <|><|> () {} 362fn 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
326mod { } 369mod { }
327", "c"); 370",
328 do_check(r#" 371 "c",
372 );
373 do_check(
374 r#"
329fn -> &str { "Hello<|><|>" } 375fn -> &str { "Hello<|><|>" }
330"#, ", world"); 376"#,
331 do_check(r#" 377 ", world",
378 );
379 do_check(
380 r#"
332fn -> &str { // "Hello<|><|>" 381fn -> &str { // "Hello<|><|>"
333"#, ", world"); 382"#,
334 do_check(r##" 383 ", world",
384 );
385 do_check(
386 r##"
335fn -> &str { r#"Hello<|><|>"# 387fn -> &str { r#"Hello<|><|>"#
336"##, ", world"); 388"##,
337 do_check(r" 389 ", world",
390 );
391 do_check(
392 r"
338#[derive(<|>Copy<|>)] 393#[derive(<|>Copy<|>)]
339enum Foo { 394enum 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 @@
1mod generated; 1mod generated;
2 2
3use std::fmt;
4use crate::SyntaxKind::*; 3use crate::SyntaxKind::*;
4use std::fmt;
5 5
6pub use self::generated::SyntaxKind; 6pub 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 @@
1use std::fmt::Write;
2use crate::{ 1use crate::{
3 algo::walk::{walk, WalkEvent}, 2 algo::walk::{walk, WalkEvent},
4 SyntaxKind, File, SyntaxNodeRef 3 File, SyntaxKind, SyntaxNodeRef,
5}; 4};
5use 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.
8pub fn dump_tree(syntax: SyntaxNodeRef) -> String { 8pub 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 @@
1use rowan::GreenNodeBuilder;
2use crate::{ 1use 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};
6use rowan::GreenNodeBuilder;
8 7
9pub(crate) struct GreenBuilder { 8pub(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 @@
1mod builder; 1mod builder;
2mod syntax_text; 2mod syntax_text;
3 3
4use self::syntax_text::SyntaxText;
5use crate::{SmolStr, SyntaxKind, TextRange, TextUnit};
6use rowan::Types;
4use std::{ 7use std::{
5 fmt, 8 fmt,
6 hash::{Hash, Hasher}, 9 hash::{Hash, Hasher},
7}; 10};
8use rowan::Types;
9use crate::{SyntaxKind, TextUnit, TextRange, SmolStr};
10use self::syntax_text::SyntaxText;
11 11
12pub use rowan::{TreeRoot};
13pub(crate) use self::builder::GreenBuilder; 12pub(crate) use self::builder::GreenBuilder;
13pub use rowan::TreeRoot;
14 14
15#[derive(Debug, Clone, Copy)] 15#[derive(Debug, Clone, Copy)]
16pub enum RaTypes {} 16pub enum RaTypes {}
@@ -31,9 +31,7 @@ pub struct SyntaxError {
31} 31}
32 32
33#[derive(Clone, Copy)] 33#[derive(Clone, Copy)]
34pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>( 34pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(::rowan::SyntaxNode<RaTypes, R>);
35 ::rowan::SyntaxNode<RaTypes, R>,
36);
37pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; 35pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;
38 36
39impl<R1, R2> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> 37impl<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)]
145pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>( 143pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>(::rowan::SyntaxNodeChildren<RaTypes, R>);
146 ::rowan::SyntaxNodeChildren<RaTypes, R>
147);
148 144
149impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> { 145impl<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
158fn has_short_text(kind: SyntaxKind) -> bool { 153fn 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 @@
1use std::{ 1use std::{fmt, ops};
2 fmt, ops,
3};
4 2
5use crate::{ 3use 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;
4extern crate walkdir; 4extern crate walkdir;
5 5
6use std::{ 6use std::{
7 fmt::Write,
7 fs, 8 fs,
8 path::{Path, PathBuf}, 9 path::{Path, PathBuf},
9 fmt::Write,
10}; 10};
11 11
12use ra_syntax::{ 12use 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
56pub fn dir_tests<F>(paths: &[&str], f: F) 55pub fn dir_tests<F>(paths: &[&str], f: F)
57 where 56where
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;
2extern crate itertools; 2extern crate itertools;
3extern crate text_unit; 3extern crate text_unit;
4 4
5use std::fmt;
6use itertools::Itertools; 5use itertools::Itertools;
7use text_unit::{TextUnit, TextRange}; 6use std::fmt;
7use text_unit::{TextRange, TextUnit};
8 8
9pub use self::difference::Changeset as __Changeset; 9pub 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 @@
1extern crate itertools; 1extern crate itertools;
2#[macro_use] 2#[macro_use]
3extern crate failure; 3extern crate failure;
4extern crate heck;
4extern crate ron; 5extern crate ron;
5extern crate tera; 6extern crate tera;
6extern crate heck;
7 7
8use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
9use itertools::Itertools;
8use std::{ 10use std::{
9 collections::HashMap, 11 collections::HashMap,
10 fs, 12 fs,
11 path::{Path, PathBuf}, 13 path::{Path, PathBuf},
12}; 14};
13use itertools::Itertools;
14use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
15 15
16pub type Result<T> = ::std::result::Result<T, failure::Error>; 16pub 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
65pub fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { 64pub 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
118pub fn project_root() -> PathBuf { 117pub 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};
14use tools::{AST, AST_TEMPLATE, Result, SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, Test, collect_tests, render_template, update, project_root}; 14use tools::{
15 collect_tests, project_root, render_template, update, Result, Test, AST, AST_TEMPLATE,
16 SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE,
17};
15 18
16const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar"; 19const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar";
17const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline"; 20const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline";
@@ -40,18 +43,23 @@ fn main() -> Result<()> {
40fn run_gen_command(name: &str, verify: bool) -> Result<()> { 43fn 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
55fn gen_tests(verify: bool) -> Result<()> { 63fn 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<()> {
145fn run(cmdline: &'static str, dir: &str) -> Result<()> { 162fn 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 @@
1extern crate tools; 1extern crate tools;
2 2
3use tools::{AST, AST_TEMPLATE, SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE, render_template, update, project_root}; 3use tools::{
4 project_root, render_template, update, AST, AST_TEMPLATE, SYNTAX_KINDS, SYNTAX_KINDS_TEMPLATE,
5};
4 6
5#[test] 7#[test]
6fn verify_template_generation() { 8fn 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}