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}