summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/lib')
-rw-r--r--src/tools/rust-analyzer/lib/la-arena/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/lib/line-index/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/lib/line-index/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/lib/line-index/src/tests.rs28
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/Cargo.toml7
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/lib.rs171
6 files changed, 198 insertions, 19 deletions
diff --git a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
index f39c3a3e4..d195bdd15 100644
--- a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
@@ -1,6 +1,6 @@
//! Yet another index-based arena.
-#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
+#![warn(rust_2018_idioms, unused_lifetimes)]
#![warn(missing_docs)]
use std::{
diff --git a/src/tools/rust-analyzer/lib/line-index/Cargo.toml b/src/tools/rust-analyzer/lib/line-index/Cargo.toml
index 6c0d06f47..494a7fa97 100644
--- a/src/tools/rust-analyzer/lib/line-index/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/line-index/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "line-index"
-version = "0.1.0"
+version = "0.1.1"
description = "Maps flat `TextSize` offsets to/from `(line, column)` representation."
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/line-index"
edition = "2021"
[dependencies]
-text-size = "1.1.0"
+text-size = "1.1.1"
nohash-hasher = "0.2.0"
diff --git a/src/tools/rust-analyzer/lib/line-index/src/lib.rs b/src/tools/rust-analyzer/lib/line-index/src/lib.rs
index 03371c9c8..58f266d67 100644
--- a/src/tools/rust-analyzer/lib/line-index/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/line-index/src/lib.rs
@@ -363,7 +363,10 @@ fn analyze_source_file_generic(
let c = src[i..].chars().next().unwrap();
char_len = c.len_utf8();
- let pos = TextSize::from(i as u32) + output_offset;
+ // The last element of `lines` represents the offset of the start of
+ // current line. To get the offset inside the line, we subtract it.
+ let pos = TextSize::from(i as u32) + output_offset
+ - lines.last().unwrap_or(&TextSize::default());
if char_len > 1 {
assert!((2..=4).contains(&char_len));
diff --git a/src/tools/rust-analyzer/lib/line-index/src/tests.rs b/src/tools/rust-analyzer/lib/line-index/src/tests.rs
index 8f3762d19..981008e34 100644
--- a/src/tools/rust-analyzer/lib/line-index/src/tests.rs
+++ b/src/tools/rust-analyzer/lib/line-index/src/tests.rs
@@ -1,4 +1,4 @@
-use crate::{LineIndex, TextSize, WideChar};
+use crate::{LineCol, LineIndex, TextSize, WideChar, WideEncoding, WideLineCol};
macro_rules! test {
(
@@ -102,7 +102,7 @@ test!(
case: multi_byte_with_new_lines,
text: "01\t345\n789abcΔf01234567\u{07}9\nbcΔf",
lines: vec![7, 27],
- multi_byte_chars: vec![(1, (13, 15)), (2, (29, 31))],
+ multi_byte_chars: vec![(1, (6, 8)), (2, (2, 4))],
);
test!(
@@ -118,3 +118,27 @@ test!(
lines: vec![16],
multi_byte_chars: vec![],
);
+
+#[test]
+fn test_try_line_col() {
+ let text = "\n\n\n\n\n宽3456";
+ assert_eq!(&text[5..8], "宽");
+ assert_eq!(&text[11..12], "6");
+ let line_index = LineIndex::new(text);
+ let before_6 = TextSize::from(11);
+ let line_col = line_index.try_line_col(before_6);
+ assert_eq!(line_col, Some(LineCol { line: 5, col: 6 }));
+}
+
+#[test]
+fn test_to_wide() {
+ let text = "\n\n\n\n\n宽3456";
+ assert_eq!(&text[5..8], "宽");
+ assert_eq!(&text[11..12], "6");
+ let line_index = LineIndex::new(text);
+ let before_6 = TextSize::from(11);
+ let line_col = line_index.try_line_col(before_6);
+ assert_eq!(line_col, Some(LineCol { line: 5, col: 6 }));
+ let wide_line_col = line_index.to_wide(WideEncoding::Utf16, line_col.unwrap());
+ assert_eq!(wide_line_col, Some(WideLineCol { line: 5, col: 4 }));
+}
diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
index 7ec3247e9..2a70aedbe 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "lsp-server"
-version = "0.7.4"
+version = "0.7.5"
description = "Generic LSP server scaffold."
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-server"
@@ -8,9 +8,10 @@ edition = "2021"
[dependencies]
log = "0.4.17"
-serde_json = "1.0.96"
-serde = { version = "1.0.156", features = ["derive"] }
+serde_json = "1.0.108"
+serde = { version = "1.0.192", features = ["derive"] }
crossbeam-channel = "0.5.6"
[dev-dependencies]
lsp-types = "=0.94"
+ctrlc = "3.4.1"
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
index affab60a2..2797a6b60 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
@@ -4,7 +4,7 @@
//!
//! Run with `RUST_LOG=lsp_server=debug` to see all the messages.
-#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
+#![warn(rust_2018_idioms, unused_lifetimes)]
mod msg;
mod stdio;
@@ -17,7 +17,7 @@ use std::{
net::{TcpListener, TcpStream, ToSocketAddrs},
};
-use crossbeam_channel::{Receiver, Sender};
+use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
pub use crate::{
error::{ExtractError, ProtocolError},
@@ -113,11 +113,62 @@ impl Connection {
/// }
/// ```
pub fn initialize_start(&self) -> Result<(RequestId, serde_json::Value), ProtocolError> {
- loop {
- break match self.receiver.recv() {
- Ok(Message::Request(req)) if req.is_initialize() => Ok((req.id, req.params)),
+ self.initialize_start_while(|| true)
+ }
+
+ /// Starts the initialization process by waiting for an initialize as described in
+ /// [`Self::initialize_start`] as long as `running` returns
+ /// `true` while the return value can be changed through a sig handler such as `CTRL + C`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::sync::atomic::{AtomicBool, Ordering};
+ /// use std::sync::Arc;
+ /// # use std::error::Error;
+ /// # use lsp_types::{ClientCapabilities, InitializeParams, ServerCapabilities};
+ /// # use lsp_server::{Connection, Message, Request, RequestId, Response};
+ /// # fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
+ /// let running = Arc::new(AtomicBool::new(true));
+ /// # running.store(true, Ordering::SeqCst);
+ /// let r = running.clone();
+ ///
+ /// ctrlc::set_handler(move || {
+ /// r.store(false, Ordering::SeqCst);
+ /// }).expect("Error setting Ctrl-C handler");
+ ///
+ /// let (connection, io_threads) = Connection::stdio();
+ ///
+ /// let res = connection.initialize_start_while(|| running.load(Ordering::SeqCst));
+ /// # assert!(res.is_err());
+ ///
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn initialize_start_while<C>(
+ &self,
+ running: C,
+ ) -> Result<(RequestId, serde_json::Value), ProtocolError>
+ where
+ C: Fn() -> bool,
+ {
+ while running() {
+ let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) {
+ Ok(msg) => msg,
+ Err(RecvTimeoutError::Timeout) => {
+ continue;
+ }
+ Err(e) => {
+ return Err(ProtocolError(format!(
+ "expected initialize request, got error: {e}"
+ )))
+ }
+ };
+
+ match msg {
+ Message::Request(req) if req.is_initialize() => return Ok((req.id, req.params)),
// Respond to non-initialize requests with ServerNotInitialized
- Ok(Message::Request(req)) => {
+ Message::Request(req) => {
let resp = Response::new_err(
req.id.clone(),
ErrorCode::ServerNotInitialized as i32,
@@ -126,15 +177,18 @@ impl Connection {
self.sender.send(resp.into()).unwrap();
continue;
}
- Ok(Message::Notification(n)) if !n.is_exit() => {
+ Message::Notification(n) if !n.is_exit() => {
continue;
}
- Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))),
- Err(e) => {
- Err(ProtocolError(format!("expected initialize request, got error: {e}")))
+ msg => {
+ return Err(ProtocolError(format!("expected initialize request, got {msg:?}")));
}
};
}
+
+ return Err(ProtocolError(String::from(
+ "Initialization has been aborted during initialization",
+ )));
}
/// Finishes the initialization process by sending an `InitializeResult` to the client
@@ -156,6 +210,51 @@ impl Connection {
}
}
+ /// Finishes the initialization process as described in [`Self::initialize_finish`] as
+ /// long as `running` returns `true` while the return value can be changed through a sig
+ /// handler such as `CTRL + C`.
+ pub fn initialize_finish_while<C>(
+ &self,
+ initialize_id: RequestId,
+ initialize_result: serde_json::Value,
+ running: C,
+ ) -> Result<(), ProtocolError>
+ where
+ C: Fn() -> bool,
+ {
+ let resp = Response::new_ok(initialize_id, initialize_result);
+ self.sender.send(resp.into()).unwrap();
+
+ while running() {
+ let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) {
+ Ok(msg) => msg,
+ Err(RecvTimeoutError::Timeout) => {
+ continue;
+ }
+ Err(e) => {
+ return Err(ProtocolError(format!(
+ "expected initialized notification, got error: {e}",
+ )));
+ }
+ };
+
+ match msg {
+ Message::Notification(n) if n.is_initialized() => {
+ return Ok(());
+ }
+ msg => {
+ return Err(ProtocolError(format!(
+ r#"expected initialized notification, got: {msg:?}"#
+ )));
+ }
+ }
+ }
+
+ return Err(ProtocolError(String::from(
+ "Initialization has been aborted during initialization",
+ )));
+ }
+
/// Initialize the connection. Sends the server capabilities
/// to the client and returns the serialized client capabilities
/// on success. If more fine-grained initialization is required use
@@ -198,6 +297,58 @@ impl Connection {
Ok(params)
}
+ /// Initialize the connection as described in [`Self::initialize`] as long as `running` returns
+ /// `true` while the return value can be changed through a sig handler such as `CTRL + C`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::sync::atomic::{AtomicBool, Ordering};
+ /// use std::sync::Arc;
+ /// # use std::error::Error;
+ /// # use lsp_types::ServerCapabilities;
+ /// # use lsp_server::{Connection, Message, Request, RequestId, Response};
+ ///
+ /// # fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
+ /// let running = Arc::new(AtomicBool::new(true));
+ /// # running.store(true, Ordering::SeqCst);
+ /// let r = running.clone();
+ ///
+ /// ctrlc::set_handler(move || {
+ /// r.store(false, Ordering::SeqCst);
+ /// }).expect("Error setting Ctrl-C handler");
+ ///
+ /// let (connection, io_threads) = Connection::stdio();
+ ///
+ /// let server_capabilities = serde_json::to_value(&ServerCapabilities::default()).unwrap();
+ /// let initialization_params = connection.initialize_while(
+ /// server_capabilities,
+ /// || running.load(Ordering::SeqCst)
+ /// );
+ ///
+ /// # assert!(initialization_params.is_err());
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn initialize_while<C>(
+ &self,
+ server_capabilities: serde_json::Value,
+ running: C,
+ ) -> Result<serde_json::Value, ProtocolError>
+ where
+ C: Fn() -> bool,
+ {
+ let (id, params) = self.initialize_start_while(&running)?;
+
+ let initialize_data = serde_json::json!({
+ "capabilities": server_capabilities,
+ });
+
+ self.initialize_finish_while(id, initialize_data, running)?;
+
+ Ok(params)
+ }
+
/// If `req` is `Shutdown`, respond to it and return `true`, otherwise return `false`
pub fn handle_shutdown(&self, req: &Request) -> Result<bool, ProtocolError> {
if !req.is_shutdown() {