1use core::fmt;
4
5use hir::Mutability;
6use ide::{CompletionItem, CompletionItemRefMode, CompletionRelevance};
7use tenthash::TentHash;
8
9pub mod ext;
10
11pub(crate) mod capabilities;
12pub(crate) mod from_proto;
13pub(crate) mod semantic_tokens;
14pub(crate) mod to_proto;
15pub(crate) mod utils;
16
17#[derive(Debug)]
18pub(crate) struct LspError {
19 pub(crate) code: i32,
20 pub(crate) message: String,
21}
22
23impl LspError {
24 pub(crate) fn new(code: i32, message: String) -> LspError {
25 LspError { code, message }
26 }
27}
28
29impl fmt::Display for LspError {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 write!(f, "Language Server request failed with {}. ({})", self.code, self.message)
32 }
33}
34
35impl std::error::Error for LspError {}
36
37pub(crate) fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
38 fn hash_completion_relevance(hasher: &mut TentHash, relevance: &CompletionRelevance) {
39 use ide_completion::{
40 CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
41 CompletionRelevanceTypeMatch,
42 };
43
44 hasher.update([
45 u8::from(relevance.exact_name_match),
46 u8::from(relevance.is_local),
47 u8::from(relevance.is_name_already_imported),
48 u8::from(relevance.requires_import),
49 u8::from(relevance.is_private_editable),
50 ]);
51
52 match relevance.type_match {
53 None => hasher.update([0u8]),
54 Some(CompletionRelevanceTypeMatch::CouldUnify) => hasher.update([1u8]),
55 Some(CompletionRelevanceTypeMatch::Exact) => hasher.update([2u8]),
56 }
57
58 hasher.update([u8::from(relevance.trait_.is_some())]);
59 if let Some(trait_) = &relevance.trait_ {
60 hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
61 }
62
63 match relevance.postfix_match {
64 None => hasher.update([0u8]),
65 Some(CompletionRelevancePostfixMatch::NonExact) => hasher.update([1u8]),
66 Some(CompletionRelevancePostfixMatch::Exact) => hasher.update([2u8]),
67 }
68
69 hasher.update([u8::from(relevance.function.is_some())]);
70 if let Some(function) = &relevance.function {
71 hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
72 let discriminant: u8 = match function.return_type {
73 CompletionRelevanceReturnType::Other => 0,
74 CompletionRelevanceReturnType::DirectConstructor => 1,
75 CompletionRelevanceReturnType::Constructor => 2,
76 CompletionRelevanceReturnType::Builder => 3,
77 };
78 hasher.update([discriminant]);
79 }
80 }
81
82 let mut hasher = TentHash::new();
83 hasher.update([
84 u8::from(is_ref_completion),
85 u8::from(item.is_snippet),
86 u8::from(item.deprecated),
87 u8::from(item.trigger_call_info),
88 ]);
89
90 hasher.update(item.label.primary.len().to_ne_bytes());
91 hasher.update(&item.label.primary);
92
93 hasher.update([u8::from(item.label.detail_left.is_some())]);
94 if let Some(label_detail) = &item.label.detail_left {
95 hasher.update(label_detail.len().to_ne_bytes());
96 hasher.update(label_detail);
97 }
98
99 hasher.update([u8::from(item.label.detail_right.is_some())]);
100 if let Some(label_detail) = &item.label.detail_right {
101 hasher.update(label_detail.len().to_ne_bytes());
102 hasher.update(label_detail);
103 }
104
105 let kind_tag = item.kind.tag();
112 hasher.update(kind_tag.len().to_ne_bytes());
113 hasher.update(kind_tag);
114
115 hasher.update(item.lookup.len().to_ne_bytes());
116 hasher.update(&item.lookup);
117
118 hasher.update([u8::from(item.detail.is_some())]);
119 if let Some(detail) = &item.detail {
120 hasher.update(detail.len().to_ne_bytes());
121 hasher.update(detail);
122 }
123
124 hash_completion_relevance(&mut hasher, &item.relevance);
125
126 hasher.update([u8::from(item.ref_match.is_some())]);
127 if let Some((ref_mode, text_size)) = &item.ref_match {
128 let discriminant = match ref_mode {
129 CompletionItemRefMode::Reference(Mutability::Shared) => 0u8,
130 CompletionItemRefMode::Reference(Mutability::Mut) => 1u8,
131 CompletionItemRefMode::Dereference => 2u8,
132 };
133 hasher.update([discriminant]);
134 hasher.update(u32::from(*text_size).to_ne_bytes());
135 }
136
137 hasher.update(item.import_to_add.len().to_ne_bytes());
138 for import_path in &item.import_to_add {
139 hasher.update(import_path.len().to_ne_bytes());
140 hasher.update(import_path);
141 }
142
143 hasher.finalize()
144}