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