From 1ccf33d88f06603bb95811237f4c297c4fa2f7e9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 25 Jun 2020 09:51:30 +0200 Subject: Minor, move code --- crates/rust-analyzer/src/lsp_utils.rs | 117 ++++++++++++++++++++++++++++++- crates/rust-analyzer/src/main_loop.rs | 126 ++-------------------------------- 2 files changed, 123 insertions(+), 120 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 078f8778e..14adb8ae7 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -1,9 +1,11 @@ //! Utilities for LSP-related boilerplate code. -use std::error::Error; +use std::{error::Error, ops::Range}; +use crate::from_proto; use crossbeam_channel::Sender; use lsp_server::{Message, Notification}; use ra_db::Canceled; +use ra_ide::LineIndex; use serde::{de::DeserializeOwned, Serialize}; pub fn show_message( @@ -42,3 +44,116 @@ where { Notification::new(N::METHOD.to_string(), params) } + +pub(crate) fn apply_document_changes( + old_text: &mut String, + content_changes: Vec, +) { + let mut line_index = LineIndex::new(old_text); + // The changes we got must be applied sequentially, but can cross lines so we + // have to keep our line index updated. + // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we + // remember the last valid line in the index and only rebuild it if needed. + // The VFS will normalize the end of lines to `\n`. + enum IndexValid { + All, + UpToLineExclusive(u64), + } + + impl IndexValid { + fn covers(&self, line: u64) -> bool { + match *self { + IndexValid::UpToLineExclusive(to) => to > line, + _ => true, + } + } + } + + let mut index_valid = IndexValid::All; + for change in content_changes { + match change.range { + Some(range) => { + if !index_valid.covers(range.end.line) { + line_index = LineIndex::new(&old_text); + } + index_valid = IndexValid::UpToLineExclusive(range.start.line); + let range = from_proto::text_range(&line_index, range); + old_text.replace_range(Range::::from(range), &change.text); + } + None => { + *old_text = change.text; + index_valid = IndexValid::UpToLineExclusive(0); + } + } + } +} + +#[cfg(test)] +mod tests { + use lsp_types::{Position, Range, TextDocumentContentChangeEvent}; + + use super::*; + + #[test] + fn test_apply_document_changes() { + macro_rules! c { + [$($sl:expr, $sc:expr; $el:expr, $ec:expr => $text:expr),+] => { + vec![$(TextDocumentContentChangeEvent { + range: Some(Range { + start: Position { line: $sl, character: $sc }, + end: Position { line: $el, character: $ec }, + }), + range_length: None, + text: String::from($text), + }),+] + }; + } + + let mut text = String::new(); + apply_document_changes(&mut text, vec![]); + assert_eq!(text, ""); + apply_document_changes( + &mut text, + vec![TextDocumentContentChangeEvent { + range: None, + range_length: None, + text: String::from("the"), + }], + ); + assert_eq!(text, "the"); + apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]); + assert_eq!(text, "the quick"); + apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); + assert_eq!(text, "quick foxes"); + apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]); + assert_eq!(text, "quick foxes\ndream"); + apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]); + assert_eq!(text, "quick foxes\nhave dream"); + apply_document_changes( + &mut text, + c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"], + ); + assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); + apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); + assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); + apply_document_changes( + &mut text, + c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], + ); + assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); + apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); + assert_eq!(text, "the quick \nthey have quiet dreams\n"); + + text = String::from("❤️"); + apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]); + assert_eq!(text, "a❤️"); + + text = String::from("a\nb"); + apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); + assert_eq!(text, "adcb"); + + text = String::from("a\nb"); + apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); + assert_eq!(text, "ațc\ncb"); + } +} 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 @@ //! The main loop of `rust-analyzer` responsible for dispatching LSP //! requests/replies and notifications back to the client. use std::{ - env, fmt, - ops::Range, - panic, + env, fmt, panic, sync::Arc, time::{Duration, Instant}, }; use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; -use lsp_types::{request::Request as _, NumberOrString, TextDocumentContentChangeEvent}; +use lsp_types::{request::Request as _, NumberOrString}; use ra_db::VfsPath; -use ra_ide::{Canceled, FileId, LineIndex}; +use ra_ide::{Canceled, FileId}; use ra_prof::profile; use ra_project_model::{PackageRoot, ProjectWorkspace}; use serde::{de::DeserializeOwned, Serialize}; @@ -24,7 +22,10 @@ use crate::{ from_proto, global_state::{file_id_to_url, GlobalState, GlobalStateSnapshot, Status}, handlers, lsp_ext, - lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, show_message}, + lsp_utils::{ + apply_document_changes, is_canceled, notification_cast, notification_is, notification_new, + show_message, + }, request_metrics::RequestMetrics, LspError, Result, }; @@ -548,49 +549,6 @@ fn on_notification( Ok(()) } -fn apply_document_changes( - old_text: &mut String, - content_changes: Vec, -) { - let mut line_index = LineIndex::new(old_text); - // The changes we got must be applied sequentially, but can cross lines so we - // have to keep our line index updated. - // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we - // remember the last valid line in the index and only rebuild it if needed. - // The VFS will normalize the end of lines to `\n`. - enum IndexValid { - All, - UpToLineExclusive(u64), - } - - impl IndexValid { - fn covers(&self, line: u64) -> bool { - match *self { - IndexValid::UpToLineExclusive(to) => to > line, - _ => true, - } - } - } - - let mut index_valid = IndexValid::All; - for change in content_changes { - match change.range { - Some(range) => { - if !index_valid.covers(range.end.line) { - line_index = LineIndex::new(&old_text); - } - index_valid = IndexValid::UpToLineExclusive(range.start.line); - let range = from_proto::text_range(&line_index, range); - old_text.replace_range(Range::::from(range), &change.text); - } - None => { - *old_text = change.text; - index_valid = IndexValid::UpToLineExclusive(0); - } - } - } -} - fn on_check_task( task: flycheck::Message, global_state: &mut GlobalState, @@ -862,73 +820,3 @@ fn update_file_notifications_on_threadpool( }) } } - -#[cfg(test)] -mod tests { - use lsp_types::{Position, Range, TextDocumentContentChangeEvent}; - - use super::*; - - #[test] - fn test_apply_document_changes() { - macro_rules! c { - [$($sl:expr, $sc:expr; $el:expr, $ec:expr => $text:expr),+] => { - vec![$(TextDocumentContentChangeEvent { - range: Some(Range { - start: Position { line: $sl, character: $sc }, - end: Position { line: $el, character: $ec }, - }), - range_length: None, - text: String::from($text), - }),+] - }; - } - - let mut text = String::new(); - apply_document_changes(&mut text, vec![]); - assert_eq!(text, ""); - apply_document_changes( - &mut text, - vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, - text: String::from("the"), - }], - ); - assert_eq!(text, "the"); - apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]); - assert_eq!(text, "the quick"); - apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); - assert_eq!(text, "quick foxes"); - apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]); - assert_eq!(text, "quick foxes\ndream"); - apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]); - assert_eq!(text, "quick foxes\nhave dream"); - apply_document_changes( - &mut text, - c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"], - ); - assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); - apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); - assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); - apply_document_changes( - &mut text, - c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], - ); - assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); - apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); - assert_eq!(text, "the quick \nthey have quiet dreams\n"); - - text = String::from("❤️"); - apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]); - assert_eq!(text, "a❤️"); - - text = String::from("a\nb"); - apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); - assert_eq!(text, "adcb"); - - text = String::from("a\nb"); - apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); - assert_eq!(text, "ațc\ncb"); - } -} -- cgit v1.2.3