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};
 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(proto::EditorAnchor {
126            anchor: Some(serialize_anchor(&selection.start)),
127            excerpt_id: 0,
128        }),
129        end: Some(proto::EditorAnchor {
130            anchor: Some(serialize_anchor(&selection.end)),
131            excerpt_id: 0,
132        }),
133        reversed: selection.reversed,
134    }
135}
136
137pub fn serialize_cursor_shape(cursor_shape: &CursorShape) -> proto::CursorShape {
138    match cursor_shape {
139        CursorShape::Bar => proto::CursorShape::CursorBar,
140        CursorShape::Block => proto::CursorShape::CursorBlock,
141        CursorShape::Underscore => proto::CursorShape::CursorUnderscore,
142        CursorShape::Hollow => proto::CursorShape::CursorHollow,
143    }
144}
145
146pub fn deserialize_cursor_shape(cursor_shape: proto::CursorShape) -> CursorShape {
147    match cursor_shape {
148        proto::CursorShape::CursorBar => CursorShape::Bar,
149        proto::CursorShape::CursorBlock => CursorShape::Block,
150        proto::CursorShape::CursorUnderscore => CursorShape::Underscore,
151        proto::CursorShape::CursorHollow => CursorShape::Hollow,
152    }
153}
154
155pub fn serialize_diagnostics<'a>(
156    diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
157) -> Vec<proto::Diagnostic> {
158    diagnostics
159        .into_iter()
160        .map(|entry| proto::Diagnostic {
161            start: Some(serialize_anchor(&entry.range.start)),
162            end: Some(serialize_anchor(&entry.range.end)),
163            message: entry.diagnostic.message.clone(),
164            severity: match entry.diagnostic.severity {
165                DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
166                DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
167                DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
168                DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
169                _ => proto::diagnostic::Severity::None,
170            } as i32,
171            group_id: entry.diagnostic.group_id as u64,
172            is_primary: entry.diagnostic.is_primary,
173            is_valid: entry.diagnostic.is_valid,
174            code: entry.diagnostic.code.clone(),
175            is_disk_based: entry.diagnostic.is_disk_based,
176            is_unnecessary: entry.diagnostic.is_unnecessary,
177        })
178        .collect()
179}
180
181pub fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
182    proto::Anchor {
183        replica_id: anchor.timestamp.replica_id as u32,
184        local_timestamp: anchor.timestamp.value,
185        offset: anchor.offset as u64,
186        bias: match anchor.bias {
187            Bias::Left => proto::Bias::Left as i32,
188            Bias::Right => proto::Bias::Right as i32,
189        },
190        buffer_id: anchor.buffer_id,
191    }
192}
193
194pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operation> {
195    Ok(
196        match message
197            .variant
198            .ok_or_else(|| anyhow!("missing operation variant"))?
199        {
200            proto::operation::Variant::Edit(edit) => {
201                crate::Operation::Buffer(text::Operation::Edit(deserialize_edit_operation(edit)))
202            }
203            proto::operation::Variant::Undo(undo) => {
204                crate::Operation::Buffer(text::Operation::Undo {
205                    lamport_timestamp: clock::Lamport {
206                        replica_id: undo.replica_id as ReplicaId,
207                        value: undo.lamport_timestamp,
208                    },
209                    undo: UndoOperation {
210                        id: clock::Local {
211                            replica_id: undo.replica_id as ReplicaId,
212                            value: undo.local_timestamp,
213                        },
214                        version: deserialize_version(undo.version),
215                        counts: undo
216                            .counts
217                            .into_iter()
218                            .map(|c| {
219                                (
220                                    clock::Local {
221                                        replica_id: c.replica_id as ReplicaId,
222                                        value: c.local_timestamp,
223                                    },
224                                    c.count,
225                                )
226                            })
227                            .collect(),
228                    },
229                })
230            }
231            proto::operation::Variant::UpdateSelections(message) => {
232                let selections = message
233                    .selections
234                    .into_iter()
235                    .filter_map(|selection| {
236                        Some(Selection {
237                            id: selection.id as usize,
238                            start: deserialize_anchor(selection.start?.anchor?)?,
239                            end: deserialize_anchor(selection.end?.anchor?)?,
240                            reversed: selection.reversed,
241                            goal: SelectionGoal::None,
242                        })
243                    })
244                    .collect::<Vec<_>>();
245
246                crate::Operation::UpdateSelections {
247                    lamport_timestamp: clock::Lamport {
248                        replica_id: message.replica_id as ReplicaId,
249                        value: message.lamport_timestamp,
250                    },
251                    selections: Arc::from(selections),
252                    line_mode: message.line_mode,
253                    cursor_shape: deserialize_cursor_shape(
254                        proto::CursorShape::from_i32(message.cursor_shape)
255                            .ok_or_else(|| anyhow!("Missing cursor shape"))?,
256                    ),
257                }
258            }
259            proto::operation::Variant::UpdateDiagnostics(message) => {
260                crate::Operation::UpdateDiagnostics {
261                    diagnostics: deserialize_diagnostics(message.diagnostics),
262                    lamport_timestamp: clock::Lamport {
263                        replica_id: message.replica_id as ReplicaId,
264                        value: message.lamport_timestamp,
265                    },
266                }
267            }
268            proto::operation::Variant::UpdateCompletionTriggers(message) => {
269                crate::Operation::UpdateCompletionTriggers {
270                    triggers: message.triggers,
271                    lamport_timestamp: clock::Lamport {
272                        replica_id: message.replica_id as ReplicaId,
273                        value: message.lamport_timestamp,
274                    },
275                }
276            }
277        },
278    )
279}
280
281pub fn deserialize_edit_operation(edit: proto::operation::Edit) -> EditOperation {
282    EditOperation {
283        timestamp: InsertionTimestamp {
284            replica_id: edit.replica_id as ReplicaId,
285            local: edit.local_timestamp,
286            lamport: edit.lamport_timestamp,
287        },
288        version: deserialize_version(edit.version),
289        ranges: edit.ranges.into_iter().map(deserialize_range).collect(),
290        new_text: edit.new_text.into_iter().map(Arc::from).collect(),
291    }
292}
293
294pub fn deserialize_undo_map_entry(
295    entry: proto::UndoMapEntry,
296) -> (clock::Local, Vec<(clock::Local, u32)>) {
297    (
298        clock::Local {
299            replica_id: entry.replica_id as u16,
300            value: entry.local_timestamp,
301        },
302        entry
303            .counts
304            .into_iter()
305            .map(|undo_count| {
306                (
307                    clock::Local {
308                        replica_id: undo_count.replica_id as u16,
309                        value: undo_count.local_timestamp,
310                    },
311                    undo_count.count,
312                )
313            })
314            .collect(),
315    )
316}
317
318pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selection<Anchor>]> {
319    Arc::from(
320        selections
321            .into_iter()
322            .filter_map(deserialize_selection)
323            .collect::<Vec<_>>(),
324    )
325}
326
327pub fn deserialize_selection(selection: proto::Selection) -> Option<Selection<Anchor>> {
328    Some(Selection {
329        id: selection.id as usize,
330        start: deserialize_anchor(selection.start?.anchor?)?,
331        end: deserialize_anchor(selection.end?.anchor?)?,
332        reversed: selection.reversed,
333        goal: SelectionGoal::None,
334    })
335}
336
337pub fn deserialize_diagnostics(
338    diagnostics: Vec<proto::Diagnostic>,
339) -> Arc<[DiagnosticEntry<Anchor>]> {
340    diagnostics
341        .into_iter()
342        .filter_map(|diagnostic| {
343            Some(DiagnosticEntry {
344                range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
345                diagnostic: Diagnostic {
346                    severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
347                        proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
348                        proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
349                        proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
350                        proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
351                        proto::diagnostic::Severity::None => return None,
352                    },
353                    message: diagnostic.message,
354                    group_id: diagnostic.group_id as usize,
355                    code: diagnostic.code,
356                    is_valid: diagnostic.is_valid,
357                    is_primary: diagnostic.is_primary,
358                    is_disk_based: diagnostic.is_disk_based,
359                    is_unnecessary: diagnostic.is_unnecessary,
360                },
361            })
362        })
363        .collect()
364}
365
366pub fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
367    Some(Anchor {
368        timestamp: clock::Local {
369            replica_id: anchor.replica_id as ReplicaId,
370            value: anchor.local_timestamp,
371        },
372        offset: anchor.offset as usize,
373        bias: match proto::Bias::from_i32(anchor.bias)? {
374            proto::Bias::Left => Bias::Left,
375            proto::Bias::Right => Bias::Right,
376        },
377        buffer_id: anchor.buffer_id,
378    })
379}
380
381pub fn lamport_timestamp_for_operation(operation: &proto::Operation) -> Option<clock::Lamport> {
382    let replica_id;
383    let value;
384    match operation.variant.as_ref()? {
385        proto::operation::Variant::Edit(op) => {
386            replica_id = op.replica_id;
387            value = op.lamport_timestamp;
388        }
389        proto::operation::Variant::Undo(op) => {
390            replica_id = op.replica_id;
391            value = op.lamport_timestamp;
392        }
393        proto::operation::Variant::UpdateDiagnostics(op) => {
394            replica_id = op.replica_id;
395            value = op.lamport_timestamp;
396        }
397        proto::operation::Variant::UpdateSelections(op) => {
398            replica_id = op.replica_id;
399            value = op.lamport_timestamp;
400        }
401        proto::operation::Variant::UpdateCompletionTriggers(op) => {
402            replica_id = op.replica_id;
403            value = op.lamport_timestamp;
404        }
405    }
406
407    Some(clock::Lamport {
408        replica_id: replica_id as ReplicaId,
409        value,
410    })
411}
412
413pub fn serialize_completion(completion: &Completion) -> proto::Completion {
414    proto::Completion {
415        old_start: Some(serialize_anchor(&completion.old_range.start)),
416        old_end: Some(serialize_anchor(&completion.old_range.end)),
417        new_text: completion.new_text.clone(),
418        lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
419    }
420}
421
422pub async fn deserialize_completion(
423    completion: proto::Completion,
424    language: Option<Arc<Language>>,
425) -> Result<Completion> {
426    let old_start = completion
427        .old_start
428        .and_then(deserialize_anchor)
429        .ok_or_else(|| anyhow!("invalid old start"))?;
430    let old_end = completion
431        .old_end
432        .and_then(deserialize_anchor)
433        .ok_or_else(|| anyhow!("invalid old end"))?;
434    let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
435
436    let mut label = None;
437    if let Some(language) = language {
438        label = language.label_for_completion(&lsp_completion).await;
439    }
440
441    Ok(Completion {
442        old_range: old_start..old_end,
443        new_text: completion.new_text,
444        label: label.unwrap_or_else(|| {
445            CodeLabel::plain(
446                lsp_completion.label.clone(),
447                lsp_completion.filter_text.as_deref(),
448            )
449        }),
450        lsp_completion,
451    })
452}
453
454pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
455    proto::CodeAction {
456        start: Some(serialize_anchor(&action.range.start)),
457        end: Some(serialize_anchor(&action.range.end)),
458        lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
459    }
460}
461
462pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
463    let start = action
464        .start
465        .and_then(deserialize_anchor)
466        .ok_or_else(|| anyhow!("invalid start"))?;
467    let end = action
468        .end
469        .and_then(deserialize_anchor)
470        .ok_or_else(|| anyhow!("invalid end"))?;
471    let lsp_action = serde_json::from_slice(&action.lsp_action)?;
472    Ok(CodeAction {
473        range: start..end,
474        lsp_action,
475    })
476}
477
478pub fn serialize_transaction(transaction: &Transaction) -> proto::Transaction {
479    proto::Transaction {
480        id: Some(serialize_local_timestamp(transaction.id)),
481        edit_ids: transaction
482            .edit_ids
483            .iter()
484            .copied()
485            .map(serialize_local_timestamp)
486            .collect(),
487        start: serialize_version(&transaction.start),
488    }
489}
490
491pub fn deserialize_transaction(transaction: proto::Transaction) -> Result<Transaction> {
492    Ok(Transaction {
493        id: deserialize_local_timestamp(
494            transaction
495                .id
496                .ok_or_else(|| anyhow!("missing transaction id"))?,
497        ),
498        edit_ids: transaction
499            .edit_ids
500            .into_iter()
501            .map(deserialize_local_timestamp)
502            .collect(),
503        start: deserialize_version(transaction.start),
504    })
505}
506
507pub fn serialize_local_timestamp(timestamp: clock::Local) -> proto::LocalTimestamp {
508    proto::LocalTimestamp {
509        replica_id: timestamp.replica_id as u32,
510        value: timestamp.value,
511    }
512}
513
514pub fn deserialize_local_timestamp(timestamp: proto::LocalTimestamp) -> clock::Local {
515    clock::Local {
516        replica_id: timestamp.replica_id as ReplicaId,
517        value: timestamp.value,
518    }
519}
520
521pub fn serialize_range(range: &Range<FullOffset>) -> proto::Range {
522    proto::Range {
523        start: range.start.0 as u64,
524        end: range.end.0 as u64,
525    }
526}
527
528pub fn deserialize_range(range: proto::Range) -> Range<FullOffset> {
529    FullOffset(range.start as usize)..FullOffset(range.end as usize)
530}
531
532pub fn deserialize_version(message: Vec<proto::VectorClockEntry>) -> clock::Global {
533    let mut version = clock::Global::new();
534    for entry in message {
535        version.observe(clock::Local {
536            replica_id: entry.replica_id as ReplicaId,
537            value: entry.timestamp,
538        });
539    }
540    version
541}
542
543pub fn serialize_version(version: &clock::Global) -> Vec<proto::VectorClockEntry> {
544    version
545        .iter()
546        .map(|entry| proto::VectorClockEntry {
547            replica_id: entry.replica_id as u32,
548            timestamp: entry.value,
549        })
550        .collect()
551}