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, LineEnding, Operation, SelectionSet};
12
13pub fn deserialize_line_ending(message: proto::LineEnding) -> text::LineEnding {
14 match message {
15 LineEnding::Unix => text::LineEnding::Unix,
16 LineEnding::Windows => text::LineEnding::Windows,
17 }
18}
19
20pub fn serialize_line_ending(message: text::LineEnding) -> proto::LineEnding {
21 match message {
22 text::LineEnding::Unix => proto::LineEnding::Unix,
23 text::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}