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}