proto.rs

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