about summary refs log tree commit diff
path: root/src/tools/rls
diff options
context:
space:
mode:
authorEric Huss <eric@huss.org>2022-08-20 21:19:43 -0700
committerEric Huss <eric@huss.org>2022-08-27 21:36:08 -0700
commit4a7e2fbb7bfdb7ddcb65b6fcf23bb5b272e66d42 (patch)
treebb2f39474cc03d3f78f5838297432a2a6a9e301d /src/tools/rls
parent1e978a3627bd65064164af3548c585fb25eef9d2 (diff)
downloadrust-4a7e2fbb7bfdb7ddcb65b6fcf23bb5b272e66d42.tar.gz
rust-4a7e2fbb7bfdb7ddcb65b6fcf23bb5b272e66d42.zip
Sunset RLS
Diffstat (limited to 'src/tools/rls')
m---------src/tools/rls0
-rw-r--r--src/tools/rls/Cargo.toml13
-rw-r--r--src/tools/rls/README.md6
-rw-r--r--src/tools/rls/src/main.rs101
4 files changed, 120 insertions, 0 deletions
diff --git a/src/tools/rls b/src/tools/rls
deleted file mode 160000
-Subproject 4d8b0a19986a4daab37287a5b5fe2da0775d187
diff --git a/src/tools/rls/Cargo.toml b/src/tools/rls/Cargo.toml
new file mode 100644
index 00000000000..92b50bf4cec
--- /dev/null
+++ b/src/tools/rls/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "rls"
+version = "2.0.0"
+edition = "2021"
+license = "Apache-2.0/MIT"
+
+[dependencies]
+serde = { version = "1.0.143", features = ["derive"] }
+serde_json = "1.0.83"
+# A noop dependency that changes in the Rust repository, it's a bit of a hack.
+# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
+# for more information.
+rustc-workspace-hack = "1.0.0"
diff --git a/src/tools/rls/README.md b/src/tools/rls/README.md
new file mode 100644
index 00000000000..43c331c413f
--- /dev/null
+++ b/src/tools/rls/README.md
@@ -0,0 +1,6 @@
+# RLS Stub
+
+RLS has been replaced with [rust-analyzer](https://rust-analyzer.github.io/).
+
+This directory contains a stub which replaces RLS with a simple LSP server
+which only displays an alert to the user that RLS is no longer available.
diff --git a/src/tools/rls/src/main.rs b/src/tools/rls/src/main.rs
new file mode 100644
index 00000000000..f96f1325d96
--- /dev/null
+++ b/src/tools/rls/src/main.rs
@@ -0,0 +1,101 @@
+//! RLS stub.
+//!
+//! This is a small stub that replaces RLS to alert the user that RLS is no
+//! longer available.
+
+use serde::Deserialize;
+use std::error::Error;
+use std::io::BufRead;
+use std::io::Write;
+
+const ALERT_MSG: &str = "\
+RLS is no longer available as of Rust 1.65.
+Consider migrating to rust-analyzer instead.
+See https://rust-analyzer.github.io/ for installation instructions.
+";
+
+fn main() {
+    if let Err(e) = run() {
+        eprintln!("error: {e}");
+        std::process::exit(1);
+    }
+}
+
+#[derive(Deserialize)]
+struct Message {
+    method: Option<String>,
+}
+
+fn run() -> Result<(), Box<dyn Error>> {
+    let mut stdin = std::io::stdin().lock();
+    let mut stdout = std::io::stdout().lock();
+
+    let init = read_message(&mut stdin)?;
+    if init.method.as_deref() != Some("initialize") {
+        return Err(format!("expected initialize, got {:?}", init.method).into());
+    }
+    // No response, the LSP specification says that `showMessageRequest` may
+    // be posted before during this phase.
+
+    // message_type 1 is "Error"
+    let alert = serde_json::json!({
+        "jsonrpc": "2.0",
+        "id": 1,
+        "method": "window/showMessageRequest",
+        "params": {
+            "message_type": "1",
+            "message": ALERT_MSG
+        }
+    });
+    write_message_raw(&mut stdout, serde_json::to_string(&alert).unwrap())?;
+
+    loop {
+        let message = read_message(&mut stdin)?;
+        if message.method.as_deref() == Some("shutdown") {
+            std::process::exit(0);
+        }
+    }
+}
+
+fn read_message_raw<R: BufRead>(reader: &mut R) -> Result<String, Box<dyn Error>> {
+    let mut content_length: usize = 0;
+
+    // Read headers.
+    loop {
+        let mut line = String::new();
+        reader.read_line(&mut line)?;
+        if line.is_empty() {
+            return Err("remote disconnected".into());
+        }
+        if line == "\r\n" {
+            break;
+        }
+        if line.to_lowercase().starts_with("content-length:") {
+            let value = &line[15..].trim();
+            content_length = usize::from_str_radix(value, 10)?;
+        }
+    }
+    if content_length == 0 {
+        return Err("no content-length".into());
+    }
+
+    let mut buffer = vec![0; content_length];
+    reader.read_exact(&mut buffer)?;
+    let content = String::from_utf8(buffer)?;
+
+    Ok(content)
+}
+
+fn read_message<R: BufRead>(reader: &mut R) -> Result<Message, Box<dyn Error>> {
+    let m = read_message_raw(reader)?;
+    match serde_json::from_str(&m) {
+        Ok(m) => Ok(m),
+        Err(e) => Err(format!("failed to parse message {m}\n{e}").into()),
+    }
+}
+
+fn write_message_raw<W: Write>(mut writer: W, output: String) -> Result<(), Box<dyn Error>> {
+    write!(writer, "Content-Length: {}\r\n\r\n{}", output.len(), output)?;
+    writer.flush()?;
+    Ok(())
+}