//! IDE context data model and public helpers for TUI `/ide` support. mod ipc; mod prompt; #[cfg(windows)] mod windows_pipe; pub(crate) use ipc::fetch_ide_context; pub(crate) use prompt::apply_ide_context_to_user_input; pub(crate) use prompt::extract_prompt_request_with_offset; pub(crate) use prompt::has_prompt_context; use serde::Deserialize; #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub(crate) struct IdeContext { active_file: Option, #[serde(default)] open_tabs: Vec, } #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct ActiveFile { #[serde(flatten)] descriptor: FileDescriptor, selection: Range, #[serde(default)] active_selection_content: String, #[serde(default)] selections: Vec, } #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct FileDescriptor { label: String, path: String, } #[derive(Debug, Clone, Deserialize, PartialEq)] struct Range { start: Position, end: Position, } #[derive(Debug, Clone, Deserialize, PartialEq)] struct Position { line: u32, character: u32, } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; use serde_json::json; #[test] fn deserializes_existing_ide_context_shape() { let value = json!({ "activeFile": { "label": "lib.rs", "path": "src/lib.rs", "fsPath": "/repo/src/lib.rs", "selection": { "start": { "line": 1, "character": 2 }, "end": { "line": 3, "character": 4 } }, "activeSelectionContent": "selected", "selections": [] }, "openTabs": [ { "label": "main.rs", "path": "src/main.rs", "fsPath": "/repo/src/main.rs", "startLine": 2, "endLine": 10 } ], "processEnv": { "path": "/usr/bin" } }); let context: IdeContext = serde_json::from_value(value).expect("deserialize ide context"); assert_eq!( context, IdeContext { active_file: Some(ActiveFile { descriptor: FileDescriptor { label: "lib.rs".to_string(), path: "src/lib.rs".to_string(), }, selection: Range { start: Position { line: 1, character: 2, }, end: Position { line: 3, character: 4, }, }, active_selection_content: "selected".to_string(), selections: Vec::new(), }), open_tabs: vec![FileDescriptor { label: "main.rs".to_string(), path: "src/main.rs".to_string(), }], } ); } }