aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/main_loop.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-06-25 08:51:54 +0100
committerGitHub <[email protected]>2020-06-25 08:51:54 +0100
commit193ea7cf9af8c501035445b42847b6e80b33751a (patch)
treeb455e9193b7bb383cb1f27d58c416d57e9035b2c /crates/rust-analyzer/src/main_loop.rs
parent0d2e695ffcd1e96cd3a6603a1d5f387f5bcfbf2e (diff)
parent1ccf33d88f06603bb95811237f4c297c4fa2f7e9 (diff)
Merge #5052
5052: Minor, move code r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/rust-analyzer/src/main_loop.rs')
-rw-r--r--crates/rust-analyzer/src/main_loop.rs126
1 files changed, 7 insertions, 119 deletions
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 200641cd5..3b3b83209 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -1,18 +1,16 @@
1//! The main loop of `rust-analyzer` responsible for dispatching LSP 1//! The main loop of `rust-analyzer` responsible for dispatching LSP
2//! requests/replies and notifications back to the client. 2//! requests/replies and notifications back to the client.
3use std::{ 3use std::{
4 env, fmt, 4 env, fmt, panic,
5 ops::Range,
6 panic,
7 sync::Arc, 5 sync::Arc,
8 time::{Duration, Instant}, 6 time::{Duration, Instant},
9}; 7};
10 8
11use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; 9use crossbeam_channel::{never, select, unbounded, RecvError, Sender};
12use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 10use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
13use lsp_types::{request::Request as _, NumberOrString, TextDocumentContentChangeEvent}; 11use lsp_types::{request::Request as _, NumberOrString};
14use ra_db::VfsPath; 12use ra_db::VfsPath;
15use ra_ide::{Canceled, FileId, LineIndex}; 13use ra_ide::{Canceled, FileId};
16use ra_prof::profile; 14use ra_prof::profile;
17use ra_project_model::{PackageRoot, ProjectWorkspace}; 15use ra_project_model::{PackageRoot, ProjectWorkspace};
18use serde::{de::DeserializeOwned, Serialize}; 16use serde::{de::DeserializeOwned, Serialize};
@@ -24,7 +22,10 @@ use crate::{
24 from_proto, 22 from_proto,
25 global_state::{file_id_to_url, GlobalState, GlobalStateSnapshot, Status}, 23 global_state::{file_id_to_url, GlobalState, GlobalStateSnapshot, Status},
26 handlers, lsp_ext, 24 handlers, lsp_ext,
27 lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, show_message}, 25 lsp_utils::{
26 apply_document_changes, is_canceled, notification_cast, notification_is, notification_new,
27 show_message,
28 },
28 request_metrics::RequestMetrics, 29 request_metrics::RequestMetrics,
29 LspError, Result, 30 LspError, Result,
30}; 31};
@@ -548,49 +549,6 @@ fn on_notification(
548 Ok(()) 549 Ok(())
549} 550}
550 551
551fn apply_document_changes(
552 old_text: &mut String,
553 content_changes: Vec<TextDocumentContentChangeEvent>,
554) {
555 let mut line_index = LineIndex::new(old_text);
556 // The changes we got must be applied sequentially, but can cross lines so we
557 // have to keep our line index updated.
558 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
559 // remember the last valid line in the index and only rebuild it if needed.
560 // The VFS will normalize the end of lines to `\n`.
561 enum IndexValid {
562 All,
563 UpToLineExclusive(u64),
564 }
565
566 impl IndexValid {
567 fn covers(&self, line: u64) -> bool {
568 match *self {
569 IndexValid::UpToLineExclusive(to) => to > line,
570 _ => true,
571 }
572 }
573 }
574
575 let mut index_valid = IndexValid::All;
576 for change in content_changes {
577 match change.range {
578 Some(range) => {
579 if !index_valid.covers(range.end.line) {
580 line_index = LineIndex::new(&old_text);
581 }
582 index_valid = IndexValid::UpToLineExclusive(range.start.line);
583 let range = from_proto::text_range(&line_index, range);
584 old_text.replace_range(Range::<usize>::from(range), &change.text);
585 }
586 None => {
587 *old_text = change.text;
588 index_valid = IndexValid::UpToLineExclusive(0);
589 }
590 }
591 }
592}
593
594fn on_check_task( 552fn on_check_task(
595 task: flycheck::Message, 553 task: flycheck::Message,
596 global_state: &mut GlobalState, 554 global_state: &mut GlobalState,
@@ -862,73 +820,3 @@ fn update_file_notifications_on_threadpool(
862 }) 820 })
863 } 821 }
864} 822}
865
866#[cfg(test)]
867mod tests {
868 use lsp_types::{Position, Range, TextDocumentContentChangeEvent};
869
870 use super::*;
871
872 #[test]
873 fn test_apply_document_changes() {
874 macro_rules! c {
875 [$($sl:expr, $sc:expr; $el:expr, $ec:expr => $text:expr),+] => {
876 vec![$(TextDocumentContentChangeEvent {
877 range: Some(Range {
878 start: Position { line: $sl, character: $sc },
879 end: Position { line: $el, character: $ec },
880 }),
881 range_length: None,
882 text: String::from($text),
883 }),+]
884 };
885 }
886
887 let mut text = String::new();
888 apply_document_changes(&mut text, vec![]);
889 assert_eq!(text, "");
890 apply_document_changes(
891 &mut text,
892 vec![TextDocumentContentChangeEvent {
893 range: None,
894 range_length: None,
895 text: String::from("the"),
896 }],
897 );
898 assert_eq!(text, "the");
899 apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]);
900 assert_eq!(text, "the quick");
901 apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
902 assert_eq!(text, "quick foxes");
903 apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]);
904 assert_eq!(text, "quick foxes\ndream");
905 apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]);
906 assert_eq!(text, "quick foxes\nhave dream");
907 apply_document_changes(
908 &mut text,
909 c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"],
910 );
911 assert_eq!(text, "the quick foxes\nhave quiet dreams\n");
912 apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
913 assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
914 apply_document_changes(
915 &mut text,
916 c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"],
917 );
918 assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n");
919 apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
920 assert_eq!(text, "the quick \nthey have quiet dreams\n");
921
922 text = String::from("❤️");
923 apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]);
924 assert_eq!(text, "a❤️");
925
926 text = String::from("a\nb");
927 apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
928 assert_eq!(text, "adcb");
929
930 text = String::from("a\nb");
931 apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
932 assert_eq!(text, "ațc\ncb");
933 }
934}