mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-02 21:44:34 +00:00
build: move molc to a separate repository
This commit is contained in:
parent
ac5b0548a3
commit
b14a00c7bb
7 changed files with 3 additions and 636 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -248,6 +248,8 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "molc"
|
name = "molc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a19b669aab31ca7552fc43cb9ab08e325113aa090f7bf97a2112b3d6241ba898"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lsp-types",
|
"lsp-types",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -17,7 +17,6 @@ members = [
|
||||||
"crates/erg_compiler",
|
"crates/erg_compiler",
|
||||||
"crates/erg_parser",
|
"crates/erg_parser",
|
||||||
"crates/els",
|
"crates/els",
|
||||||
"crates/molc"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
@ -69,7 +68,6 @@ erg_common = { version = "0.6.20-nightly.2", path = "./crates/erg_common" }
|
||||||
erg_parser = { version = "0.6.20-nightly.2", path = "./crates/erg_parser" }
|
erg_parser = { version = "0.6.20-nightly.2", path = "./crates/erg_parser" }
|
||||||
erg_compiler = { version = "0.6.20-nightly.2", path = "./crates/erg_compiler" }
|
erg_compiler = { version = "0.6.20-nightly.2", path = "./crates/erg_compiler" }
|
||||||
els = { version = "0.1.32-nightly.2", path = "./crates/els" }
|
els = { version = "0.1.32-nightly.2", path = "./crates/els" }
|
||||||
molc = { version = "0.1.0", path = "./crates/molc" }
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { workspace = true }
|
erg_common = { workspace = true }
|
||||||
|
|
|
@ -23,7 +23,7 @@ experimental = ["erg_common/experimental", "erg_compiler/experimental"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { workspace = true, features = ["els"] }
|
erg_common = { workspace = true, features = ["els"] }
|
||||||
erg_compiler = { workspace = true, features = ["els"] }
|
erg_compiler = { workspace = true, features = ["els"] }
|
||||||
molc = { workspace = true }
|
molc = { version = "0.1.0" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0.85"
|
serde_json = "1.0.85"
|
||||||
lsp-types = { version = "0.93.2", features = ["proposed"] }
|
lsp-types = { version = "0.93.2", features = ["proposed"] }
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "molc"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "A mock language client for testing language servers"
|
|
||||||
authors.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
repository.workspace = true
|
|
||||||
homepage.workspace = true
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_json = "1.0.85"
|
|
||||||
lsp-types = { version = "0.93.2", features = ["proposed"] }
|
|
||||||
|
|
||||||
[path]
|
|
||||||
lib = "src/lib.rs"
|
|
|
@ -1,69 +0,0 @@
|
||||||
# `molc`
|
|
||||||
|
|
||||||
`molc` is a mock (fake) language client for testing language servers.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
You can see specific examples of molc use in [ELS](https://github.com/erg-lang/erg/tree/main/crates/els).
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use lsp_types::{Url, Value};
|
|
||||||
|
|
||||||
use molc::{FakeClient, LangServer, RedirectableStdout};
|
|
||||||
use molc::oneline_range;
|
|
||||||
|
|
||||||
pub struct Server {
|
|
||||||
stdout_redirect: Option<std::sync::mpsc::Sender<Value>>,
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LangServer for Server {
|
|
||||||
fn dispatch(&mut self, msg: impl Into<Value>) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
self.dispatch(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RedirectableStdout for Server {
|
|
||||||
fn sender(&self) -> Option<&std::sync::mpsc::Sender<Value>> {
|
|
||||||
self.stdout_redirect.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Server {
|
|
||||||
fn bind_fake_client() -> FakeClient<Self> {
|
|
||||||
// The server should send responses to this channel at least during testing.
|
|
||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
|
||||||
DummyClient::new(
|
|
||||||
Server::new(Some(sender)),
|
|
||||||
receiver,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(&mut self, msg: &Value, id: i64) -> ELSResult<()> {
|
|
||||||
self.send_log("initializing the language server")?;
|
|
||||||
let result = InitializeResult {
|
|
||||||
...
|
|
||||||
};
|
|
||||||
self.init_services();
|
|
||||||
self.send_stdout(&json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": id,
|
|
||||||
"result": result,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_references() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut client = Server::bind_fake_client();
|
|
||||||
client.request_initialize()?;
|
|
||||||
let uri = Url::from_file_path(Path::new(FILE_A).canonicalize()?).unwrap();
|
|
||||||
client.notify_open(FILE_A)?;
|
|
||||||
let locations = client.request_references(uri, 1, 4)?.unwrap();
|
|
||||||
assert_eq!(locations.len(), 1);
|
|
||||||
assert_eq!(&locations[0].range, &oneline_range(1, 4, 5));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,466 +0,0 @@
|
||||||
pub mod messages;
|
|
||||||
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{stdout, Read, Write};
|
|
||||||
use std::path::Path;
|
|
||||||
use std::{collections::HashMap, sync::mpsc::Sender};
|
|
||||||
|
|
||||||
use lsp_types::{
|
|
||||||
CompletionContext, CompletionParams, CompletionResponse, CompletionTriggerKind,
|
|
||||||
DidChangeTextDocumentParams, DidOpenTextDocumentParams, DocumentSymbolParams,
|
|
||||||
DocumentSymbolResponse, FoldingRange, FoldingRangeParams, GotoDefinitionParams,
|
|
||||||
GotoDefinitionResponse, Hover, HoverParams, InitializeResult, Location, Position, Range,
|
|
||||||
ReferenceContext, ReferenceParams, RenameParams, ServerCapabilities, SignatureHelp,
|
|
||||||
SignatureHelpContext, SignatureHelpParams, SignatureHelpTriggerKind,
|
|
||||||
TextDocumentContentChangeEvent, TextDocumentIdentifier, TextDocumentItem,
|
|
||||||
TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, WorkspaceEdit,
|
|
||||||
};
|
|
||||||
use serde::de::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
use serde_json::{json, Value};
|
|
||||||
|
|
||||||
use crate::messages::{ErrorMessage, LogMessage, ShowMessage};
|
|
||||||
|
|
||||||
fn safe_yield() {
|
|
||||||
std::thread::yield_now();
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_char(line: u32, character: u32, text: &str) -> TextDocumentContentChangeEvent {
|
|
||||||
TextDocumentContentChangeEvent {
|
|
||||||
range: Some(Range {
|
|
||||||
start: Position { line, character },
|
|
||||||
end: Position { line, character },
|
|
||||||
}),
|
|
||||||
range_length: None,
|
|
||||||
text: text.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn abs_pos(uri: Url, line: u32, col: u32) -> TextDocumentPositionParams {
|
|
||||||
TextDocumentPositionParams {
|
|
||||||
text_document: TextDocumentIdentifier::new(uri),
|
|
||||||
position: Position {
|
|
||||||
line,
|
|
||||||
character: col,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn oneline_range(line: u32, from: u32, to: u32) -> Range {
|
|
||||||
Range {
|
|
||||||
start: Position {
|
|
||||||
line,
|
|
||||||
character: from,
|
|
||||||
},
|
|
||||||
end: Position {
|
|
||||||
line,
|
|
||||||
character: to,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_msgs(_input: &str) -> Vec<Value> {
|
|
||||||
let mut input = _input;
|
|
||||||
let mut msgs = Vec::new();
|
|
||||||
loop {
|
|
||||||
if input.starts_with("Content-Length: ") {
|
|
||||||
let idx = "Content-Length: ".len();
|
|
||||||
input = &input[idx..];
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let dights = input.find("\r\n").unwrap();
|
|
||||||
let len = input[..dights].parse::<usize>().unwrap();
|
|
||||||
let idx = dights + "\r\n\r\n".len();
|
|
||||||
input = &input[idx..];
|
|
||||||
let msg = &input
|
|
||||||
.get(..len)
|
|
||||||
.unwrap_or_else(|| panic!("len: {len}, input: `{input}` -> _input: `{_input}`"));
|
|
||||||
input = &input[len..];
|
|
||||||
msgs.push(serde_json::from_str(msg).unwrap());
|
|
||||||
}
|
|
||||||
msgs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
|
||||||
|
|
||||||
pub trait RedirectableStdout {
|
|
||||||
fn sender(&self) -> Option<&Sender<Value>>;
|
|
||||||
|
|
||||||
fn send_stdout<T: ?Sized + Serialize>(&self, message: &T) -> Result<()> {
|
|
||||||
if let Some(sender) = self.sender() {
|
|
||||||
sender.send(serde_json::to_value(message)?)?;
|
|
||||||
} else {
|
|
||||||
let msg = serde_json::to_string(message)?;
|
|
||||||
let mut stdout = stdout().lock();
|
|
||||||
write!(stdout, "Content-Length: {}\r\n\r\n{}", msg.len(), msg)?;
|
|
||||||
stdout.flush()?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_log<S: Into<String>>(&self, msg: S) -> Result<()> {
|
|
||||||
if cfg!(debug_assertions) || cfg!(feature = "debug") {
|
|
||||||
self.send_stdout(&LogMessage::new(msg))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn send_info<S: Into<String>>(&self, msg: S) -> Result<()> {
|
|
||||||
self.send_stdout(&ShowMessage::info(msg))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_error_info<S: Into<String>>(&self, msg: S) -> Result<()> {
|
|
||||||
self.send_stdout(&ShowMessage::error(msg))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_error<S: Into<String>>(&self, id: Option<i64>, code: i64, msg: S) -> Result<()> {
|
|
||||||
self.send_stdout(&ErrorMessage::new(
|
|
||||||
id,
|
|
||||||
json!({ "code": code, "message": msg.into() }),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_invalid_req_error(&self) -> Result<()> {
|
|
||||||
self.send_error(None, -32601, "received an invalid request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LangServer {
|
|
||||||
fn dispatch(&mut self, msg: impl Into<Value>) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FakeClient<LS: LangServer> {
|
|
||||||
server: LS,
|
|
||||||
receiver: std::sync::mpsc::Receiver<Value>,
|
|
||||||
server_capas: Option<ServerCapabilities>,
|
|
||||||
pub responses: Vec<Value>,
|
|
||||||
#[allow(clippy::complexity)]
|
|
||||||
request_handlers: HashMap<String, Box<dyn Fn(&Value, &mut LS) -> Result<()>>>,
|
|
||||||
ver: i32,
|
|
||||||
req_id: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<LS: LangServer> FakeClient<LS> {
|
|
||||||
/// The server should send responses to the channel at least during testing.
|
|
||||||
pub fn new(server: LS, receiver: std::sync::mpsc::Receiver<Value>) -> Self {
|
|
||||||
FakeClient {
|
|
||||||
receiver,
|
|
||||||
responses: Vec::new(),
|
|
||||||
ver: 0,
|
|
||||||
req_id: 0,
|
|
||||||
server_capas: None,
|
|
||||||
request_handlers: HashMap::new(),
|
|
||||||
server,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_request_handler(
|
|
||||||
&mut self,
|
|
||||||
method_name: impl Into<String>,
|
|
||||||
handler: impl Fn(&Value, &mut LS) -> Result<()> + 'static,
|
|
||||||
) {
|
|
||||||
self.request_handlers
|
|
||||||
.insert(method_name.into(), Box::new(handler));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_request_handler(&mut self, method_name: &str) {
|
|
||||||
self.request_handlers.remove(method_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Waits for `n` messages to be received.
|
|
||||||
/// When a request is received, the registered handler will be executed.
|
|
||||||
pub fn wait_messages(&mut self, n: usize) -> Result<()> {
|
|
||||||
for _ in 0..n {
|
|
||||||
if let Ok(msg) = self.receiver.recv() {
|
|
||||||
if msg.get("method").is_some_and(|_| msg.get("id").is_some()) {
|
|
||||||
self.handle_server_request(&msg);
|
|
||||||
}
|
|
||||||
self.responses.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Waits for a response to the request, where its `id` is expected to be that of `req_id`,
|
|
||||||
/// and `req_id` will be incremented if the response is successfully received.
|
|
||||||
/// When a request is received, the registered handler will be executed.
|
|
||||||
fn wait_for<R>(&mut self) -> Result<R>
|
|
||||||
where
|
|
||||||
R: Deserialize<'static>,
|
|
||||||
{
|
|
||||||
loop {
|
|
||||||
if let Ok(msg) = self.receiver.recv() {
|
|
||||||
if msg.get("method").is_some_and(|_| msg.get("id").is_some()) {
|
|
||||||
self.handle_server_request(&msg);
|
|
||||||
}
|
|
||||||
self.responses.push(msg);
|
|
||||||
let msg = self.responses.last().unwrap();
|
|
||||||
if msg.get("id").is_some_and(|val| val == self.req_id) {
|
|
||||||
if let Some(result) = msg
|
|
||||||
.get("result")
|
|
||||||
.cloned()
|
|
||||||
.and_then(|res| R::deserialize(res).ok())
|
|
||||||
{
|
|
||||||
self.req_id += 1;
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
safe_yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_server_request(&mut self, msg: &Value) {
|
|
||||||
if let Some(method) = msg.get("method").and_then(|val| val.as_str()) {
|
|
||||||
if let Some(handler) = self.request_handlers.get(method) {
|
|
||||||
if let Err(err) = handler(msg, &mut self.server) {
|
|
||||||
eprintln!("error: {:?}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This will set the server capabilities
|
|
||||||
pub fn request_initialize(&mut self) -> Result<InitializeResult> {
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "initialize",
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
let res = self.wait_for::<InitializeResult>()?;
|
|
||||||
self.server_capas = Some(res.capabilities.clone());
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn notify_open(&mut self, file: &str) -> Result<()> {
|
|
||||||
let uri = Url::from_file_path(Path::new(file).canonicalize().unwrap()).unwrap();
|
|
||||||
let mut text = String::new();
|
|
||||||
File::open(file).unwrap().read_to_string(&mut text)?;
|
|
||||||
let params = DidOpenTextDocumentParams {
|
|
||||||
text_document: TextDocumentItem::new(uri, "erg".to_string(), self.ver, text),
|
|
||||||
};
|
|
||||||
self.ver += 1;
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "textDocument/didOpen",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn notify_change(
|
|
||||||
&mut self,
|
|
||||||
uri: Url,
|
|
||||||
change: TextDocumentContentChangeEvent,
|
|
||||||
) -> Result<()> {
|
|
||||||
let params = DidChangeTextDocumentParams {
|
|
||||||
text_document: VersionedTextDocumentIdentifier::new(uri.clone(), self.ver),
|
|
||||||
content_changes: vec![change],
|
|
||||||
};
|
|
||||||
self.ver += 1;
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "textDocument/didChange",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_trigger_char(&self, character: &str) -> bool {
|
|
||||||
self.server_capas.as_ref().is_some_and(|cap| {
|
|
||||||
cap.completion_provider.as_ref().is_some_and(|comp| {
|
|
||||||
comp.trigger_characters
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|chars| chars.iter().any(|c| c == character))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_completion(
|
|
||||||
&mut self,
|
|
||||||
uri: Url,
|
|
||||||
line: u32,
|
|
||||||
col: u32,
|
|
||||||
character: &str,
|
|
||||||
) -> Result<Option<CompletionResponse>> {
|
|
||||||
let text_document_position = abs_pos(uri, line, col);
|
|
||||||
let trigger_kind = if self.is_trigger_char(character) {
|
|
||||||
CompletionTriggerKind::TRIGGER_CHARACTER
|
|
||||||
} else {
|
|
||||||
CompletionTriggerKind::INVOKED
|
|
||||||
};
|
|
||||||
let trigger_character = self
|
|
||||||
.is_trigger_char(character)
|
|
||||||
.then_some(character.to_string());
|
|
||||||
let context = Some(CompletionContext {
|
|
||||||
trigger_kind,
|
|
||||||
trigger_character,
|
|
||||||
});
|
|
||||||
let params = CompletionParams {
|
|
||||||
text_document_position,
|
|
||||||
context,
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
partial_result_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/completion",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<CompletionResponse>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_rename(
|
|
||||||
&mut self,
|
|
||||||
uri: Url,
|
|
||||||
line: u32,
|
|
||||||
col: u32,
|
|
||||||
new_name: &str,
|
|
||||||
) -> Result<Option<WorkspaceEdit>> {
|
|
||||||
let text_document_position = abs_pos(uri, line, col);
|
|
||||||
let params = RenameParams {
|
|
||||||
text_document_position,
|
|
||||||
new_name: new_name.to_string(),
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/rename",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<WorkspaceEdit>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_signature_help(
|
|
||||||
&mut self,
|
|
||||||
uri: Url,
|
|
||||||
line: u32,
|
|
||||||
col: u32,
|
|
||||||
character: &str,
|
|
||||||
) -> Result<Option<SignatureHelp>> {
|
|
||||||
let text_document_position_params = abs_pos(uri, line, col);
|
|
||||||
let context = SignatureHelpContext {
|
|
||||||
trigger_kind: SignatureHelpTriggerKind::TRIGGER_CHARACTER,
|
|
||||||
trigger_character: Some(character.to_string()),
|
|
||||||
is_retrigger: false,
|
|
||||||
active_signature_help: None,
|
|
||||||
};
|
|
||||||
let params = SignatureHelpParams {
|
|
||||||
text_document_position_params,
|
|
||||||
context: Some(context),
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/signatureHelp",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<SignatureHelp>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_hover(&mut self, uri: Url, line: u32, col: u32) -> Result<Option<Hover>> {
|
|
||||||
let params = HoverParams {
|
|
||||||
text_document_position_params: abs_pos(uri, line, col),
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/hover",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<Hover>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_references(
|
|
||||||
&mut self,
|
|
||||||
uri: Url,
|
|
||||||
line: u32,
|
|
||||||
col: u32,
|
|
||||||
) -> Result<Option<Vec<Location>>> {
|
|
||||||
let context = ReferenceContext {
|
|
||||||
include_declaration: false,
|
|
||||||
};
|
|
||||||
let params = ReferenceParams {
|
|
||||||
text_document_position: abs_pos(uri, line, col),
|
|
||||||
context,
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
partial_result_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/references",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<Vec<Location>>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_goto_definition(
|
|
||||||
&mut self,
|
|
||||||
uri: Url,
|
|
||||||
line: u32,
|
|
||||||
col: u32,
|
|
||||||
) -> Result<Option<GotoDefinitionResponse>> {
|
|
||||||
let params = GotoDefinitionParams {
|
|
||||||
text_document_position_params: abs_pos(uri, line, col),
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
partial_result_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/definition",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<GotoDefinitionResponse>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_folding_range(&mut self, uri: Url) -> Result<Option<Vec<FoldingRange>>> {
|
|
||||||
let params = FoldingRangeParams {
|
|
||||||
text_document: TextDocumentIdentifier::new(uri),
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
partial_result_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/foldingRange",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<Vec<FoldingRange>>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_document_symbols(&mut self, uri: Url) -> Result<Option<DocumentSymbolResponse>> {
|
|
||||||
let params = DocumentSymbolParams {
|
|
||||||
text_document: TextDocumentIdentifier::new(uri),
|
|
||||||
work_done_progress_params: Default::default(),
|
|
||||||
partial_result_params: Default::default(),
|
|
||||||
};
|
|
||||||
let msg = json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": self.req_id,
|
|
||||||
"method": "textDocument/documentSymbol",
|
|
||||||
"params": params,
|
|
||||||
});
|
|
||||||
self.server.dispatch(msg)?;
|
|
||||||
self.wait_for::<Option<DocumentSymbolResponse>>()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::json;
|
|
||||||
use serde_json::{Number, Value};
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct ErrorMessage {
|
|
||||||
jsonrpc: String,
|
|
||||||
id: Option<Number>,
|
|
||||||
error: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ErrorMessage {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn new<N: Into<Number>>(id: Option<N>, error: Value) -> Self {
|
|
||||||
Self {
|
|
||||||
jsonrpc: "2.0".into(),
|
|
||||||
id: id.map(|i| i.into()),
|
|
||||||
error,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct LogMessage {
|
|
||||||
jsonrpc: String,
|
|
||||||
method: String,
|
|
||||||
params: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LogMessage {
|
|
||||||
pub fn new<S: Into<String>>(message: S) -> Self {
|
|
||||||
Self {
|
|
||||||
jsonrpc: "2.0".into(),
|
|
||||||
method: "window/logMessage".into(),
|
|
||||||
params: json! {
|
|
||||||
{
|
|
||||||
"type": 3,
|
|
||||||
"message": message.into(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct ShowMessage {
|
|
||||||
jsonrpc: String,
|
|
||||||
method: String,
|
|
||||||
params: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShowMessage {
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn info<S: Into<String>>(message: S) -> Self {
|
|
||||||
Self {
|
|
||||||
jsonrpc: "2.0".into(),
|
|
||||||
method: "window/showMessage".into(),
|
|
||||||
params: json! {
|
|
||||||
{
|
|
||||||
"type": 3,
|
|
||||||
"message": message.into(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error<S: Into<String>>(message: S) -> Self {
|
|
||||||
Self {
|
|
||||||
jsonrpc: "2.0".into(),
|
|
||||||
method: "window/showMessage".into(),
|
|
||||||
params: json! {
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"message": message.into(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue