mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-02 13:41:10 +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]]
|
||||
name = "molc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19b669aab31ca7552fc43cb9ab08e325113aa090f7bf97a2112b3d6241ba898"
|
||||
dependencies = [
|
||||
"lsp-types",
|
||||
"serde",
|
||||
|
|
|
@ -17,7 +17,6 @@ members = [
|
|||
"crates/erg_compiler",
|
||||
"crates/erg_parser",
|
||||
"crates/els",
|
||||
"crates/molc"
|
||||
]
|
||||
|
||||
[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_compiler = { version = "0.6.20-nightly.2", path = "./crates/erg_compiler" }
|
||||
els = { version = "0.1.32-nightly.2", path = "./crates/els" }
|
||||
molc = { version = "0.1.0", path = "./crates/molc" }
|
||||
|
||||
[dependencies]
|
||||
erg_common = { workspace = true }
|
||||
|
|
|
@ -23,7 +23,7 @@ experimental = ["erg_common/experimental", "erg_compiler/experimental"]
|
|||
[dependencies]
|
||||
erg_common = { 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_json = "1.0.85"
|
||||
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