#![allow(dead_code)]
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize)]
pub struct JsonRpcRequest<T> {
pub jsonrpc: &'static str,
pub id: u32,
pub method: &'static str,
pub params: T,
}
impl<T> JsonRpcRequest<T> {
pub fn new(id: u32, method: &'static str, params: T) -> Self {
Self {
jsonrpc: "2.0",
id,
method,
params,
}
}
}
#[derive(Debug, Serialize)]
pub struct JsonRpcNotification<T> {
pub jsonrpc: &'static str,
pub method: &'static str,
pub params: T,
}
impl<T> JsonRpcNotification<T> {
pub fn new(method: &'static str, params: T) -> Self {
Self {
jsonrpc: "2.0",
method,
params,
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum JsonRpcId {
Number(u32),
String(String),
}
#[derive(Debug, Deserialize)]
pub struct JsonRpcResponse<T> {
pub jsonrpc: String,
pub id: Option<JsonRpcId>,
pub result: Option<T>,
pub error: Option<JsonRpcError>,
}
#[derive(Debug, Deserialize)]
pub struct JsonRpcError {
pub code: i32,
pub message: String,
pub data: Option<serde_json::Value>,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct InitializeParams {
pub process_id: Option<u32>,
pub root_uri: Option<String>,
pub capabilities: ClientCapabilities,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ClientCapabilities {
pub text_document: TextDocumentClientCapabilities,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TextDocumentClientCapabilities {
pub hover: HoverClientCapabilities,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct HoverClientCapabilities {
pub content_format: Vec<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct InitializeResult {
pub capabilities: ServerCapabilities,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ServerCapabilities {
pub hover_provider: Option<bool>,
pub text_document_sync: Option<TextDocumentSyncOptions>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TextDocumentSyncOptions {
pub open_close: Option<bool>,
pub change: Option<u32>,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DidOpenTextDocumentParams {
pub text_document: TextDocumentItem,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TextDocumentItem {
pub uri: String,
pub language_id: String,
pub version: i32,
pub text: String,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DidCloseTextDocumentParams {
pub text_document: TextDocumentIdentifier,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DidChangeTextDocumentParams {
pub text_document: VersionedTextDocumentIdentifier,
pub content_changes: Vec<TextDocumentContentChangeEvent>,
}
#[derive(Debug, Serialize)]
pub struct VersionedTextDocumentIdentifier {
pub uri: String,
pub version: i32,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TextDocumentContentChangeEvent {
#[serde(skip_serializing_if = "Option::is_none")]
pub range: Option<Range>,
pub text: String,
}
#[derive(Debug, Serialize, Clone)]
pub struct TextDocumentIdentifier {
pub uri: String,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct HoverParams {
pub text_document: TextDocumentIdentifier,
pub position: Position,
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub struct Position {
pub line: u32,
pub character: u32,
}
#[derive(Debug, Deserialize)]
pub struct Hover {
pub contents: HoverContents,
pub range: Option<Range>,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum HoverContents {
Single(MarkedStringOrMarkup),
Array(Vec<MarkedStringOrMarkup>),
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum MarkedStringOrMarkup {
String(String),
MarkupContent(MarkupContent),
MarkedString(MarkedString),
}
#[derive(Debug, Deserialize)]
pub struct MarkupContent {
pub kind: String,
pub value: String,
}
#[derive(Debug, Deserialize)]
pub struct MarkedString {
pub language: String,
pub value: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Range {
pub start: Position,
pub end: Position,
}
#[derive(Debug, Serialize)]
pub struct ShutdownParams {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_initialize_params_serialization() {
let params = InitializeParams {
process_id: Some(12345),
root_uri: Some("file:///path/to/project".to_string()),
capabilities: ClientCapabilities {
text_document: TextDocumentClientCapabilities {
hover: HoverClientCapabilities {
content_format: vec!["plaintext".to_string()],
},
},
},
};
let json = serde_json::to_string(¶ms).unwrap();
assert!(json.contains("processId"));
assert!(json.contains("rootUri"));
assert!(json.contains("textDocument"));
}
#[test]
fn test_hover_response_deserialization() {
let json = r#"{
"contents": {
"kind": "plaintext",
"value": "const x: string"
},
"range": {
"start": {"line": 0, "character": 6},
"end": {"line": 0, "character": 7}
}
}"#;
let hover: Hover = serde_json::from_str(json).unwrap();
match hover.contents {
HoverContents::Single(MarkedStringOrMarkup::MarkupContent(mc)) => {
assert_eq!(mc.value, "const x: string");
}
_ => panic!("Expected MarkupContent"),
}
}
#[test]
fn test_hover_response_string_contents() {
let json = r#"{
"contents": "const x: string"
}"#;
let hover: Hover = serde_json::from_str(json).unwrap();
match hover.contents {
HoverContents::Single(MarkedStringOrMarkup::String(s)) => {
assert_eq!(s, "const x: string");
}
_ => panic!("Expected String"),
}
}
#[test]
fn test_hover_response_array_contents() {
let json = r#"{
"contents": [
{"language": "typescript", "value": "const x: string"},
"Documentation for x"
]
}"#;
let hover: Hover = serde_json::from_str(json).unwrap();
match hover.contents {
HoverContents::Array(arr) => {
assert_eq!(arr.len(), 2);
}
_ => panic!("Expected Array"),
}
}
}