aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--crates/ra_analysis/src/db.rs12
-rw-r--r--crates/ra_analysis/src/imp.rs16
-rw-r--r--crates/ra_analysis/src/lib.rs15
-rw-r--r--crates/ra_analysis/tests/tests.rs2
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_db/src/loc2id.rs7
-rw-r--r--crates/ra_editor/src/folding_ranges.rs74
-rw-r--r--crates/ra_hir/src/module/imp.rs8
-rw-r--r--crates/ra_lsp_server/src/conv.rs36
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs18
-rw-r--r--crates/ra_lsp_server/src/server_world.rs10
-rw-r--r--crates/ra_text_edit/src/text_edit.rs4
-rw-r--r--crates/test_utils/src/lib.rs39
-rw-r--r--crates/tools/src/lib.rs2
16 files changed, 160 insertions, 89 deletions
diff --git a/.travis.yml b/.travis.yml
index 5589b0002..5e11cbd2f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ env:
9 9
10build: &rust_build 10build: &rust_build
11 language: rust 11 language: rust
12 rust: 1.31.0 12 rust: 1.31.1
13 script: 13 script:
14 - cargo gen-tests --verify 14 - cargo gen-tests --verify
15 - cargo gen-syntax --verify 15 - cargo gen-syntax --verify
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index 3d0f13f34..94729d296 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,4 +1,4 @@
1use std::sync::Arc; 1use std::{fmt, sync::Arc};
2use salsa::{self, Database}; 2use salsa::{self, Database};
3use ra_db::{LocationIntener, BaseDatabase}; 3use ra_db::{LocationIntener, BaseDatabase};
4use hir::{self, DefId, DefLoc}; 4use hir::{self, DefId, DefLoc};
@@ -13,11 +13,19 @@ pub(crate) struct RootDatabase {
13 id_maps: Arc<IdMaps>, 13 id_maps: Arc<IdMaps>,
14} 14}
15 15
16#[derive(Debug, Default)] 16#[derive(Default)]
17struct IdMaps { 17struct IdMaps {
18 defs: LocationIntener<DefLoc, DefId>, 18 defs: LocationIntener<DefLoc, DefId>,
19} 19}
20 20
21impl fmt::Debug for IdMaps {
22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23 f.debug_struct("IdMaps")
24 .field("n_defs", &self.defs.len())
25 .finish()
26 }
27}
28
21impl salsa::Database for RootDatabase { 29impl salsa::Database for RootDatabase {
22 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> { 30 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
23 &self.runtime 31 &self.runtime
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index b44d9297a..5701e1ae2 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -25,7 +25,7 @@ use crate::{
25 db, 25 db,
26 symbol_index::{SymbolIndex, SymbolsDatabase, LibrarySymbolsQuery}, 26 symbol_index::{SymbolIndex, SymbolsDatabase, LibrarySymbolsQuery},
27 AnalysisChange, RootChange, Cancelable, CrateId, Diagnostic, FileId, 27 AnalysisChange, RootChange, Cancelable, CrateId, Diagnostic, FileId,
28 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, 28 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileEdit,
29 ReferenceResolution, 29 ReferenceResolution,
30}; 30};
31 31
@@ -368,10 +368,11 @@ impl AnalysisImpl {
368 .collect::<Vec<_>>(); 368 .collect::<Vec<_>>();
369 if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? { 369 if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? {
370 for (name_node, problem) in m.problems(&*self.db) { 370 for (name_node, problem) in m.problems(&*self.db) {
371 let source_root = self.db.file_source_root(file_id);
371 let diag = match problem { 372 let diag = match problem {
372 Problem::UnresolvedModule { candidate } => { 373 Problem::UnresolvedModule { candidate } => {
373 let create_file = FileSystemEdit::CreateFile { 374 let create_file = FileSystemEdit::CreateFile {
374 anchor: file_id, 375 source_root,
375 path: candidate.clone(), 376 path: candidate.clone(),
376 }; 377 };
377 let fix = SourceChange { 378 let fix = SourceChange {
@@ -388,11 +389,12 @@ impl AnalysisImpl {
388 } 389 }
389 Problem::NotDirOwner { move_to, candidate } => { 390 Problem::NotDirOwner { move_to, candidate } => {
390 let move_file = FileSystemEdit::MoveFile { 391 let move_file = FileSystemEdit::MoveFile {
391 file: file_id, 392 src: file_id,
392 path: move_to.clone(), 393 dst_source_root: source_root,
394 dst_path: move_to.clone(),
393 }; 395 };
394 let create_file = FileSystemEdit::CreateFile { 396 let create_file = FileSystemEdit::CreateFile {
395 anchor: file_id, 397 source_root,
396 path: move_to.join(candidate), 398 path: move_to.join(candidate),
397 }; 399 };
398 let fix = SourceChange { 400 let fix = SourceChange {
@@ -518,9 +520,9 @@ impl AnalysisImpl {
518 520
519impl SourceChange { 521impl SourceChange {
520 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange { 522 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
521 let file_edit = SourceFileNodeEdit { 523 let file_edit = SourceFileEdit {
522 file_id, 524 file_id,
523 edits: edit.edit.into_atoms(), 525 edit: edit.edit,
524 }; 526 };
525 SourceChange { 527 SourceChange {
526 label: label.to_string(), 528 label: label.to_string(),
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index a1d462528..c7e7dc1c0 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -20,7 +20,7 @@ use std::{fmt, sync::Arc};
20 20
21use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
22use ra_syntax::{SourceFileNode, TextRange, TextUnit}; 22use ra_syntax::{SourceFileNode, TextRange, TextUnit};
23use ra_text_edit::AtomTextEdit; 23use ra_text_edit::TextEdit;
24use rayon::prelude::*; 24use rayon::prelude::*;
25use relative_path::RelativePathBuf; 25use relative_path::RelativePathBuf;
26 26
@@ -159,26 +159,27 @@ impl AnalysisHost {
159#[derive(Debug)] 159#[derive(Debug)]
160pub struct SourceChange { 160pub struct SourceChange {
161 pub label: String, 161 pub label: String,
162 pub source_file_edits: Vec<SourceFileNodeEdit>, 162 pub source_file_edits: Vec<SourceFileEdit>,
163 pub file_system_edits: Vec<FileSystemEdit>, 163 pub file_system_edits: Vec<FileSystemEdit>,
164 pub cursor_position: Option<FilePosition>, 164 pub cursor_position: Option<FilePosition>,
165} 165}
166 166
167#[derive(Debug)] 167#[derive(Debug)]
168pub struct SourceFileNodeEdit { 168pub struct SourceFileEdit {
169 pub file_id: FileId, 169 pub file_id: FileId,
170 pub edits: Vec<AtomTextEdit>, 170 pub edit: TextEdit,
171} 171}
172 172
173#[derive(Debug)] 173#[derive(Debug)]
174pub enum FileSystemEdit { 174pub enum FileSystemEdit {
175 CreateFile { 175 CreateFile {
176 anchor: FileId, 176 source_root: SourceRootId,
177 path: RelativePathBuf, 177 path: RelativePathBuf,
178 }, 178 },
179 MoveFile { 179 MoveFile {
180 file: FileId, 180 src: FileId,
181 path: RelativePathBuf, 181 dst_source_root: SourceRootId,
182 dst_path: RelativePathBuf,
182 }, 183 },
183} 184}
184 185
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index 889b568b9..67738da48 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -81,7 +81,7 @@ fn test_unresolved_module_diagnostic() {
81 fix: Some(SourceChange { 81 fix: Some(SourceChange {
82 label: "create module", 82 label: "create module",
83 source_file_edits: [], 83 source_file_edits: [],
84 file_system_edits: [CreateFile { anchor: FileId(1), path: "../foo.rs" }], 84 file_system_edits: [CreateFile { source_root: SourceRootId(0), path: "foo.rs" }],
85 cursor_position: None }) }]"#, 85 cursor_position: None }) }]"#,
86 &diagnostics, 86 &diagnostics,
87 ); 87 );
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 65fa3cbfa..0aca6f343 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -15,7 +15,7 @@ pub type Cancelable<T> = Result<T, Canceled>;
15 15
16impl std::fmt::Display for Canceled { 16impl std::fmt::Display for Canceled {
17 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 17 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 fmt.write_str("Canceled") 18 fmt.write_str("canceled")
19 } 19 }
20} 20}
21 21
diff --git a/crates/ra_db/src/loc2id.rs b/crates/ra_db/src/loc2id.rs
index 69ba43d0f..2dc7930d8 100644
--- a/crates/ra_db/src/loc2id.rs
+++ b/crates/ra_db/src/loc2id.rs
@@ -42,6 +42,10 @@ where
42 ID: NumericId, 42 ID: NumericId,
43 LOC: Clone + Eq + Hash, 43 LOC: Clone + Eq + Hash,
44{ 44{
45 pub fn len(&self) -> usize {
46 self.loc2id.len()
47 }
48
45 pub fn loc2id(&mut self, loc: &LOC) -> ID { 49 pub fn loc2id(&mut self, loc: &LOC) -> ID {
46 match self.loc2id.get(loc) { 50 match self.loc2id.get(loc) {
47 Some(id) => return id.clone(), 51 Some(id) => return id.clone(),
@@ -91,6 +95,9 @@ where
91 ID: NumericId, 95 ID: NumericId,
92 LOC: Clone + Eq + Hash, 96 LOC: Clone + Eq + Hash,
93{ 97{
98 pub fn len(&self) -> usize {
99 self.map.lock().len()
100 }
94 pub fn loc2id(&self, loc: &LOC) -> ID { 101 pub fn loc2id(&self, loc: &LOC) -> ID {
95 self.map.lock().loc2id(loc) 102 self.map.lock().loc2id(loc)
96 } 103 }
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
index 2a8fa3cda..da542ecf0 100644
--- a/crates/ra_editor/src/folding_ranges.rs
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -10,6 +10,7 @@ use ra_syntax::{
10pub enum FoldKind { 10pub enum FoldKind {
11 Comment, 11 Comment,
12 Imports, 12 Imports,
13 Block,
13} 14}
14 15
15#[derive(Debug)] 16#[derive(Debug)]
@@ -62,6 +63,8 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
62 match kind { 63 match kind {
63 COMMENT => Some(FoldKind::Comment), 64 COMMENT => Some(FoldKind::Comment),
64 USE_ITEM => Some(FoldKind::Imports), 65 USE_ITEM => Some(FoldKind::Imports),
66 NAMED_FIELD_DEF_LIST | FIELD_PAT_LIST | ITEM_LIST | EXTERN_ITEM_LIST | USE_TREE_LIST
67 | BLOCK | ENUM_VARIANT_LIST => Some(FoldKind::Block),
65 _ => None, 68 _ => None,
66 } 69 }
67} 70}
@@ -170,7 +173,7 @@ mod tests {
170 use test_utils::extract_ranges; 173 use test_utils::extract_ranges;
171 174
172 fn do_check(text: &str, fold_kinds: &[FoldKind]) { 175 fn do_check(text: &str, fold_kinds: &[FoldKind]) {
173 let (ranges, text) = extract_ranges(text); 176 let (ranges, text) = extract_ranges(text, "fold");
174 let file = SourceFileNode::parse(&text); 177 let file = SourceFileNode::parse(&text);
175 let folds = folding_ranges(&file); 178 let folds = folding_ranges(&file);
176 179
@@ -198,26 +201,27 @@ mod tests {
198 #[test] 201 #[test]
199 fn test_fold_comments() { 202 fn test_fold_comments() {
200 let text = r#" 203 let text = r#"
201<|>// Hello 204<fold>// Hello
202// this is a multiline 205// this is a multiline
203// comment 206// comment
204//<|> 207//</fold>
205 208
206// But this is not 209// But this is not
207 210
208fn main() { 211fn main() <fold>{
209 <|>// We should 212 <fold>// We should
210 // also 213 // also
211 // fold 214 // fold
212 // this one.<|> 215 // this one.</fold>
213 <|>//! But this one is different 216 <fold>//! But this one is different
214 //! because it has another flavor<|> 217 //! because it has another flavor</fold>
215 <|>/* As does this 218 <fold>/* As does this
216 multiline comment */<|> 219 multiline comment */</fold>
217}"#; 220}</fold>"#;
218 221
219 let fold_kinds = &[ 222 let fold_kinds = &[
220 FoldKind::Comment, 223 FoldKind::Comment,
224 FoldKind::Block,
221 FoldKind::Comment, 225 FoldKind::Comment,
222 FoldKind::Comment, 226 FoldKind::Comment,
223 FoldKind::Comment, 227 FoldKind::Comment,
@@ -228,60 +232,66 @@ fn main() {
228 #[test] 232 #[test]
229 fn test_fold_imports() { 233 fn test_fold_imports() {
230 let text = r#" 234 let text = r#"
231<|>use std::{ 235<fold>use std::<fold>{
232 str, 236 str,
233 vec, 237 vec,
234 io as iop 238 io as iop
235};<|> 239}</fold>;</fold>
236 240
237fn main() { 241fn main() <fold>{
238}"#; 242}</fold>"#;
239 243
240 let folds = &[FoldKind::Imports]; 244 let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
241 do_check(text, folds); 245 do_check(text, folds);
242 } 246 }
243 247
244 #[test] 248 #[test]
245 fn test_fold_import_groups() { 249 fn test_fold_import_groups() {
246 let text = r#" 250 let text = r#"
247<|>use std::str; 251<fold>use std::str;
248use std::vec; 252use std::vec;
249use std::io as iop;<|> 253use std::io as iop;</fold>
250 254
251<|>use std::mem; 255<fold>use std::mem;
252use std::f64;<|> 256use std::f64;</fold>
253 257
254use std::collections::HashMap; 258use std::collections::HashMap;
255// Some random comment 259// Some random comment
256use std::collections::VecDeque; 260use std::collections::VecDeque;
257 261
258fn main() { 262fn main() <fold>{
259}"#; 263}</fold>"#;
260 264
261 let folds = &[FoldKind::Imports, FoldKind::Imports]; 265 let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
262 do_check(text, folds); 266 do_check(text, folds);
263 } 267 }
264 268
265 #[test] 269 #[test]
266 fn test_fold_import_and_groups() { 270 fn test_fold_import_and_groups() {
267 let text = r#" 271 let text = r#"
268<|>use std::str; 272<fold>use std::str;
269use std::vec; 273use std::vec;
270use std::io as iop;<|> 274use std::io as iop;</fold>
271 275
272<|>use std::mem; 276<fold>use std::mem;
273use std::f64;<|> 277use std::f64;</fold>
274 278
275<|>use std::collections::{ 279<fold>use std::collections::<fold>{
276 HashMap, 280 HashMap,
277 VecDeque, 281 VecDeque,
278};<|> 282}</fold>;</fold>
279// Some random comment 283// Some random comment
280 284
281fn main() { 285fn main() <fold>{
282}"#; 286}</fold>"#;
283 287
284 let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Imports]; 288 let folds = &[
289 FoldKind::Imports,
290 FoldKind::Imports,
291 FoldKind::Imports,
292 FoldKind::Block,
293 FoldKind::Block,
294 ];
285 do_check(text, folds); 295 do_check(text, folds);
286 } 296 }
287 297
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
index f3a346152..748fdb64e 100644
--- a/crates/ra_hir/src/module/imp.rs
+++ b/crates/ra_hir/src/module/imp.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 ast::{self, NameOwner}, 4 ast::{self, NameOwner},
5 SmolStr, 5 SmolStr,
6}; 6};
7use relative_path::{RelativePathBuf, RelativePath}; 7use relative_path::RelativePathBuf;
8use rustc_hash::{FxHashMap, FxHashSet}; 8use rustc_hash::{FxHashMap, FxHashSet};
9use arrayvec::ArrayVec; 9use arrayvec::ArrayVec;
10use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; 10use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
@@ -184,11 +184,7 @@ fn resolve_submodule(
184 .collect::<Vec<_>>(); 184 .collect::<Vec<_>>();
185 let problem = if points_to.is_empty() { 185 let problem = if points_to.is_empty() {
186 Some(Problem::UnresolvedModule { 186 Some(Problem::UnresolvedModule {
187 candidate: RelativePath::new("../").join(&if is_dir_owner { 187 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
188 file_mod
189 } else {
190 file_dir_mod
191 }),
192 }) 188 })
193 } else { 189 } else {
194 None 190 None
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 7467f472c..218ded4ee 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, 3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier,
4}; 4};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileNodeEdit, FilePosition}; 5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition};
6use ra_editor::{LineCol, LineIndex}; 6use ra_editor::{LineCol, LineIndex};
7use ra_text_edit::{AtomTextEdit, TextEdit}; 7use ra_text_edit::{AtomTextEdit, TextEdit};
8use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 8use ra_syntax::{SyntaxKind, TextRange, TextUnit};
@@ -97,21 +97,21 @@ impl ConvWith for TextEdit {
97 type Output = Vec<languageserver_types::TextEdit>; 97 type Output = Vec<languageserver_types::TextEdit>;
98 98
99 fn conv_with(self, line_index: &LineIndex) -> Vec<languageserver_types::TextEdit> { 99 fn conv_with(self, line_index: &LineIndex) -> Vec<languageserver_types::TextEdit> {
100 self.into_atoms() 100 self.as_atoms()
101 .into_iter() 101 .into_iter()
102 .map_conv_with(line_index) 102 .map_conv_with(line_index)
103 .collect() 103 .collect()
104 } 104 }
105} 105}
106 106
107impl ConvWith for AtomTextEdit { 107impl<'a> ConvWith for &'a AtomTextEdit {
108 type Ctx = LineIndex; 108 type Ctx = LineIndex;
109 type Output = languageserver_types::TextEdit; 109 type Output = languageserver_types::TextEdit;
110 110
111 fn conv_with(self, line_index: &LineIndex) -> languageserver_types::TextEdit { 111 fn conv_with(self, line_index: &LineIndex) -> languageserver_types::TextEdit {
112 languageserver_types::TextEdit { 112 languageserver_types::TextEdit {
113 range: self.delete.conv_with(line_index), 113 range: self.delete.conv_with(line_index),
114 new_text: self.insert, 114 new_text: self.insert.clone(),
115 } 115 }
116 } 116 }
117} 117}
@@ -199,7 +199,7 @@ impl TryConvWith for SourceChange {
199 .source_file_edits 199 .source_file_edits
200 .iter() 200 .iter()
201 .find(|it| it.file_id == pos.file_id) 201 .find(|it| it.file_id == pos.file_id)
202 .map(|it| it.edits.as_slice()) 202 .map(|it| it.edit.as_atoms())
203 .unwrap_or(&[]); 203 .unwrap_or(&[]);
204 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits); 204 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
205 let position = 205 let position =
@@ -256,7 +256,7 @@ fn translate_offset_with_edit(
256 } 256 }
257} 257}
258 258
259impl TryConvWith for SourceFileNodeEdit { 259impl TryConvWith for SourceFileEdit {
260 type Ctx = ServerWorld; 260 type Ctx = ServerWorld;
261 type Output = TextDocumentEdit; 261 type Output = TextDocumentEdit;
262 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> { 262 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> {
@@ -265,7 +265,12 @@ impl TryConvWith for SourceFileNodeEdit {
265 version: None, 265 version: None,
266 }; 266 };
267 let line_index = world.analysis().file_line_index(self.file_id); 267 let line_index = world.analysis().file_line_index(self.file_id);
268 let edits = self.edits.into_iter().map_conv_with(&line_index).collect(); 268 let edits = self
269 .edit
270 .as_atoms()
271 .iter()
272 .map_conv_with(&line_index)
273 .collect();
269 Ok(TextDocumentEdit { 274 Ok(TextDocumentEdit {
270 text_document, 275 text_document,
271 edits, 276 edits,
@@ -278,16 +283,17 @@ impl TryConvWith for FileSystemEdit {
278 type Output = req::FileSystemEdit; 283 type Output = req::FileSystemEdit;
279 fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> { 284 fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> {
280 let res = match self { 285 let res = match self {
281 FileSystemEdit::CreateFile { anchor, path } => { 286 FileSystemEdit::CreateFile { source_root, path } => {
282 let uri = world.file_id_to_uri(anchor)?; 287 let uri = world.path_to_uri(source_root, &path)?;
283 let path = &path.as_str()[3..]; // strip `../` b/c url is weird
284 let uri = uri.join(path)?;
285 req::FileSystemEdit::CreateFile { uri } 288 req::FileSystemEdit::CreateFile { uri }
286 } 289 }
287 FileSystemEdit::MoveFile { file, path } => { 290 FileSystemEdit::MoveFile {
288 let src = world.file_id_to_uri(file)?; 291 src,
289 let path = &path.as_str()[3..]; // strip `../` b/c url is weird 292 dst_source_root,
290 let dst = src.join(path)?; 293 dst_path,
294 } => {
295 let src = world.file_id_to_uri(src)?;
296 let dst = world.path_to_uri(dst_source_root, &dst_path)?;
291 req::FileSystemEdit::MoveFile { src, dst } 297 req::FileSystemEdit::MoveFile { src, dst }
292 } 298 }
293 }; 299 };
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 1d6e3e5d6..afe0fec89 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -387,7 +387,7 @@ impl<'a> PoolDispatcher<'a> {
387 RawResponse::err( 387 RawResponse::err(
388 id, 388 id,
389 ErrorCode::ContentModified as i32, 389 ErrorCode::ContentModified as i32,
390 e.to_string(), 390 format!("content modified: {}", e),
391 ) 391 )
392 } else { 392 } else {
393 RawResponse::err( 393 RawResponse::err(
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 572ae7fb5..1751d7fa8 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -107,9 +107,16 @@ pub fn handle_on_type_formatting(
107 }; 107 };
108 let edits = match world.analysis().on_eq_typed(position) { 108 let edits = match world.analysis().on_eq_typed(position) {
109 None => return Ok(None), 109 None => return Ok(None),
110 Some(mut action) => action.source_file_edits.pop().unwrap().edits, 110 Some(mut action) => action
111 .source_file_edits
112 .pop()
113 .unwrap()
114 .edit
115 .as_atoms()
116 .iter()
117 .map_conv_with(&line_index)
118 .collect(),
111 }; 119 };
112 let edits = edits.into_iter().map_conv_with(&line_index).collect();
113 Ok(Some(edits)) 120 Ok(Some(edits))
114} 121}
115 122
@@ -446,8 +453,9 @@ pub fn handle_folding_range(
446 .into_iter() 453 .into_iter()
447 .map(|fold| { 454 .map(|fold| {
448 let kind = match fold.kind { 455 let kind = match fold.kind {
449 FoldKind::Comment => FoldingRangeKind::Comment, 456 FoldKind::Comment => Some(FoldingRangeKind::Comment),
450 FoldKind::Imports => FoldingRangeKind::Imports, 457 FoldKind::Imports => Some(FoldingRangeKind::Imports),
458 FoldKind::Block => None,
451 }; 459 };
452 let range = fold.range.conv_with(&line_index); 460 let range = fold.range.conv_with(&line_index);
453 FoldingRange { 461 FoldingRange {
@@ -455,7 +463,7 @@ pub fn handle_folding_range(
455 start_character: Some(range.start.character), 463 start_character: Some(range.start.character),
456 end_line: range.end.line, 464 end_line: range.end.line,
457 end_character: Some(range.start.character), 465 end_character: Some(range.start.character),
458 kind: Some(kind), 466 kind,
459 } 467 }
460 }) 468 })
461 .collect(), 469 .collect(),
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index 785877c4b..73cccc9dd 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -8,7 +8,7 @@ use ra_analysis::{
8 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, 8 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData,
9 SourceRootId 9 SourceRootId
10}; 10};
11use ra_vfs::{Vfs, VfsChange, VfsFile}; 11use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot};
12use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
13use relative_path::RelativePathBuf; 13use relative_path::RelativePathBuf;
14use parking_lot::RwLock; 14use parking_lot::RwLock;
@@ -183,4 +183,12 @@ impl ServerWorld {
183 .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; 183 .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
184 Ok(url) 184 Ok(url)
185 } 185 }
186
187 pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
188 let base = self.vfs.read().root2path(VfsRoot(root.0));
189 let path = path.to_path(base);
190 let url = Url::from_file_path(&path)
191 .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
192 Ok(url)
193 }
186} 194}
diff --git a/crates/ra_text_edit/src/text_edit.rs b/crates/ra_text_edit/src/text_edit.rs
index fb46f046d..392968d63 100644
--- a/crates/ra_text_edit/src/text_edit.rs
+++ b/crates/ra_text_edit/src/text_edit.rs
@@ -41,8 +41,8 @@ impl TextEditBuilder {
41} 41}
42 42
43impl TextEdit { 43impl TextEdit {
44 pub fn into_atoms(self) -> Vec<AtomTextEdit> { 44 pub fn as_atoms(&self) -> &[AtomTextEdit] {
45 self.atoms 45 &self.atoms
46 } 46 }
47 47
48 pub fn apply(&self, text: &str) -> String { 48 pub fn apply(&self, text: &str) -> String {
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 0a94adb74..1ae800d7c 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -66,15 +66,40 @@ pub fn try_extract_range(text: &str) -> Option<(TextRange, String)> {
66 Some((TextRange::from_to(start, end), text)) 66 Some((TextRange::from_to(start, end), text))
67} 67}
68 68
69pub fn extract_ranges(text: &str) -> (Vec<TextRange>, String) { 69/// Extracts ranges, marked with `<tag> </tag>` paris from the `text`
70pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
71 let open = format!("<{}>", tag);
72 let close = format!("</{}>", tag);
70 let mut ranges = Vec::new(); 73 let mut ranges = Vec::new();
71 let mut text = String::from(text); 74 let mut res = String::new();
72 while let Some((range, new_text)) = try_extract_range(&text) { 75 let mut stack = Vec::new();
73 text = new_text; 76 loop {
74 ranges.push(range); 77 match text.find('<') {
78 None => {
79 res.push_str(text);
80 break;
81 }
82 Some(i) => {
83 res.push_str(&text[..i]);
84 text = &text[i..];
85 if text.starts_with(&open) {
86 text = &text[open.len()..];
87 let from = TextUnit::of_str(&res);
88 stack.push(from);
89 } else if text.starts_with(&close) {
90 text = &text[close.len()..];
91 let from = stack
92 .pop()
93 .unwrap_or_else(|| panic!("unmatched </{}>", tag));
94 let to = TextUnit::of_str(&res);
95 ranges.push(TextRange::from_to(from, to));
96 }
97 }
98 }
75 } 99 }
76 100 assert!(stack.is_empty(), "unmatched <{}>", tag);
77 (ranges, text) 101 ranges.sort_by_key(|r| (r.start(), r.end()));
102 (ranges, res)
78} 103}
79 104
80pub fn add_cursor(text: &str, offset: TextUnit) -> String { 105pub fn add_cursor(text: &str, offset: TextUnit) -> String {
diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs
index 580d8b802..2795afe0b 100644
--- a/crates/tools/src/lib.rs
+++ b/crates/tools/src/lib.rs
@@ -15,7 +15,7 @@ pub type Result<T> = std::result::Result<T, failure::Error>;
15pub const GRAMMAR: &str = "crates/ra_syntax/src/grammar.ron"; 15pub const GRAMMAR: &str = "crates/ra_syntax/src/grammar.ron";
16pub const SYNTAX_KINDS: &str = "crates/ra_syntax/src/syntax_kinds/generated.rs.tera"; 16pub const SYNTAX_KINDS: &str = "crates/ra_syntax/src/syntax_kinds/generated.rs.tera";
17pub const AST: &str = "crates/ra_syntax/src/ast/generated.rs.tera"; 17pub const AST: &str = "crates/ra_syntax/src/ast/generated.rs.tera";
18const TOOLCHAIN: &str = "1.31.0"; 18const TOOLCHAIN: &str = "1.31.1";
19 19
20#[derive(Debug)] 20#[derive(Debug)]
21pub struct Test { 21pub struct Test {