1use serde::{Deserialize, Deserializer, Serialize, Serializer};
39use std::collections::HashMap;
40
41#[derive(Debug, Clone, Deserialize)]
43pub struct KakColor(String);
44
45#[derive(Debug, Clone, Deserialize)]
47#[serde(rename_all = "snake_case")]
48pub enum KakAttribute {
49 Underline,
50 Reverse,
51 Blink,
52 Bold,
53 Dim,
54 Italic,
55 FinalFg,
56 FinalBg,
57 FinalAttr,
58}
59
60#[derive(Debug, Clone, Deserialize)]
62pub struct KakFace {
63 pub fg: KakColor,
64 pub bg: KakColor,
65 pub attributes: Vec<KakAttribute>,
66}
67
68#[derive(Debug, Clone, Deserialize)]
70pub struct KakAtom {
71 pub face: KakFace,
72 pub contents: String,
73}
74
75pub type KakLine = Vec<KakAtom>;
77
78#[derive(Debug, Clone, Deserialize)]
80pub struct KakCoord {
81 pub line: u32,
82 pub column: u32,
83}
84
85#[derive(Debug, Clone)]
87pub enum IncomingRequest {
88 Draw {
89 lines: Vec<KakLine>,
90 default_face: KakFace,
91 padding_face: KakFace,
92 },
93 DrawStatus {
94 status_line: KakLine,
95 mode_line: KakLine,
96 default_face: KakFace,
97 },
98 MenuShow {
99 items: Vec<KakLine>,
100 anchor: KakCoord,
101 selected_item_face: KakFace,
102 menu_face: KakFace,
103 style: String,
104 },
105 MenuSelect {
106 selected: u32,
107 },
108 MenuHide,
109 InfoShow {
110 title: KakLine,
111 content: Vec<KakLine>,
112 anchor: KakCoord,
113 face: KakFace,
114 style: String,
115 },
116 InfoHide,
117 SetCursor {
118 mode: String,
119 coord: KakCoord,
120 },
121 SetUiOptions {
122 options: HashMap<String, String>,
123 },
124 Refresh {
125 force: bool,
126 },
127}
128
129#[derive(Debug, Clone, Deserialize)]
130#[serde(rename_all = "snake_case")]
131#[serde(tag = "method", content = "params")]
132enum RawIncomingRequest {
133 Draw(Vec<KakLine>, KakFace, KakFace),
134 DrawStatus(KakLine, KakLine, KakFace),
135 MenuShow(Vec<KakLine>, KakCoord, KakFace, KakFace, String),
136 MenuSelect((u32,)),
137 MenuHide([(); 0]),
138 InfoShow(KakLine, Vec<KakLine>, KakCoord, KakFace, String),
139 InfoHide([(); 0]),
140 SetCursor(String, KakCoord),
141 SetUiOptions((HashMap<String, String>,)),
142 Refresh((bool,)),
143}
144
145impl<'de> Deserialize<'de> for IncomingRequest {
146 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147 where
148 D: Deserializer<'de>,
149 {
150 Ok(<JsonRpc<RawIncomingRequest>>::deserialize(deserializer)?
151 .inner
152 .into())
153 }
154}
155
156impl From<RawIncomingRequest> for IncomingRequest {
157 fn from(raw_request: RawIncomingRequest) -> Self {
158 type Raw = RawIncomingRequest;
159 type Processed = IncomingRequest;
160 match raw_request {
161 Raw::Draw(a, b, c) => Processed::Draw {
162 lines: a,
163 default_face: b,
164 padding_face: c,
165 },
166 Raw::DrawStatus(a, b, c) => Processed::DrawStatus {
167 status_line: a,
168 mode_line: b,
169 default_face: c,
170 },
171 Raw::MenuShow(a, b, c, d, e) => Processed::MenuShow {
172 items: a,
173 anchor: b,
174 selected_item_face: c,
175 menu_face: d,
176 style: e,
177 },
178 Raw::MenuSelect((a,)) => Processed::MenuSelect { selected: a },
179 Raw::MenuHide(_) => Processed::MenuHide,
180 Raw::InfoShow(a, b, c, d, e) => Processed::InfoShow {
181 title: a,
182 content: b,
183 anchor: c,
184 face: d,
185 style: e,
186 },
187 Raw::InfoHide(_) => Processed::InfoHide,
188 Raw::SetCursor(a, b) => Processed::SetCursor { mode: a, coord: b },
189 Raw::SetUiOptions((a,)) => Processed::SetUiOptions { options: a },
190 Raw::Refresh((a,)) => Processed::Refresh { force: a },
191 }
192 }
193}
194
195#[derive(Debug, Clone)]
197pub enum OutgoingRequest {
198 Keys(Vec<String>),
199 Resize {
200 rows: u32,
201 columns: u32,
202 },
203 Scroll {
204 amount: u32,
205 },
206 MouseMove {
207 line: u32,
208 column: u32,
209 },
210 MousePress {
211 button: String,
212 line: u32,
213 column: u32,
214 },
215 MouseRelease {
216 button: String,
217 line: u32,
218 column: u32,
219 },
220 MenuSelect {
221 index: u32,
222 },
223}
224
225#[derive(Debug, Clone, Serialize)]
226#[serde(rename_all = "snake_case")]
227#[serde(tag = "method", content = "params")]
228enum RawOutgoingRequest {
229 Keys(Vec<String>),
230 Resize(u32, u32),
231 Scroll((u32,)),
232 MouseMove(u32, u32),
233 MousePress(String, u32, u32),
234 MouseRelease(String, u32, u32),
235 MenuSelect((u32,)),
236}
237
238impl Serialize for OutgoingRequest {
239 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
240 where
241 S: Serializer,
242 {
243 JsonRpc::new(RawOutgoingRequest::from(self.clone())).serialize(serializer)
244 }
245}
246
247impl From<OutgoingRequest> for RawOutgoingRequest {
248 fn from(request: OutgoingRequest) -> Self {
249 type Raw = RawOutgoingRequest;
250 type Processed = OutgoingRequest;
251 match request {
252 Processed::Keys(vec) => Raw::Keys(vec),
253 Processed::Resize {
254 rows: a,
255 columns: b,
256 } => Raw::Resize(a, b),
257 Processed::Scroll { amount: a } => Raw::Scroll((a,)),
258 Processed::MouseMove { line: a, column: b } => Raw::MouseMove(a, b),
259 Processed::MousePress {
260 button: a,
261 line: b,
262 column: c,
263 } => Raw::MousePress(a, b, c),
264 Processed::MouseRelease {
265 button: a,
266 line: b,
267 column: c,
268 } => Raw::MouseRelease(a, b, c),
269 Processed::MenuSelect { index: a } => Raw::MenuSelect((a,)),
270 }
271 }
272}
273
274#[derive(Deserialize, Serialize)]
275struct JsonRpc<T> {
276 jsonrpc: String,
277 #[serde(flatten)]
278 pub inner: T,
279}
280
281impl<T> JsonRpc<T> {
282 fn new(inner: T) -> Self {
283 Self {
284 jsonrpc: "2.0".to_string(),
285 inner,
286 }
287 }
288}