use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize)]
pub struct DaemonStatusResponse {
pub ready: bool,
pub indexed_at: Option<String>,
pub workspace_root: String,
pub process_id: u32,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SymbolQueryRequest {
pub name: String,
pub kind: String,
pub exact: bool,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SymbolItem {
pub name: String,
pub kind: String,
pub file: String,
pub line: u32,
pub col: u32,
pub container_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct OutlineQueryRequest {
pub file: PathBuf,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct OutlineItem {
pub name: String,
pub kind: String,
pub detail: Option<String>,
pub line: u32,
pub col: u32,
pub end_line: u32,
pub children: Vec<OutlineItem>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DefinitionQueryRequest {
pub file: PathBuf,
pub line: u32,
pub col: u32,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DefinitionItem {
pub file: String,
pub line: u32,
pub col: u32,
pub end_line: u32,
pub end_col: u32,
pub snippet: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CursorQueryRequest {
pub file: PathBuf,
pub line: u32,
pub col: u32,
pub mode: String, pub depth: u32,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CursorItem {
pub name: String,
pub kind: String,
pub file: String,
pub line: u32,
pub col: u32,
pub caller_or_callee: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct TypeHierarchyQueryRequest {
pub file: PathBuf,
pub line: u32,
pub col: u32,
pub mode: String, pub depth: u32,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct TypeHierarchyItemResult {
pub name: String,
pub kind: String,
pub file: String,
pub line: u32,
pub col: u32,
pub detail: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BodyItem {
pub file: String,
pub line: u32,
pub col: u32,
pub end_line: u32,
pub end_col: u32,
pub body: String,
pub total_lines: usize,
pub is_truncated: bool,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CheckQueryRequest {
pub target: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CheckDiagnosticItem {
pub message: String,
pub level: String, pub file: Option<String>,
pub line: Option<u32>,
pub col: Option<u32>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CheckResponse {
pub success: bool,
pub diagnostics: Vec<CheckDiagnosticItem>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_daemon_status_json_roundtrip() {
let status = DaemonStatusResponse {
ready: true,
indexed_at: Some("2026-07-31T10:00:00Z".to_string()),
workspace_root: "/path/to/workspace".to_string(),
process_id: 12345,
};
let json = serde_json::to_string(&status).unwrap();
let decoded: DaemonStatusResponse = serde_json::from_str(&json).unwrap();
assert!(decoded.ready);
assert_eq!(decoded.process_id, 12345);
assert_eq!(decoded.workspace_root, "/path/to/workspace");
}
#[test]
fn test_symbol_item_json_roundtrip() {
let item = SymbolItem {
name: "LspClient".to_string(),
kind: "struct".to_string(),
file: "src/lsp/client.rs".to_string(),
line: 15,
col: 1,
container_name: Some("lsp".to_string()),
body: None,
};
let json = serde_json::to_string(&item).unwrap();
let decoded: SymbolItem = serde_json::from_str(&json).unwrap();
assert_eq!(decoded.name, "LspClient");
assert_eq!(decoded.kind, "struct");
}
}