1use crate::{diagnostic_set::DiagnosticEntry, Completion, Diagnostic, Language, Operation};
2use anyhow::{anyhow, Result};
3use clock::ReplicaId;
4use collections::HashSet;
5use lsp::DiagnosticSeverity;
6use rpc::proto;
7use std::sync::Arc;
8use text::*;
9
10pub use proto::{Buffer, BufferState, SelectionSet};
11
12pub fn serialize_operation(operation: &Operation) -> proto::Operation {
13 proto::Operation {
14 variant: Some(match operation {
15 Operation::Buffer(text::Operation::Edit(edit)) => {
16 proto::operation::Variant::Edit(serialize_edit_operation(edit))
17 }
18 Operation::Buffer(text::Operation::Undo {
19 undo,
20 lamport_timestamp,
21 }) => proto::operation::Variant::Undo(proto::operation::Undo {
22 replica_id: undo.id.replica_id as u32,
23 local_timestamp: undo.id.value,
24 lamport_timestamp: lamport_timestamp.value,
25 ranges: undo
26 .ranges
27 .iter()
28 .map(|r| proto::Range {
29 start: r.start.0 as u64,
30 end: r.end.0 as u64,
31 })
32 .collect(),
33 counts: undo
34 .counts
35 .iter()
36 .map(|(edit_id, count)| proto::UndoCount {
37 replica_id: edit_id.replica_id as u32,
38 local_timestamp: edit_id.value,
39 count: *count,
40 })
41 .collect(),
42 version: From::from(&undo.version),
43 }),
44 Operation::UpdateSelections {
45 replica_id,
46 selections,
47 lamport_timestamp,
48 } => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections {
49 replica_id: *replica_id as u32,
50 lamport_timestamp: lamport_timestamp.value,
51 selections: serialize_selections(selections),
52 }),
53 Operation::UpdateDiagnostics {
54 diagnostics,
55 lamport_timestamp,
56 } => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics {
57 replica_id: lamport_timestamp.replica_id as u32,
58 lamport_timestamp: lamport_timestamp.value,
59 diagnostics: serialize_diagnostics(diagnostics.iter()),
60 }),
61 Operation::UpdateCompletionTriggers { triggers } => {
62 proto::operation::Variant::UpdateCompletionTriggers(
63 proto::operation::UpdateCompletionTriggers {
64 triggers: triggers.clone(),
65 },
66 )
67 }
68 }),
69 }
70}
71
72pub fn serialize_edit_operation(operation: &EditOperation) -> proto::operation::Edit {
73 let ranges = operation
74 .ranges
75 .iter()
76 .map(|range| proto::Range {
77 start: range.start.0 as u64,
78 end: range.end.0 as u64,
79 })
80 .collect();
81 proto::operation::Edit {
82 replica_id: operation.timestamp.replica_id as u32,
83 local_timestamp: operation.timestamp.local,
84 lamport_timestamp: operation.timestamp.lamport,
85 version: From::from(&operation.version),
86 ranges,
87 new_text: operation.new_text.clone(),
88 }
89}
90
91pub fn serialize_undo_map_entry(
92 (edit_id, counts): (&clock::Local, &[(clock::Local, u32)]),
93) -> proto::UndoMapEntry {
94 proto::UndoMapEntry {
95 replica_id: edit_id.replica_id as u32,
96 local_timestamp: edit_id.value,
97 counts: counts
98 .iter()
99 .map(|(undo_id, count)| proto::UndoCount {
100 replica_id: undo_id.replica_id as u32,
101 local_timestamp: undo_id.value,
102 count: *count,
103 })
104 .collect(),
105 }
106}
107
108pub fn serialize_buffer_fragment(fragment: &text::Fragment) -> proto::BufferFragment {
109 proto::BufferFragment {
110 replica_id: fragment.insertion_timestamp.replica_id as u32,
111 local_timestamp: fragment.insertion_timestamp.local,
112 lamport_timestamp: fragment.insertion_timestamp.lamport,
113 insertion_offset: fragment.insertion_offset as u32,
114 len: fragment.len as u32,
115 visible: fragment.visible,
116 deletions: fragment
117 .deletions
118 .iter()
119 .map(|clock| proto::VectorClockEntry {
120 replica_id: clock.replica_id as u32,
121 timestamp: clock.value,
122 })
123 .collect(),
124 max_undos: From::from(&fragment.max_undos),
125 }
126}
127
128pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto::Selection> {
129 selections
130 .iter()
131 .map(|selection| proto::Selection {
132 id: selection.id as u64,
133 start: Some(serialize_anchor(&selection.start)),
134 end: Some(serialize_anchor(&selection.end)),
135 reversed: selection.reversed,
136 })
137 .collect()
138}
139
140pub fn serialize_diagnostics<'a>(
141 diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
142) -> Vec<proto::Diagnostic> {
143 diagnostics
144 .into_iter()
145 .map(|entry| proto::Diagnostic {
146 start: Some(serialize_anchor(&entry.range.start)),
147 end: Some(serialize_anchor(&entry.range.end)),
148 message: entry.diagnostic.message.clone(),
149 severity: match entry.diagnostic.severity {
150 DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
151 DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
152 DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
153 DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
154 _ => proto::diagnostic::Severity::None,
155 } as i32,
156 group_id: entry.diagnostic.group_id as u64,
157 is_primary: entry.diagnostic.is_primary,
158 is_valid: entry.diagnostic.is_valid,
159 code: entry.diagnostic.code.clone(),
160 is_disk_based: entry.diagnostic.is_disk_based,
161 })
162 .collect()
163}
164
165pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
166 proto::Anchor {
167 replica_id: anchor.timestamp.replica_id as u32,
168 local_timestamp: anchor.timestamp.value,
169 offset: anchor.offset as u64,
170 bias: match anchor.bias {
171 Bias::Left => proto::Bias::Left as i32,
172 Bias::Right => proto::Bias::Right as i32,
173 },
174 }
175}
176
177pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
178 Ok(
179 match message
180 .variant
181 .ok_or_else(|| anyhow!("missing operation variant"))?
182 {
183 proto::operation::Variant::Edit(edit) => {
184 Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
185 }
186 proto::operation::Variant::Undo(undo) => Operation::Buffer(text::Operation::Undo {
187 lamport_timestamp: clock::Lamport {
188 replica_id: undo.replica_id as ReplicaId,
189 value: undo.lamport_timestamp,
190 },
191 undo: UndoOperation {
192 id: clock::Local {
193 replica_id: undo.replica_id as ReplicaId,
194 value: undo.local_timestamp,
195 },
196 counts: undo
197 .counts
198 .into_iter()
199 .map(|c| {
200 (
201 clock::Local {
202 replica_id: c.replica_id as ReplicaId,
203 value: c.local_timestamp,
204 },
205 c.count,
206 )
207 })
208 .collect(),
209 ranges: undo
210 .ranges
211 .into_iter()
212 .map(|r| FullOffset(r.start as usize)..FullOffset(r.end as usize))
213 .collect(),
214 version: undo.version.into(),
215 },
216 }),
217 proto::operation::Variant::UpdateSelections(message) => {
218 let selections = message
219 .selections
220 .into_iter()
221 .filter_map(|selection| {
222 Some(Selection {
223 id: selection.id as usize,
224 start: deserialize_anchor(selection.start?)?,
225 end: deserialize_anchor(selection.end?)?,
226 reversed: selection.reversed,
227 goal: SelectionGoal::None,
228 })
229 })
230 .collect::<Vec<_>>();
231
232 Operation::UpdateSelections {
233 replica_id: message.replica_id as ReplicaId,
234 lamport_timestamp: clock::Lamport {
235 replica_id: message.replica_id as ReplicaId,
236 value: message.lamport_timestamp,
237 },
238 selections: Arc::from(selections),
239 }
240 }
241 proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
242 diagnostics: deserialize_diagnostics(message.diagnostics),
243 lamport_timestamp: clock::Lamport {
244 replica_id: message.replica_id as ReplicaId,
245 value: message.lamport_timestamp,
246 },
247 },
248 proto::operation::Variant::UpdateCompletionTriggers(message) => {
249 Operation::UpdateCompletionTriggers {
250 triggers: message.triggers,
251 }
252 }
253 },
254 )
255}
256
257pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
258 let ranges = edit
259 .ranges
260 .into_iter()
261 .map(|range| FullOffset(range.start as usize)..FullOffset(range.end as usize))
262 .collect();
263 EditOperation {
264 timestamp: InsertionTimestamp {
265 replica_id: edit.replica_id as ReplicaId,
266 local: edit.local_timestamp,
267 lamport: edit.lamport_timestamp,
268 },
269 version: edit.version.into(),
270 ranges,
271 new_text: edit.new_text,
272 }
273}
274
275pub fn deserialize_undo_map_entry(
276 entry: proto::UndoMapEntry,
277) -> (clock::Local, Vec<(clock::Local, u32)>) {
278 (
279 clock::Local {
280 replica_id: entry.replica_id as u16,
281 value: entry.local_timestamp,
282 },
283 entry
284 .counts
285 .into_iter()
286 .map(|undo_count| {
287 (
288 clock::Local {
289 replica_id: undo_count.replica_id as u16,
290 value: undo_count.local_timestamp,
291 },
292 undo_count.count,
293 )
294 })
295 .collect(),
296 )
297}
298
299pub fn deserialize_buffer_fragment(
300 message: proto::BufferFragment,
301 ix: usize,
302 count: usize,
303) -> Fragment {
304 Fragment {
305 id: locator::Locator::from_index(ix, count),
306 insertion_timestamp: InsertionTimestamp {
307 replica_id: message.replica_id as ReplicaId,
308 local: message.local_timestamp,
309 lamport: message.lamport_timestamp,
310 },
311 insertion_offset: message.insertion_offset as usize,
312 len: message.len as usize,
313 visible: message.visible,
314 deletions: HashSet::from_iter(message.deletions.into_iter().map(|entry| clock::Local {
315 replica_id: entry.replica_id as ReplicaId,
316 value: entry.timestamp,
317 })),
318 max_undos: From::from(message.max_undos),
319 }
320}
321
322pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
323 Arc::from(
324 selections
325 .into_iter()
326 .filter_map(|selection| {
327 Some(Selection {
328 id: selection.id as usize,
329 start: deserialize_anchor(selection.start?)?,
330 end: deserialize_anchor(selection.end?)?,
331 reversed: selection.reversed,
332 goal: SelectionGoal::None,
333 })
334 })
335 .collect::<Vec<_>>(),
336 )
337}
338
339pub fn deserialize_diagnostics(
340 diagnostics: Vec<proto::Diagnostic>,
341) -> Arc<[DiagnosticEntry<Anchor>]> {
342 diagnostics
343 .into_iter()
344 .filter_map(|diagnostic| {
345 Some(DiagnosticEntry {
346 range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
347 diagnostic: Diagnostic {
348 severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
349 proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
350 proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
351 proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
352 proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
353 proto::diagnostic::Severity::None => return None,
354 },
355 message: diagnostic.message,
356 group_id: diagnostic.group_id as usize,
357 code: diagnostic.code,
358 is_valid: diagnostic.is_valid,
359 is_primary: diagnostic.is_primary,
360 is_disk_based: diagnostic.is_disk_based,
361 },
362 })
363 })
364 .collect()
365}
366
367pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
368 Some(Anchor {
369 timestamp: clock::Local {
370 replica_id: anchor.replica_id as ReplicaId,
371 value: anchor.local_timestamp,
372 },
373 offset: anchor.offset as usize,
374 bias: match proto::Bias::from_i32(anchor.bias)? {
375 proto::Bias::Left => Bias::Left,
376 proto::Bias::Right => Bias::Right,
377 },
378 })
379}
380
381pub fn serialize_completion(completion: &Completion<Anchor>) -> proto::Completion {
382 proto::Completion {
383 old_start: Some(serialize_anchor(&completion.old_range.start)),
384 old_end: Some(serialize_anchor(&completion.old_range.end)),
385 new_text: completion.new_text.clone(),
386 lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
387 }
388}
389
390pub fn deserialize_completion(
391 completion: proto::Completion,
392 language: Option<&Arc<Language>>,
393) -> Result<Completion<Anchor>> {
394 let old_start = completion
395 .old_start
396 .and_then(deserialize_anchor)
397 .ok_or_else(|| anyhow!("invalid old start"))?;
398 let old_end = completion
399 .old_end
400 .and_then(deserialize_anchor)
401 .ok_or_else(|| anyhow!("invalid old end"))?;
402 let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
403 Ok(Completion {
404 old_range: old_start..old_end,
405 new_text: completion.new_text,
406 label: language.and_then(|l| l.label_for_completion(&lsp_completion)),
407 lsp_completion,
408 })
409}