Rust · 3172 bytes Raw Blame History
1 //! Shared IPC protocol types for garfield.
2 //!
3 //! This crate defines the request/response types used for communication
4 //! between garfield and garfieldctl, as well as with other gar components.
5
6 use serde::{Deserialize, Serialize};
7
8 /// IPC request from client to garfield.
9 #[derive(Debug, Clone, Serialize, Deserialize)]
10 #[serde(tag = "command", rename_all = "snake_case")]
11 pub enum Command {
12 /// Open a directory in garfield.
13 Open {
14 path: String,
15 /// Open in new tab instead of current view.
16 #[serde(default)]
17 new_tab: bool,
18 },
19 /// Query current directory.
20 CurrentDir,
21 /// Query garfield status.
22 Status,
23 /// Request file picker dialog.
24 FilePicker {
25 /// Dialog title.
26 title: Option<String>,
27 /// Starting directory.
28 start_dir: Option<String>,
29 /// File type filters (e.g., "*.rs", "*.txt").
30 filters: Vec<String>,
31 /// Allow selecting multiple files.
32 #[serde(default)]
33 multiple: bool,
34 },
35 /// Request folder picker dialog.
36 FolderPicker {
37 /// Dialog title.
38 title: Option<String>,
39 /// Starting directory.
40 start_dir: Option<String>,
41 },
42 /// Quit garfield.
43 Quit,
44 }
45
46 /// IPC response from garfield to client.
47 #[derive(Debug, Clone, Serialize, Deserialize)]
48 pub struct Response {
49 /// Whether the command succeeded.
50 pub success: bool,
51 /// Response data (command-specific).
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub data: Option<serde_json::Value>,
54 /// Error message if failed.
55 #[serde(skip_serializing_if = "Option::is_none")]
56 pub error: Option<String>,
57 }
58
59 impl Response {
60 /// Create a successful response with no data.
61 pub fn ok() -> Self {
62 Self {
63 success: true,
64 data: None,
65 error: None,
66 }
67 }
68
69 /// Create a successful response with data.
70 pub fn ok_with_data(data: impl Serialize) -> Self {
71 Self {
72 success: true,
73 data: serde_json::to_value(data).ok(),
74 error: None,
75 }
76 }
77
78 /// Create an error response.
79 pub fn err(message: impl Into<String>) -> Self {
80 Self {
81 success: false,
82 data: None,
83 error: Some(message.into()),
84 }
85 }
86 }
87
88 /// Status information returned by the Status command.
89 #[derive(Debug, Clone, Serialize, Deserialize)]
90 pub struct StatusInfo {
91 /// Current working directory.
92 pub current_dir: String,
93 /// Number of open tabs.
94 pub tab_count: usize,
95 /// Number of selected files.
96 pub selection_count: usize,
97 }
98
99 /// Result of a file picker dialog.
100 #[derive(Debug, Clone, Serialize, Deserialize)]
101 pub struct PickerResult {
102 /// Selected file paths (empty if cancelled).
103 pub paths: Vec<String>,
104 /// Whether the dialog was cancelled.
105 pub cancelled: bool,
106 }
107
108 /// Default socket path for garfield IPC.
109 pub fn socket_path() -> std::path::PathBuf {
110 let runtime_dir = std::env::var("XDG_RUNTIME_DIR")
111 .unwrap_or_else(|_| "/tmp".to_string());
112 std::path::PathBuf::from(runtime_dir).join("garfield.sock")
113 }
114