proto.rs

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