1use crate::schema::{ColorRole, DecorationKind, GutterDecorationKind, HoverPhase, Paint, Severity};
22use std::rc::Rc;
23
24pub const DECORATION_LEN: usize = 44;
26
27pub const SYNTAX_SPAN_LEN: usize = 28;
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub enum RecordFieldType {
33 U32,
34 U64,
35 Role {
38 name: &'static str,
39 optional: bool,
40 },
41 Paint,
43 Flag,
45 Text,
48}
49
50#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52pub struct RecordField {
53 pub name: &'static str,
54 pub offset: u16,
55 pub ty: RecordFieldType,
56}
57
58#[derive(Clone, Copy, Debug, Eq, PartialEq)]
63pub struct RecordSchema {
64 pub name: &'static str,
66 pub length: u16,
67 pub fields: &'static [RecordField],
68}
69
70const fn field(name: &'static str, offset: u16, ty: RecordFieldType) -> RecordField {
71 RecordField { name, offset, ty }
72}
73
74pub const DECORATION_RECORD: RecordSchema = RecordSchema {
78 name: "DecorationRecord",
79 length: DECORATION_LEN as u16,
80 fields: &[
81 field("version", 0, RecordFieldType::U32),
82 field(
83 "kind",
84 4,
85 RecordFieldType::Role {
86 name: "DecorationKind",
87 optional: false,
88 },
89 ),
90 field(
91 "severity",
92 6,
93 RecordFieldType::Role {
94 name: "Severity",
95 optional: true,
96 },
97 ),
98 field(
99 "color",
100 8,
101 RecordFieldType::Role {
102 name: "ColorRole",
103 optional: true,
104 },
105 ),
106 field("startLine", 12, RecordFieldType::U32),
107 field("startColumn", 16, RecordFieldType::U32),
108 field("endLine", 20, RecordFieldType::U32),
109 field("endColumn", 24, RecordFieldType::U32),
110 field("id", 28, RecordFieldType::U64),
111 field("text", 36, RecordFieldType::Text),
112 ],
113};
114
115pub const SYNTAX_SPAN_RECORD: RecordSchema = RecordSchema {
117 name: "SyntaxSpanRecord",
118 length: SYNTAX_SPAN_LEN as u16,
119 fields: &[
120 field("version", 0, RecordFieldType::U32),
121 field("startLine", 4, RecordFieldType::U32),
122 field("startColumn", 8, RecordFieldType::U32),
123 field("endLine", 12, RecordFieldType::U32),
124 field("endColumn", 16, RecordFieldType::U32),
125 field("paint", 20, RecordFieldType::Paint),
126 ],
127};
128
129pub const FOLD_LEN: usize = 16;
131
132pub const GUTTER_DECORATION_LEN: usize = 28;
134
135pub const FOLD_RECORD: RecordSchema = RecordSchema {
139 name: "FoldRecord",
140 length: FOLD_LEN as u16,
141 fields: &[
142 field("version", 0, RecordFieldType::U32),
143 field("startLine", 4, RecordFieldType::U32),
144 field("endLine", 8, RecordFieldType::U32),
145 field("collapsed", 12, RecordFieldType::Flag),
146 ],
147};
148
149pub const GUTTER_DECORATION_RECORD: RecordSchema = RecordSchema {
153 name: "GutterDecorationRecord",
154 length: GUTTER_DECORATION_LEN as u16,
155 fields: &[
156 field("version", 0, RecordFieldType::U32),
157 field("line", 4, RecordFieldType::U32),
158 field(
159 "kind",
160 8,
161 RecordFieldType::Role {
162 name: "GutterDecorationKind",
163 optional: false,
164 },
165 ),
166 field(
167 "color",
168 10,
169 RecordFieldType::Role {
170 name: "ColorRole",
171 optional: true,
172 },
173 ),
174 field("id", 12, RecordFieldType::U64),
175 field("glyph", 20, RecordFieldType::U32),
176 ],
177};
178
179const fn hash_bytes(mut hash: u64, bytes: &[u8]) -> u64 {
180 let mut index = 0;
181 while index < bytes.len() {
182 hash ^= bytes[index] as u64;
183 hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
184 index += 1;
185 }
186 hash
187}
188
189pub(crate) const fn hash_record_schema(mut hash: u64, schema: RecordSchema) -> u64 {
192 hash = hash_bytes(hash, schema.name.as_bytes());
193 hash = hash_bytes(hash, &schema.length.to_le_bytes());
194 let mut index = 0;
195 while index < schema.fields.len() {
196 let field = schema.fields[index];
197 hash = hash_bytes(hash, field.name.as_bytes());
198 hash = hash_bytes(hash, &field.offset.to_le_bytes());
199 hash = match field.ty {
200 RecordFieldType::U32 => hash_bytes(hash, &[1]),
201 RecordFieldType::U64 => hash_bytes(hash, &[2]),
202 RecordFieldType::Role { name, optional } => {
203 let hash = hash_bytes(hash, &[3, optional as u8]);
204 hash_bytes(hash, name.as_bytes())
205 }
206 RecordFieldType::Paint => hash_bytes(hash, &[4]),
207 RecordFieldType::Text => hash_bytes(hash, &[5]),
208 RecordFieldType::Flag => hash_bytes(hash, &[6]),
209 };
210 index += 1;
211 }
212 hash
213}
214
215#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
218pub struct Position {
219 pub line: u32,
220 pub column: u32,
221}
222
223impl Position {
224 pub const fn new(line: u32, column: u32) -> Self {
225 Self { line, column }
226 }
227}
228
229#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
231pub struct CodeRange {
232 pub start: Position,
233 pub end: Position,
234}
235
236impl CodeRange {
237 pub const fn new(start: Position, end: Position) -> Self {
238 Self { start, end }
239 }
240
241 pub const fn at(position: Position) -> Self {
243 Self {
244 start: position,
245 end: position,
246 }
247 }
248
249 pub const fn of(start_line: u32, start_column: u32, end_line: u32, end_column: u32) -> Self {
251 Self {
252 start: Position::new(start_line, start_column),
253 end: Position::new(end_line, end_column),
254 }
255 }
256
257 pub fn is_empty(&self) -> bool {
258 self.start == self.end
259 }
260}
261
262#[derive(Clone, Debug, PartialEq)]
268pub struct Decoration {
269 pub version: u32,
271 pub kind: DecorationKind,
272 pub severity: Option<Severity>,
274 pub color: Option<ColorRole>,
277 pub range: CodeRange,
278 pub id: u64,
281 pub text: String,
283}
284
285impl Decoration {
286 pub fn underline(version: u32, range: CodeRange, severity: Severity) -> Self {
288 Self {
289 version,
290 kind: DecorationKind::Underline,
291 severity: Some(severity),
292 color: None,
293 range,
294 id: 0,
295 text: String::new(),
296 }
297 }
298
299 pub fn code_lens(version: u32, line: u32, text: impl Into<String>, id: u64) -> Self {
301 Self {
302 version,
303 kind: DecorationKind::CodeLens,
304 severity: None,
305 color: None,
306 range: CodeRange::at(Position::new(line, 0)),
307 id,
308 text: text.into(),
309 }
310 }
311
312 pub fn hover_anchor(version: u32, range: CodeRange, id: u64) -> Self {
314 Self {
315 version,
316 kind: DecorationKind::HoverAnchor,
317 severity: None,
318 color: None,
319 range,
320 id,
321 text: String::new(),
322 }
323 }
324
325 pub fn ghost_text(version: u32, at: Position, text: impl Into<String>, id: u64) -> Self {
328 Self {
329 version,
330 kind: DecorationKind::GhostText,
331 severity: None,
332 color: None,
333 range: CodeRange::at(at),
334 id,
335 text: text.into(),
336 }
337 }
338
339 pub fn with_color(mut self, role: ColorRole) -> Self {
341 self.color = Some(role);
342 self
343 }
344
345 pub fn with_id(mut self, id: u64) -> Self {
346 self.id = id;
347 self
348 }
349}
350
351fn put_u16(out: &mut Vec<u8>, value: u16) {
352 out.extend_from_slice(&value.to_le_bytes());
353}
354
355fn put_u32(out: &mut Vec<u8>, value: u32) {
356 out.extend_from_slice(&value.to_le_bytes());
357}
358
359fn put_u64(out: &mut Vec<u8>, value: u64) {
360 out.extend_from_slice(&value.to_le_bytes());
361}
362
363fn put_range(out: &mut Vec<u8>, range: CodeRange) {
364 put_u32(out, range.start.line);
365 put_u32(out, range.start.column);
366 put_u32(out, range.end.line);
367 put_u32(out, range.end.column);
368}
369
370fn word(record: &[u8], at: usize) -> u32 {
371 u32::from_le_bytes([record[at], record[at + 1], record[at + 2], record[at + 3]])
372}
373
374fn half(record: &[u8], at: usize) -> u16 {
375 u16::from_le_bytes([record[at], record[at + 1]])
376}
377
378fn long(record: &[u8], at: usize) -> u64 {
379 u64::from(word(record, at)) | (u64::from(word(record, at + 4)) << 32)
380}
381
382fn range_at(record: &[u8], at: usize) -> CodeRange {
383 CodeRange::of(
384 word(record, at),
385 word(record, at + 4),
386 word(record, at + 8),
387 word(record, at + 12),
388 )
389}
390
391#[derive(Clone, Default, PartialEq)]
397pub struct Decorations {
398 bytes: Option<Rc<[u8]>>,
399}
400
401impl std::fmt::Debug for Decorations {
402 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
403 formatter
404 .debug_struct("Decorations")
405 .field("decorations", &self.decorations().len())
406 .finish()
407 }
408}
409
410impl Decorations {
411 pub fn new(decorations: impl IntoIterator<Item = Decoration>) -> Self {
412 let decorations: Vec<Decoration> = decorations.into_iter().collect();
413 let records_len = decorations.len() * DECORATION_LEN;
414 let mut bytes = Vec::with_capacity(records_len);
415 let mut texts = Vec::new();
416 for decoration in &decorations {
417 put_u32(&mut bytes, decoration.version);
418 put_u16(&mut bytes, decoration.kind as u16);
419 put_u16(
420 &mut bytes,
421 decoration.severity.map_or(0, |value| value as u16),
422 );
423 put_u16(&mut bytes, decoration.color.map_or(0, |value| value as u16));
424 put_u16(&mut bytes, 0);
425 put_range(&mut bytes, decoration.range);
426 put_u64(&mut bytes, decoration.id);
427 put_u32(&mut bytes, (records_len + texts.len()) as u32);
430 put_u32(&mut bytes, decoration.text.len() as u32);
431 texts.extend_from_slice(decoration.text.as_bytes());
432 }
433 bytes.extend_from_slice(&texts);
434 Self::from_bytes(bytes)
435 }
436
437 pub fn from_bytes(bytes: impl Into<Rc<[u8]>>) -> Self {
439 let bytes = bytes.into();
440 Self {
441 bytes: (!bytes.is_empty()).then_some(bytes),
442 }
443 }
444
445 pub fn as_bytes(&self) -> &[u8] {
446 self.bytes.as_deref().unwrap_or(&[])
447 }
448
449 pub fn is_empty(&self) -> bool {
450 self.bytes.is_none()
451 }
452
453 pub fn decorations(&self) -> Vec<Decoration> {
460 let bytes = self.as_bytes();
461 let mut end = bytes.len();
462 let mut at = 0;
463 let mut found = Vec::new();
464 while at + DECORATION_LEN <= end {
465 let record = &bytes[at..at + DECORATION_LEN];
466 at += DECORATION_LEN;
467 let text_offset = word(record, 36) as usize;
468 let text_len = word(record, 40) as usize;
469 if text_len > 0 {
470 end = end.min(text_offset);
471 }
472 let Ok(kind) = DecorationKind::try_from(half(record, 4)) else {
473 continue;
474 };
475 let severity = match half(record, 6) {
476 0 => None,
477 tag => match Severity::try_from(tag) {
478 Ok(severity) => Some(severity),
479 Err(()) => continue,
480 },
481 };
482 let color = match half(record, 8) {
483 0 => None,
484 tag => match ColorRole::try_from(tag) {
485 Ok(role) => Some(role),
486 Err(()) => continue,
487 },
488 };
489 let text = if text_len == 0 {
490 String::new()
491 } else {
492 match bytes
493 .get(text_offset..text_offset + text_len)
494 .and_then(|run| std::str::from_utf8(run).ok())
495 {
496 Some(text) => text.to_owned(),
497 None => continue,
498 }
499 };
500 found.push(Decoration {
501 version: word(record, 0),
502 kind,
503 severity,
504 color,
505 range: range_at(record, 12),
506 id: long(record, 28),
507 text,
508 });
509 }
510 found
511 }
512}
513
514#[derive(Clone, Copy, Debug, PartialEq)]
520pub struct SyntaxSpan {
521 pub version: u32,
522 pub range: CodeRange,
523 pub paint: Paint,
524}
525
526impl SyntaxSpan {
527 pub const fn new(version: u32, range: CodeRange, paint: Paint) -> Self {
528 Self {
529 version,
530 range,
531 paint,
532 }
533 }
534
535 pub const fn role(version: u32, range: CodeRange, role: ColorRole) -> Self {
537 Self::new(version, range, Paint::Role(role))
538 }
539}
540
541#[derive(Clone, Default, PartialEq)]
543pub struct SyntaxSpans {
544 bytes: Option<Rc<[u8]>>,
545}
546
547impl std::fmt::Debug for SyntaxSpans {
548 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
549 formatter
550 .debug_struct("SyntaxSpans")
551 .field("spans", &(self.as_bytes().len() / SYNTAX_SPAN_LEN))
552 .finish()
553 }
554}
555
556impl SyntaxSpans {
557 pub fn new(spans: impl IntoIterator<Item = SyntaxSpan>) -> Self {
558 let mut bytes = Vec::new();
559 for span in spans {
560 put_u32(&mut bytes, span.version);
561 put_range(&mut bytes, span.range);
562 put_u64(&mut bytes, span.paint.to_bits());
563 }
564 Self::from_bytes(bytes)
565 }
566
567 pub fn from_bytes(bytes: impl Into<Rc<[u8]>>) -> Self {
568 let bytes = bytes.into();
569 Self {
570 bytes: (!bytes.is_empty()).then_some(bytes),
571 }
572 }
573
574 pub fn as_bytes(&self) -> &[u8] {
575 self.bytes.as_deref().unwrap_or(&[])
576 }
577
578 pub fn is_empty(&self) -> bool {
579 self.bytes.is_none()
580 }
581
582 pub fn spans(&self) -> Vec<SyntaxSpan> {
585 self.as_bytes()
586 .chunks_exact(SYNTAX_SPAN_LEN)
587 .filter_map(|record| {
588 Some(SyntaxSpan {
589 version: word(record, 0),
590 range: range_at(record, 4),
591 paint: Paint::from_bits(long(record, 20))?,
592 })
593 })
594 .collect()
595 }
596}
597
598pub fn byte_offset(text: &str, position: Position) -> Option<usize> {
602 let bytes = text.as_bytes();
603 let mut start = 0;
604 for _ in 0..position.line {
605 let at = bytes[start..]
606 .iter()
607 .position(|byte| *byte == b'\n' || *byte == b'\r')?
608 + start;
609 start = if bytes[at] == b'\r' && bytes.get(at + 1) == Some(&b'\n') {
610 at + 2
611 } else {
612 at + 1
613 };
614 }
615 let end = bytes[start..]
616 .iter()
617 .position(|byte| *byte == b'\n' || *byte == b'\r')
618 .map_or(bytes.len(), |offset| start + offset);
619 let mut units = 0_u32;
620 let mut offset = start;
621 for character in text[start..end].chars() {
622 if units == position.column {
623 return Some(offset);
624 }
625 units += character.len_utf16() as u32;
626 offset += character.len_utf8();
627 if units > position.column {
628 return None;
629 }
630 }
631 (units == position.column).then_some(offset)
632}
633
634#[derive(Clone, Debug, PartialEq)]
640pub struct CodeChange {
641 pub version: u32,
642 pub range: CodeRange,
643 pub text: String,
644}
645
646impl CodeChange {
647 pub fn apply_to(&self, text: &mut String) -> bool {
654 let (Some(start), Some(end)) = (
655 byte_offset(text, self.range.start),
656 byte_offset(text, self.range.end),
657 ) else {
658 return false;
659 };
660 if start > end {
661 return false;
662 }
663 text.replace_range(start..end, &self.text);
664 true
665 }
666}
667
668#[derive(Clone, Copy, Debug, Eq, PartialEq)]
671pub struct EditRejected {
672 pub request_id: u32,
674 pub base_version: u32,
675 pub current_version: u32,
677 pub range: CodeRange,
679}
680
681#[derive(Clone, Copy, Debug, Eq, PartialEq)]
687pub struct CodeHover {
688 pub decoration: Option<u64>,
690 pub position: Position,
691 pub phase: HoverPhase,
692}
693
694#[derive(Clone, Copy, Debug, Eq, PartialEq)]
699pub struct SaveRequest {
700 pub version: u32,
702}
703
704#[derive(Clone, Copy, Debug, Eq, PartialEq)]
706pub struct Fold {
707 pub version: u32,
709 pub start_line: u32,
711 pub end_line: u32,
714 pub collapsed: bool,
715}
716
717impl Fold {
718 pub const fn new(version: u32, start_line: u32, end_line: u32) -> Self {
720 Self {
721 version,
722 start_line,
723 end_line,
724 collapsed: false,
725 }
726 }
727
728 pub const fn collapsed(mut self) -> Self {
730 self.collapsed = true;
731 self
732 }
733}
734
735#[derive(Clone, Default, PartialEq)]
737pub struct Folds {
738 bytes: Option<Rc<[u8]>>,
739}
740
741impl std::fmt::Debug for Folds {
742 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
743 formatter
744 .debug_struct("Folds")
745 .field("folds", &(self.as_bytes().len() / FOLD_LEN))
746 .finish()
747 }
748}
749
750impl Folds {
751 pub fn new(folds: impl IntoIterator<Item = Fold>) -> Self {
752 let mut bytes = Vec::new();
753 for fold in folds {
754 put_u32(&mut bytes, fold.version);
755 put_u32(&mut bytes, fold.start_line);
756 put_u32(&mut bytes, fold.end_line);
757 put_u32(&mut bytes, u32::from(fold.collapsed));
758 }
759 Self::from_bytes(bytes)
760 }
761
762 pub fn from_bytes(bytes: impl Into<Rc<[u8]>>) -> Self {
763 let bytes = bytes.into();
764 Self {
765 bytes: (!bytes.is_empty()).then_some(bytes),
766 }
767 }
768
769 pub fn as_bytes(&self) -> &[u8] {
770 self.bytes.as_deref().unwrap_or(&[])
771 }
772
773 pub fn is_empty(&self) -> bool {
774 self.bytes.is_none()
775 }
776
777 pub fn folds(&self) -> Vec<Fold> {
780 self.as_bytes()
781 .chunks_exact(FOLD_LEN)
782 .filter_map(|record| {
783 Some(Fold {
784 version: word(record, 0),
785 start_line: word(record, 4),
786 end_line: word(record, 8),
787 collapsed: match word(record, 12) {
788 0 => false,
789 1 => true,
790 _ => return None,
791 },
792 })
793 })
794 .collect()
795 }
796}
797
798#[derive(Clone, Copy, Debug, Eq, PartialEq)]
804pub struct GutterDecoration {
805 pub version: u32,
807 pub line: u32,
808 pub kind: GutterDecorationKind,
809 pub color: Option<ColorRole>,
810 pub id: u64,
813 pub glyph: u32,
815}
816
817impl GutterDecoration {
818 pub const fn dot(version: u32, line: u32, id: u64) -> Self {
820 Self {
821 version,
822 line,
823 kind: GutterDecorationKind::Dot,
824 color: None,
825 id,
826 glyph: 0,
827 }
828 }
829
830 pub const fn bar(version: u32, line: u32, id: u64) -> Self {
832 Self {
833 version,
834 line,
835 kind: GutterDecorationKind::Bar,
836 color: None,
837 id,
838 glyph: 0,
839 }
840 }
841
842 pub const fn glyph(version: u32, line: u32, glyph: char, id: u64) -> Self {
844 Self {
845 version,
846 line,
847 kind: GutterDecorationKind::Glyph,
848 color: None,
849 id,
850 glyph: glyph as u32,
851 }
852 }
853
854 pub const fn with_color(mut self, role: ColorRole) -> Self {
856 self.color = Some(role);
857 self
858 }
859
860 pub const fn with_id(mut self, id: u64) -> Self {
861 self.id = id;
862 self
863 }
864}
865
866#[derive(Clone, Default, PartialEq)]
868pub struct GutterDecorations {
869 bytes: Option<Rc<[u8]>>,
870}
871
872impl std::fmt::Debug for GutterDecorations {
873 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
874 formatter
875 .debug_struct("GutterDecorations")
876 .field(
877 "decorations",
878 &(self.as_bytes().len() / GUTTER_DECORATION_LEN),
879 )
880 .finish()
881 }
882}
883
884impl GutterDecorations {
885 pub fn new(decorations: impl IntoIterator<Item = GutterDecoration>) -> Self {
886 let mut bytes = Vec::new();
887 for decoration in decorations {
888 put_u32(&mut bytes, decoration.version);
889 put_u32(&mut bytes, decoration.line);
890 put_u16(&mut bytes, decoration.kind as u16);
891 put_u16(&mut bytes, decoration.color.map_or(0, |value| value as u16));
892 put_u64(&mut bytes, decoration.id);
893 put_u32(&mut bytes, decoration.glyph);
894 put_u32(&mut bytes, 0);
895 }
896 Self::from_bytes(bytes)
897 }
898
899 pub fn from_bytes(bytes: impl Into<Rc<[u8]>>) -> Self {
900 let bytes = bytes.into();
901 Self {
902 bytes: (!bytes.is_empty()).then_some(bytes),
903 }
904 }
905
906 pub fn as_bytes(&self) -> &[u8] {
907 self.bytes.as_deref().unwrap_or(&[])
908 }
909
910 pub fn is_empty(&self) -> bool {
911 self.bytes.is_none()
912 }
913
914 pub fn decorations(&self) -> Vec<GutterDecoration> {
917 self.as_bytes()
918 .chunks_exact(GUTTER_DECORATION_LEN)
919 .filter_map(|record| {
920 let kind = GutterDecorationKind::try_from(half(record, 8)).ok()?;
921 let color = match half(record, 10) {
922 0 => None,
923 tag => Some(ColorRole::try_from(tag).ok()?),
924 };
925 Some(GutterDecoration {
926 version: word(record, 0),
927 line: word(record, 4),
928 kind,
929 color,
930 id: long(record, 12),
931 glyph: word(record, 20),
932 })
933 })
934 .collect()
935 }
936}
937
938#[derive(Clone, Copy, Debug, Eq, PartialEq)]
944pub struct SelectionChange {
945 pub version: u32,
946 pub anchor: Position,
947 pub active: Position,
948}
949
950impl SelectionChange {
951 pub fn is_caret(&self) -> bool {
953 self.anchor == self.active
954 }
955
956 pub fn range(&self) -> CodeRange {
958 CodeRange::new(self.anchor.min(self.active), self.anchor.max(self.active))
959 }
960}
961
962#[derive(Clone, Copy, Debug, Eq, PartialEq)]
964pub struct VisibleRange {
965 pub version: u32,
966 pub first_line: u32,
968 pub last_line: u32,
970}
971
972#[derive(Clone, Copy, Debug, Eq, PartialEq)]
974pub struct FoldChange {
975 pub start_line: u32,
977 pub collapsed: bool,
978}