diff options
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/conv.rs | 150 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 6 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/world.rs | 6 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/main.rs | 48 |
5 files changed, 123 insertions, 89 deletions
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index 2c69a6993..afeac0d8a 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -16,7 +16,7 @@ lsp-types = { version = "0.60.0", features = ["proposed"] } | |||
16 | rustc-hash = "1.0" | 16 | rustc-hash = "1.0" |
17 | parking_lot = "0.9.0" | 17 | parking_lot = "0.9.0" |
18 | 18 | ||
19 | ra_vfs = "0.2.0" | 19 | ra_vfs = "0.2.7" |
20 | thread_worker = { path = "../thread_worker" } | 20 | thread_worker = { path = "../thread_worker" } |
21 | ra_syntax = { path = "../ra_syntax" } | 21 | ra_syntax = { path = "../ra_syntax" } |
22 | ra_text_edit = { path = "../ra_text_edit" } | 22 | ra_text_edit = { path = "../ra_text_edit" } |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index df8ea6e0d..0ad2ea10f 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -11,6 +11,7 @@ use ra_ide_api::{ | |||
11 | }; | 11 | }; |
12 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; | 12 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; |
13 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 13 | use ra_text_edit::{AtomTextEdit, TextEdit}; |
14 | use ra_vfs::LineEndings; | ||
14 | 15 | ||
15 | use crate::{req, world::WorldSnapshot, Result}; | 16 | use crate::{req, world::WorldSnapshot, Result}; |
16 | 17 | ||
@@ -19,16 +20,14 @@ pub trait Conv { | |||
19 | fn conv(self) -> Self::Output; | 20 | fn conv(self) -> Self::Output; |
20 | } | 21 | } |
21 | 22 | ||
22 | pub trait ConvWith { | 23 | pub trait ConvWith<CTX> { |
23 | type Ctx; | ||
24 | type Output; | 24 | type Output; |
25 | fn conv_with(self, ctx: &Self::Ctx) -> Self::Output; | 25 | fn conv_with(self, ctx: CTX) -> Self::Output; |
26 | } | 26 | } |
27 | 27 | ||
28 | pub trait TryConvWith { | 28 | pub trait TryConvWith<CTX> { |
29 | type Ctx; | ||
30 | type Output; | 29 | type Output; |
31 | fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output>; | 30 | fn try_conv_with(self, ctx: CTX) -> Result<Self::Output>; |
32 | } | 31 | } |
33 | 32 | ||
34 | impl Conv for SyntaxKind { | 33 | impl Conv for SyntaxKind { |
@@ -89,11 +88,10 @@ impl Conv for Severity { | |||
89 | } | 88 | } |
90 | } | 89 | } |
91 | 90 | ||
92 | impl ConvWith for CompletionItem { | 91 | impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem { |
93 | type Ctx = LineIndex; | ||
94 | type Output = ::lsp_types::CompletionItem; | 92 | type Output = ::lsp_types::CompletionItem; |
95 | 93 | ||
96 | fn conv_with(self, ctx: &LineIndex) -> ::lsp_types::CompletionItem { | 94 | fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> ::lsp_types::CompletionItem { |
97 | let mut additional_text_edits = Vec::new(); | 95 | let mut additional_text_edits = Vec::new(); |
98 | let mut text_edit = None; | 96 | let mut text_edit = None; |
99 | // LSP does not allow arbitrary edits in completion, so we have to do a | 97 | // LSP does not allow arbitrary edits in completion, so we have to do a |
@@ -138,8 +136,7 @@ impl ConvWith for CompletionItem { | |||
138 | } | 136 | } |
139 | } | 137 | } |
140 | 138 | ||
141 | impl ConvWith for Position { | 139 | impl ConvWith<&LineIndex> for Position { |
142 | type Ctx = LineIndex; | ||
143 | type Output = TextUnit; | 140 | type Output = TextUnit; |
144 | 141 | ||
145 | fn conv_with(self, line_index: &LineIndex) -> TextUnit { | 142 | fn conv_with(self, line_index: &LineIndex) -> TextUnit { |
@@ -148,8 +145,7 @@ impl ConvWith for Position { | |||
148 | } | 145 | } |
149 | } | 146 | } |
150 | 147 | ||
151 | impl ConvWith for TextUnit { | 148 | impl ConvWith<&LineIndex> for TextUnit { |
152 | type Ctx = LineIndex; | ||
153 | type Output = Position; | 149 | type Output = Position; |
154 | 150 | ||
155 | fn conv_with(self, line_index: &LineIndex) -> Position { | 151 | fn conv_with(self, line_index: &LineIndex) -> Position { |
@@ -158,8 +154,7 @@ impl ConvWith for TextUnit { | |||
158 | } | 154 | } |
159 | } | 155 | } |
160 | 156 | ||
161 | impl ConvWith for TextRange { | 157 | impl ConvWith<&LineIndex> for TextRange { |
162 | type Ctx = LineIndex; | ||
163 | type Output = Range; | 158 | type Output = Range; |
164 | 159 | ||
165 | fn conv_with(self, line_index: &LineIndex) -> Range { | 160 | fn conv_with(self, line_index: &LineIndex) -> Range { |
@@ -167,8 +162,7 @@ impl ConvWith for TextRange { | |||
167 | } | 162 | } |
168 | } | 163 | } |
169 | 164 | ||
170 | impl ConvWith for Range { | 165 | impl ConvWith<&LineIndex> for Range { |
171 | type Ctx = LineIndex; | ||
172 | type Output = TextRange; | 166 | type Output = TextRange; |
173 | 167 | ||
174 | fn conv_with(self, line_index: &LineIndex) -> TextRange { | 168 | fn conv_with(self, line_index: &LineIndex) -> TextRange { |
@@ -208,77 +202,73 @@ impl Conv for ra_ide_api::FunctionSignature { | |||
208 | } | 202 | } |
209 | } | 203 | } |
210 | 204 | ||
211 | impl ConvWith for TextEdit { | 205 | impl ConvWith<(&LineIndex, LineEndings)> for TextEdit { |
212 | type Ctx = LineIndex; | ||
213 | type Output = Vec<lsp_types::TextEdit>; | 206 | type Output = Vec<lsp_types::TextEdit>; |
214 | 207 | ||
215 | fn conv_with(self, line_index: &LineIndex) -> Vec<lsp_types::TextEdit> { | 208 | fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> Vec<lsp_types::TextEdit> { |
216 | self.as_atoms().iter().map_conv_with(line_index).collect() | 209 | self.as_atoms().iter().map_conv_with(ctx).collect() |
217 | } | 210 | } |
218 | } | 211 | } |
219 | 212 | ||
220 | impl<'a> ConvWith for &'a AtomTextEdit { | 213 | impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit { |
221 | type Ctx = LineIndex; | ||
222 | type Output = lsp_types::TextEdit; | 214 | type Output = lsp_types::TextEdit; |
223 | 215 | ||
224 | fn conv_with(self, line_index: &LineIndex) -> lsp_types::TextEdit { | 216 | fn conv_with( |
225 | lsp_types::TextEdit { | 217 | self, |
226 | range: self.delete.conv_with(line_index), | 218 | (line_index, line_endings): (&LineIndex, LineEndings), |
227 | new_text: self.insert.clone(), | 219 | ) -> lsp_types::TextEdit { |
220 | let mut new_text = self.insert.clone(); | ||
221 | if line_endings == LineEndings::Dos { | ||
222 | new_text = new_text.replace('\n', "\r\n"); | ||
228 | } | 223 | } |
224 | lsp_types::TextEdit { range: self.delete.conv_with(line_index), new_text } | ||
229 | } | 225 | } |
230 | } | 226 | } |
231 | 227 | ||
232 | impl<T: ConvWith> ConvWith for Option<T> { | 228 | impl<T: ConvWith<CTX>, CTX> ConvWith<CTX> for Option<T> { |
233 | type Ctx = <T as ConvWith>::Ctx; | 229 | type Output = Option<T::Output>; |
234 | type Output = Option<<T as ConvWith>::Output>; | 230 | |
235 | fn conv_with(self, ctx: &Self::Ctx) -> Self::Output { | 231 | fn conv_with(self, ctx: CTX) -> Self::Output { |
236 | self.map(|x| ConvWith::conv_with(x, ctx)) | 232 | self.map(|x| ConvWith::conv_with(x, ctx)) |
237 | } | 233 | } |
238 | } | 234 | } |
239 | 235 | ||
240 | impl<'a> TryConvWith for &'a Url { | 236 | impl TryConvWith<&WorldSnapshot> for &Url { |
241 | type Ctx = WorldSnapshot; | ||
242 | type Output = FileId; | 237 | type Output = FileId; |
243 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { | 238 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { |
244 | world.uri_to_file_id(self) | 239 | world.uri_to_file_id(self) |
245 | } | 240 | } |
246 | } | 241 | } |
247 | 242 | ||
248 | impl TryConvWith for FileId { | 243 | impl TryConvWith<&WorldSnapshot> for FileId { |
249 | type Ctx = WorldSnapshot; | ||
250 | type Output = Url; | 244 | type Output = Url; |
251 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<Url> { | 245 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<Url> { |
252 | world.file_id_to_uri(self) | 246 | world.file_id_to_uri(self) |
253 | } | 247 | } |
254 | } | 248 | } |
255 | 249 | ||
256 | impl<'a> TryConvWith for &'a TextDocumentItem { | 250 | impl TryConvWith<&WorldSnapshot> for &TextDocumentItem { |
257 | type Ctx = WorldSnapshot; | ||
258 | type Output = FileId; | 251 | type Output = FileId; |
259 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { | 252 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { |
260 | self.uri.try_conv_with(world) | 253 | self.uri.try_conv_with(world) |
261 | } | 254 | } |
262 | } | 255 | } |
263 | 256 | ||
264 | impl<'a> TryConvWith for &'a VersionedTextDocumentIdentifier { | 257 | impl TryConvWith<&WorldSnapshot> for &VersionedTextDocumentIdentifier { |
265 | type Ctx = WorldSnapshot; | ||
266 | type Output = FileId; | 258 | type Output = FileId; |
267 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { | 259 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { |
268 | self.uri.try_conv_with(world) | 260 | self.uri.try_conv_with(world) |
269 | } | 261 | } |
270 | } | 262 | } |
271 | 263 | ||
272 | impl<'a> TryConvWith for &'a TextDocumentIdentifier { | 264 | impl TryConvWith<&WorldSnapshot> for &TextDocumentIdentifier { |
273 | type Ctx = WorldSnapshot; | ||
274 | type Output = FileId; | 265 | type Output = FileId; |
275 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { | 266 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileId> { |
276 | world.uri_to_file_id(&self.uri) | 267 | world.uri_to_file_id(&self.uri) |
277 | } | 268 | } |
278 | } | 269 | } |
279 | 270 | ||
280 | impl<'a> TryConvWith for &'a TextDocumentPositionParams { | 271 | impl TryConvWith<&WorldSnapshot> for &TextDocumentPositionParams { |
281 | type Ctx = WorldSnapshot; | ||
282 | type Output = FilePosition; | 272 | type Output = FilePosition; |
283 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FilePosition> { | 273 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FilePosition> { |
284 | let file_id = self.text_document.try_conv_with(world)?; | 274 | let file_id = self.text_document.try_conv_with(world)?; |
@@ -288,8 +278,7 @@ impl<'a> TryConvWith for &'a TextDocumentPositionParams { | |||
288 | } | 278 | } |
289 | } | 279 | } |
290 | 280 | ||
291 | impl<'a> TryConvWith for (&'a TextDocumentIdentifier, Range) { | 281 | impl TryConvWith<&WorldSnapshot> for (&TextDocumentIdentifier, Range) { |
292 | type Ctx = WorldSnapshot; | ||
293 | type Output = FileRange; | 282 | type Output = FileRange; |
294 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileRange> { | 283 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<FileRange> { |
295 | let file_id = self.0.try_conv_with(world)?; | 284 | let file_id = self.0.try_conv_with(world)?; |
@@ -299,10 +288,9 @@ impl<'a> TryConvWith for (&'a TextDocumentIdentifier, Range) { | |||
299 | } | 288 | } |
300 | } | 289 | } |
301 | 290 | ||
302 | impl<T: TryConvWith> TryConvWith for Vec<T> { | 291 | impl<T: TryConvWith<CTX>, CTX: Copy> TryConvWith<CTX> for Vec<T> { |
303 | type Ctx = <T as TryConvWith>::Ctx; | 292 | type Output = Vec<<T as TryConvWith<CTX>>::Output>; |
304 | type Output = Vec<<T as TryConvWith>::Output>; | 293 | fn try_conv_with(self, ctx: CTX) -> Result<Self::Output> { |
305 | fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output> { | ||
306 | let mut res = Vec::with_capacity(self.len()); | 294 | let mut res = Vec::with_capacity(self.len()); |
307 | for item in self { | 295 | for item in self { |
308 | res.push(item.try_conv_with(ctx)?); | 296 | res.push(item.try_conv_with(ctx)?); |
@@ -311,8 +299,7 @@ impl<T: TryConvWith> TryConvWith for Vec<T> { | |||
311 | } | 299 | } |
312 | } | 300 | } |
313 | 301 | ||
314 | impl TryConvWith for SourceChange { | 302 | impl TryConvWith<&WorldSnapshot> for SourceChange { |
315 | type Ctx = WorldSnapshot; | ||
316 | type Output = req::SourceChange; | 303 | type Output = req::SourceChange; |
317 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<req::SourceChange> { | 304 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<req::SourceChange> { |
318 | let cursor_position = match self.cursor_position { | 305 | let cursor_position = match self.cursor_position { |
@@ -351,8 +338,7 @@ impl TryConvWith for SourceChange { | |||
351 | } | 338 | } |
352 | } | 339 | } |
353 | 340 | ||
354 | impl TryConvWith for SourceFileEdit { | 341 | impl TryConvWith<&WorldSnapshot> for SourceFileEdit { |
355 | type Ctx = WorldSnapshot; | ||
356 | type Output = TextDocumentEdit; | 342 | type Output = TextDocumentEdit; |
357 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<TextDocumentEdit> { | 343 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<TextDocumentEdit> { |
358 | let text_document = VersionedTextDocumentIdentifier { | 344 | let text_document = VersionedTextDocumentIdentifier { |
@@ -360,13 +346,14 @@ impl TryConvWith for SourceFileEdit { | |||
360 | version: None, | 346 | version: None, |
361 | }; | 347 | }; |
362 | let line_index = world.analysis().file_line_index(self.file_id)?; | 348 | let line_index = world.analysis().file_line_index(self.file_id)?; |
363 | let edits = self.edit.as_atoms().iter().map_conv_with(&line_index).collect(); | 349 | let line_endings = world.file_line_endings(self.file_id); |
350 | let edits = | ||
351 | self.edit.as_atoms().iter().map_conv_with((&line_index, line_endings)).collect(); | ||
364 | Ok(TextDocumentEdit { text_document, edits }) | 352 | Ok(TextDocumentEdit { text_document, edits }) |
365 | } | 353 | } |
366 | } | 354 | } |
367 | 355 | ||
368 | impl TryConvWith for FileSystemEdit { | 356 | impl TryConvWith<&WorldSnapshot> for FileSystemEdit { |
369 | type Ctx = WorldSnapshot; | ||
370 | type Output = ResourceOp; | 357 | type Output = ResourceOp; |
371 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<ResourceOp> { | 358 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<ResourceOp> { |
372 | let res = match self { | 359 | let res = match self { |
@@ -384,8 +371,7 @@ impl TryConvWith for FileSystemEdit { | |||
384 | } | 371 | } |
385 | } | 372 | } |
386 | 373 | ||
387 | impl TryConvWith for &NavigationTarget { | 374 | impl TryConvWith<&WorldSnapshot> for &NavigationTarget { |
388 | type Ctx = WorldSnapshot; | ||
389 | type Output = Location; | 375 | type Output = Location; |
390 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<Location> { | 376 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<Location> { |
391 | let line_index = world.analysis().file_line_index(self.file_id())?; | 377 | let line_index = world.analysis().file_line_index(self.file_id())?; |
@@ -394,8 +380,7 @@ impl TryConvWith for &NavigationTarget { | |||
394 | } | 380 | } |
395 | } | 381 | } |
396 | 382 | ||
397 | impl TryConvWith for (FileId, RangeInfo<NavigationTarget>) { | 383 | impl TryConvWith<&WorldSnapshot> for (FileId, RangeInfo<NavigationTarget>) { |
398 | type Ctx = WorldSnapshot; | ||
399 | type Output = LocationLink; | 384 | type Output = LocationLink; |
400 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<LocationLink> { | 385 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<LocationLink> { |
401 | let (src_file_id, target) = self; | 386 | let (src_file_id, target) = self; |
@@ -422,8 +407,7 @@ impl TryConvWith for (FileId, RangeInfo<NavigationTarget>) { | |||
422 | } | 407 | } |
423 | } | 408 | } |
424 | 409 | ||
425 | impl TryConvWith for (FileId, RangeInfo<Vec<NavigationTarget>>) { | 410 | impl TryConvWith<&WorldSnapshot> for (FileId, RangeInfo<Vec<NavigationTarget>>) { |
426 | type Ctx = WorldSnapshot; | ||
427 | type Output = req::GotoDefinitionResponse; | 411 | type Output = req::GotoDefinitionResponse; |
428 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<req::GotoTypeDefinitionResponse> { | 412 | fn try_conv_with(self, world: &WorldSnapshot) -> Result<req::GotoTypeDefinitionResponse> { |
429 | let (file_id, RangeInfo { range, info: navs }) = self; | 413 | let (file_id, RangeInfo { range, info: navs }) = self; |
@@ -454,57 +438,55 @@ pub fn to_location( | |||
454 | Ok(loc) | 438 | Ok(loc) |
455 | } | 439 | } |
456 | 440 | ||
457 | pub trait MapConvWith<'a>: Sized + 'a { | 441 | pub trait MapConvWith<CTX>: Sized { |
458 | type Ctx; | ||
459 | type Output; | 442 | type Output; |
460 | 443 | ||
461 | fn map_conv_with(self, ctx: &'a Self::Ctx) -> ConvWithIter<'a, Self, Self::Ctx> { | 444 | fn map_conv_with(self, ctx: CTX) -> ConvWithIter<Self, CTX> { |
462 | ConvWithIter { iter: self, ctx } | 445 | ConvWithIter { iter: self, ctx } |
463 | } | 446 | } |
464 | } | 447 | } |
465 | 448 | ||
466 | impl<'a, I> MapConvWith<'a> for I | 449 | impl<CTX, I> MapConvWith<CTX> for I |
467 | where | 450 | where |
468 | I: Iterator + 'a, | 451 | I: Iterator, |
469 | I::Item: ConvWith, | 452 | I::Item: ConvWith<CTX>, |
470 | { | 453 | { |
471 | type Ctx = <I::Item as ConvWith>::Ctx; | 454 | type Output = <I::Item as ConvWith<CTX>>::Output; |
472 | type Output = <I::Item as ConvWith>::Output; | ||
473 | } | 455 | } |
474 | 456 | ||
475 | pub struct ConvWithIter<'a, I, Ctx: 'a> { | 457 | pub struct ConvWithIter<I, CTX> { |
476 | iter: I, | 458 | iter: I, |
477 | ctx: &'a Ctx, | 459 | ctx: CTX, |
478 | } | 460 | } |
479 | 461 | ||
480 | impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx> | 462 | impl<I, CTX> Iterator for ConvWithIter<I, CTX> |
481 | where | 463 | where |
482 | I: Iterator, | 464 | I: Iterator, |
483 | I::Item: ConvWith<Ctx = Ctx>, | 465 | I::Item: ConvWith<CTX>, |
466 | CTX: Copy, | ||
484 | { | 467 | { |
485 | type Item = <I::Item as ConvWith>::Output; | 468 | type Item = <I::Item as ConvWith<CTX>>::Output; |
486 | 469 | ||
487 | fn next(&mut self) -> Option<Self::Item> { | 470 | fn next(&mut self) -> Option<Self::Item> { |
488 | self.iter.next().map(|item| item.conv_with(self.ctx)) | 471 | self.iter.next().map(|item| item.conv_with(self.ctx)) |
489 | } | 472 | } |
490 | } | 473 | } |
491 | 474 | ||
492 | pub trait TryConvWithToVec<'a>: Sized + 'a { | 475 | pub trait TryConvWithToVec<CTX>: Sized { |
493 | type Ctx; | ||
494 | type Output; | 476 | type Output; |
495 | 477 | ||
496 | fn try_conv_with_to_vec(self, ctx: &'a Self::Ctx) -> Result<Vec<Self::Output>>; | 478 | fn try_conv_with_to_vec(self, ctx: CTX) -> Result<Vec<Self::Output>>; |
497 | } | 479 | } |
498 | 480 | ||
499 | impl<'a, I> TryConvWithToVec<'a> for I | 481 | impl<I, CTX> TryConvWithToVec<CTX> for I |
500 | where | 482 | where |
501 | I: Iterator + 'a, | 483 | I: Iterator, |
502 | I::Item: TryConvWith, | 484 | I::Item: TryConvWith<CTX>, |
485 | CTX: Copy, | ||
503 | { | 486 | { |
504 | type Ctx = <I::Item as TryConvWith>::Ctx; | 487 | type Output = <I::Item as TryConvWith<CTX>>::Output; |
505 | type Output = <I::Item as TryConvWith>::Output; | ||
506 | 488 | ||
507 | fn try_conv_with_to_vec(self, ctx: &'a Self::Ctx) -> Result<Vec<Self::Output>> { | 489 | fn try_conv_with_to_vec(self, ctx: CTX) -> Result<Vec<Self::Output>> { |
508 | self.map(|it| it.try_conv_with(ctx)).collect() | 490 | self.map(|it| it.try_conv_with(ctx)).collect() |
509 | } | 491 | } |
510 | } | 492 | } |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index b465707f8..3a559e845 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -138,6 +138,7 @@ pub fn handle_on_type_formatting( | |||
138 | let _p = profile("handle_on_type_formatting"); | 138 | let _p = profile("handle_on_type_formatting"); |
139 | let mut position = params.text_document_position.try_conv_with(&world)?; | 139 | let mut position = params.text_document_position.try_conv_with(&world)?; |
140 | let line_index = world.analysis().file_line_index(position.file_id)?; | 140 | let line_index = world.analysis().file_line_index(position.file_id)?; |
141 | let line_endings = world.file_line_endings(position.file_id); | ||
141 | 142 | ||
142 | // in `ra_ide_api`, the `on_type` invariant is that | 143 | // in `ra_ide_api`, the `on_type` invariant is that |
143 | // `text.char_at(position) == typed_char`. | 144 | // `text.char_at(position) == typed_char`. |
@@ -156,7 +157,7 @@ pub fn handle_on_type_formatting( | |||
156 | // This should be a single-file edit | 157 | // This should be a single-file edit |
157 | let edit = edit.source_file_edits.pop().unwrap(); | 158 | let edit = edit.source_file_edits.pop().unwrap(); |
158 | 159 | ||
159 | let change: Vec<TextEdit> = edit.edit.conv_with(&line_index); | 160 | let change: Vec<TextEdit> = edit.edit.conv_with((&line_index, line_endings)); |
160 | Ok(Some(change)) | 161 | Ok(Some(change)) |
161 | } | 162 | } |
162 | 163 | ||
@@ -370,8 +371,9 @@ pub fn handle_completion( | |||
370 | Some(items) => items, | 371 | Some(items) => items, |
371 | }; | 372 | }; |
372 | let line_index = world.analysis().file_line_index(position.file_id)?; | 373 | let line_index = world.analysis().file_line_index(position.file_id)?; |
374 | let line_endings = world.file_line_endings(position.file_id); | ||
373 | let items: Vec<CompletionItem> = | 375 | let items: Vec<CompletionItem> = |
374 | items.into_iter().map(|item| item.conv_with(&line_index)).collect(); | 376 | items.into_iter().map(|item| item.conv_with((&line_index, line_endings))).collect(); |
375 | 377 | ||
376 | Ok(Some(items.into())) | 378 | Ok(Some(items.into())) |
377 | } | 379 | } |
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs index 9990ef62e..10f96812f 100644 --- a/crates/ra_lsp_server/src/world.rs +++ b/crates/ra_lsp_server/src/world.rs | |||
@@ -9,7 +9,7 @@ use parking_lot::RwLock; | |||
9 | use ra_ide_api::{ | 9 | use ra_ide_api::{ |
10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, | 10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, |
11 | }; | 11 | }; |
12 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsFile, VfsRoot}; | 12 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot}; |
13 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; | 13 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; |
14 | use relative_path::RelativePathBuf; | 14 | use relative_path::RelativePathBuf; |
15 | 15 | ||
@@ -210,6 +210,10 @@ impl WorldSnapshot { | |||
210 | Ok(url) | 210 | Ok(url) |
211 | } | 211 | } |
212 | 212 | ||
213 | pub fn file_line_endings(&self, id: FileId) -> LineEndings { | ||
214 | self.vfs.read().file_line_endings(VfsFile(id.0)) | ||
215 | } | ||
216 | |||
213 | pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> { | 217 | pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> { |
214 | let base = self.vfs.read().root2path(VfsRoot(root.0)); | 218 | let base = self.vfs.read().root2path(VfsRoot(root.0)); |
215 | let path = path.to_path(base); | 219 | let path = path.to_path(base); |
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index de3bd5bc5..152681062 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs | |||
@@ -208,7 +208,7 @@ pub use std::collections::HashMap; | |||
208 | "range": { | 208 | "range": { |
209 | "end": { | 209 | "end": { |
210 | "character": 0, | 210 | "character": 0, |
211 | "line": 6 | 211 | "line": 7 |
212 | }, | 212 | }, |
213 | "start": { | 213 | "start": { |
214 | "character": 0, | 214 | "character": 0, |
@@ -414,3 +414,49 @@ fn main() {{}} | |||
414 | let elapsed = start.elapsed(); | 414 | let elapsed = start.elapsed(); |
415 | assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed); | 415 | assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed); |
416 | } | 416 | } |
417 | |||
418 | #[test] | ||
419 | fn preserves_dos_line_endings() { | ||
420 | let server = Project::with_fixture( | ||
421 | &" | ||
422 | //- Cargo.toml | ||
423 | [package] | ||
424 | name = \"foo\" | ||
425 | version = \"0.0.0\" | ||
426 | |||
427 | //- src/main.rs | ||
428 | /// Some Docs\r\nfn main() {} | ||
429 | ", | ||
430 | ) | ||
431 | .server(); | ||
432 | |||
433 | server.request::<OnEnter>( | ||
434 | TextDocumentPositionParams { | ||
435 | text_document: server.doc_id("src/main.rs"), | ||
436 | position: Position { line: 0, character: 8 }, | ||
437 | }, | ||
438 | json!({ | ||
439 | "cursorPosition": { | ||
440 | "position": { "line": 1, "character": 4 }, | ||
441 | "textDocument": { "uri": "file:///[..]src/main.rs" } | ||
442 | }, | ||
443 | "label": "on enter", | ||
444 | "workspaceEdit": { | ||
445 | "documentChanges": [ | ||
446 | { | ||
447 | "edits": [ | ||
448 | { | ||
449 | "newText": "\r\n/// ", | ||
450 | "range": { | ||
451 | "end": { "line": 0, "character": 8 }, | ||
452 | "start": { "line": 0, "character": 8 } | ||
453 | } | ||
454 | } | ||
455 | ], | ||
456 | "textDocument": { "uri": "file:///[..]src/main.rs", "version": null } | ||
457 | } | ||
458 | ] | ||
459 | } | ||
460 | }), | ||
461 | ); | ||
462 | } | ||