@@ -3,7 +3,20 @@ use std::collections::HashMap;
3
3
use anyhow:: anyhow;
4
4
use anyhow:: Result ;
5
5
use djls_project:: TemplateTags ;
6
- use tower_lsp_server:: lsp_types:: * ;
6
+ use salsa:: Database ;
7
+ use tower_lsp_server:: lsp_types:: CompletionItem ;
8
+ use tower_lsp_server:: lsp_types:: CompletionItemKind ;
9
+ use tower_lsp_server:: lsp_types:: CompletionResponse ;
10
+ use tower_lsp_server:: lsp_types:: DidChangeTextDocumentParams ;
11
+ use tower_lsp_server:: lsp_types:: DidCloseTextDocumentParams ;
12
+ use tower_lsp_server:: lsp_types:: DidOpenTextDocumentParams ;
13
+ use tower_lsp_server:: lsp_types:: Documentation ;
14
+ use tower_lsp_server:: lsp_types:: InsertTextFormat ;
15
+ use tower_lsp_server:: lsp_types:: MarkupContent ;
16
+ use tower_lsp_server:: lsp_types:: MarkupKind ;
17
+ use tower_lsp_server:: lsp_types:: Position ;
18
+ use tower_lsp_server:: lsp_types:: Range ;
19
+ use tower_lsp_server:: lsp_types:: TextDocumentContentChangeEvent ;
7
20
8
21
#[ derive( Debug , Default ) ]
9
22
pub struct Store {
@@ -19,54 +32,42 @@ impl Store {
19
32
}
20
33
}
21
34
22
- pub fn handle_did_open ( & mut self , params : DidOpenTextDocumentParams ) -> Result < ( ) > {
23
- let document = TextDocument :: new (
24
- params. text_document . uri . to_string ( ) ,
25
- params. text_document . text ,
26
- params. text_document . version ,
27
- params. text_document . language_id ,
28
- ) ;
35
+ pub fn handle_did_open ( & mut self , db : & dyn Database , params : & DidOpenTextDocumentParams ) {
36
+ let uri = params. text_document . uri . to_string ( ) ;
37
+ let version = params. text_document . version ;
29
38
30
- self . add_document ( document) ;
39
+ let document = TextDocument :: from_did_open_params ( db , params ) ;
31
40
32
- Ok ( ( ) )
41
+ self . add_document ( document, uri. clone ( ) ) ;
42
+ self . versions . insert ( uri, version) ;
33
43
}
34
44
35
- pub fn handle_did_change ( & mut self , params : DidChangeTextDocumentParams ) -> Result < ( ) > {
45
+ pub fn handle_did_change (
46
+ & mut self ,
47
+ db : & dyn Database ,
48
+ params : & DidChangeTextDocumentParams ,
49
+ ) -> Result < ( ) > {
36
50
let uri = params. text_document . uri . as_str ( ) . to_string ( ) ;
37
51
let version = params. text_document . version ;
38
52
39
53
let document = self
40
- . get_document_mut ( & uri)
54
+ . get_document ( & uri)
41
55
. ok_or_else ( || anyhow ! ( "Document not found: {}" , uri) ) ?;
42
56
43
- for change in params. content_changes {
44
- if let Some ( range) = change. range {
45
- document. apply_change ( range, & change. text ) ?;
46
- } else {
47
- // Full document update
48
- document. set_content ( change. text ) ;
49
- }
50
- }
57
+ let new_document = document. with_changes ( db, & params. content_changes , version) ;
51
58
52
- document . version = version ;
59
+ self . documents . insert ( uri . clone ( ) , new_document ) ;
53
60
self . versions . insert ( uri, version) ;
54
61
55
62
Ok ( ( ) )
56
63
}
57
64
58
- pub fn handle_did_close ( & mut self , params : DidCloseTextDocumentParams ) -> Result < ( ) > {
65
+ pub fn handle_did_close ( & mut self , params : & DidCloseTextDocumentParams ) {
59
66
self . remove_document ( params. text_document . uri . as_str ( ) ) ;
60
-
61
- Ok ( ( ) )
62
67
}
63
68
64
- fn add_document ( & mut self , document : TextDocument ) {
65
- let uri = document. uri . clone ( ) ;
66
- let version = document. version ;
67
-
68
- self . documents . insert ( uri. clone ( ) , document) ;
69
- self . versions . insert ( uri, version) ;
69
+ fn add_document ( & mut self , document : TextDocument , uri : String ) {
70
+ self . documents . insert ( uri, document) ;
70
71
}
71
72
72
73
fn remove_document ( & mut self , uri : & str ) {
@@ -78,6 +79,7 @@ impl Store {
78
79
self . documents . get ( uri)
79
80
}
80
81
82
+ #[ allow( dead_code) ]
81
83
fn get_document_mut ( & mut self , uri : & str ) -> Option < & mut TextDocument > {
82
84
self . documents . get_mut ( uri)
83
85
}
@@ -88,13 +90,14 @@ impl Store {
88
90
}
89
91
90
92
#[ allow( dead_code) ]
91
- pub fn get_documents_by_language (
92
- & self ,
93
+ pub fn get_documents_by_language < ' db > (
94
+ & ' db self ,
95
+ db : & ' db dyn Database ,
93
96
language_id : LanguageId ,
94
- ) -> impl Iterator < Item = & TextDocument > {
97
+ ) -> impl Iterator < Item = & ' db TextDocument > + ' db {
95
98
self . documents
96
99
. values ( )
97
- . filter ( move |doc| doc. language_id == language_id)
100
+ . filter ( move |doc| doc. language_id ( db ) == language_id)
98
101
}
99
102
100
103
#[ allow( dead_code) ]
@@ -109,17 +112,18 @@ impl Store {
109
112
110
113
pub fn get_completions (
111
114
& self ,
115
+ db : & dyn Database ,
112
116
uri : & str ,
113
117
position : Position ,
114
118
tags : & TemplateTags ,
115
119
) -> Option < CompletionResponse > {
116
120
let document = self . get_document ( uri) ?;
117
121
118
- if document. language_id != LanguageId :: HtmlDjango {
122
+ if document. language_id ( db ) != LanguageId :: HtmlDjango {
119
123
return None ;
120
124
}
121
125
122
- let context = document. get_template_tag_context ( position) ?;
126
+ let context = document. get_template_tag_context ( db , position) ?;
123
127
124
128
let mut completions: Vec < CompletionItem > = tags
125
129
. iter ( )
@@ -135,7 +139,7 @@ impl Store {
135
139
documentation : tag. doc ( ) . as_ref ( ) . map ( |doc| {
136
140
Documentation :: MarkupContent ( MarkupContent {
137
141
kind : MarkupKind :: Markdown ,
138
- value : doc. to_string ( ) ,
142
+ value : ( * doc) . to_string ( ) ,
139
143
} )
140
144
} ) ,
141
145
insert_text : Some ( match context. closing_brace {
@@ -158,89 +162,110 @@ impl Store {
158
162
}
159
163
}
160
164
161
- #[ derive ( Clone , Debug ) ]
165
+ #[ salsa :: input ( debug ) ]
162
166
pub struct TextDocument {
167
+ #[ return_ref]
163
168
uri : String ,
169
+ #[ return_ref]
164
170
contents : String ,
171
+ #[ return_ref]
165
172
index : LineIndex ,
166
173
version : i32 ,
167
174
language_id : LanguageId ,
168
175
}
169
176
170
177
impl TextDocument {
171
- fn new ( uri : String , contents : String , version : i32 , language_id : String ) -> Self {
178
+ pub fn from_did_open_params ( db : & dyn Database , params : & DidOpenTextDocumentParams ) -> Self {
179
+ let uri = params. text_document . uri . to_string ( ) ;
180
+ let contents = params. text_document . text . clone ( ) ;
181
+ let version = params. text_document . version ;
182
+ let language_id = LanguageId :: from ( params. text_document . language_id . as_str ( ) ) ;
183
+
172
184
let index = LineIndex :: new ( & contents) ;
173
- Self {
174
- uri,
175
- contents,
176
- index,
177
- version,
178
- language_id : LanguageId :: from ( language_id) ,
179
- }
185
+ TextDocument :: new ( db, uri, contents, index, version, language_id)
180
186
}
181
187
182
- pub fn apply_change ( & mut self , range : Range , new_text : & str ) -> Result < ( ) > {
183
- let start_offset = self
184
- . index
185
- . offset ( range. start )
186
- . ok_or_else ( || anyhow ! ( "Invalid start position: {:?}" , range. start) ) ?
187
- as usize ;
188
- let end_offset = self
189
- . index
190
- . offset ( range. end )
191
- . ok_or_else ( || anyhow ! ( "Invalid end position: {:?}" , range. end) ) ?
192
- as usize ;
188
+ pub fn with_changes (
189
+ self ,
190
+ db : & dyn Database ,
191
+ changes : & [ TextDocumentContentChangeEvent ] ,
192
+ new_version : i32 ,
193
+ ) -> Self {
194
+ let mut new_contents = self . contents ( db) . to_string ( ) ;
193
195
194
- let mut new_content = String :: with_capacity (
195
- self . contents . len ( ) - ( end_offset - start_offset ) + new_text . len ( ) ,
196
- ) ;
196
+ for change in changes {
197
+ if let Some ( range ) = change . range {
198
+ let index = LineIndex :: new ( & new_contents ) ;
197
199
198
- new_content. push_str ( & self . contents [ ..start_offset] ) ;
199
- new_content. push_str ( new_text) ;
200
- new_content. push_str ( & self . contents [ end_offset..] ) ;
200
+ if let ( Some ( start_offset) , Some ( end_offset) ) = (
201
+ index. offset ( range. start ) . map ( |o| o as usize ) ,
202
+ index. offset ( range. end ) . map ( |o| o as usize ) ,
203
+ ) {
204
+ let mut updated_content = String :: with_capacity (
205
+ new_contents. len ( ) - ( end_offset - start_offset) + change. text . len ( ) ,
206
+ ) ;
201
207
202
- self . set_content ( new_content) ;
208
+ updated_content. push_str ( & new_contents[ ..start_offset] ) ;
209
+ updated_content. push_str ( & change. text ) ;
210
+ updated_content. push_str ( & new_contents[ end_offset..] ) ;
203
211
204
- Ok ( ( ) )
205
- }
212
+ new_contents = updated_content;
213
+ }
214
+ } else {
215
+ // Full document update
216
+ new_contents. clone_from ( & change. text ) ;
217
+ }
218
+ }
206
219
207
- pub fn set_content ( & mut self , new_content : String ) {
208
- self . contents = new_content;
209
- self . index = LineIndex :: new ( & self . contents ) ;
220
+ let index = LineIndex :: new ( & new_contents) ;
221
+ TextDocument :: new (
222
+ db,
223
+ self . uri ( db) . to_string ( ) ,
224
+ new_contents,
225
+ index,
226
+ new_version,
227
+ self . language_id ( db) ,
228
+ )
210
229
}
211
230
212
231
#[ allow( dead_code) ]
213
- pub fn get_text ( & self ) -> & str {
214
- & self . contents
232
+ pub fn get_text ( self , db : & dyn Database ) -> String {
233
+ self . contents ( db ) . to_string ( )
215
234
}
216
235
217
236
#[ allow( dead_code) ]
218
- pub fn get_text_range ( & self , range : Range ) -> Option < & str > {
219
- let start = self . index . offset ( range. start ) ? as usize ;
220
- let end = self . index . offset ( range. end ) ? as usize ;
221
-
222
- Some ( & self . contents [ start..end] )
237
+ pub fn get_text_range ( self , db : & dyn Database , range : Range ) -> Option < String > {
238
+ let index = self . index ( db) ;
239
+ let start = index. offset ( range. start ) ? as usize ;
240
+ let end = index. offset ( range. end ) ? as usize ;
241
+ let contents = self . contents ( db) ;
242
+ Some ( contents[ start..end] . to_string ( ) )
223
243
}
224
244
225
- pub fn get_line ( & self , line : u32 ) -> Option < & str > {
226
- let start = self . index . line_starts . get ( line as usize ) ? ;
227
- let end = self
228
- . index
245
+ pub fn get_line ( self , db : & dyn Database , line : u32 ) -> Option < String > {
246
+ let index = self . index ( db ) ;
247
+ let start = index . line_starts . get ( line as usize ) ? ;
248
+ let end = index
229
249
. line_starts
230
250
. get ( line as usize + 1 )
231
251
. copied ( )
232
- . unwrap_or ( self . index . length ) ;
252
+ . unwrap_or ( index. length ) ;
233
253
234
- Some ( & self . contents [ * start as usize ..end as usize ] )
254
+ let contents = self . contents ( db) ;
255
+ Some ( contents[ * start as usize ..end as usize ] . to_string ( ) )
235
256
}
236
257
237
258
#[ allow( dead_code) ]
238
- pub fn line_count ( & self ) -> usize {
239
- self . index . line_starts . len ( )
259
+ pub fn line_count ( self , db : & dyn Database ) -> usize {
260
+ self . index ( db ) . line_starts . len ( )
240
261
}
241
262
242
- pub fn get_template_tag_context ( & self , position : Position ) -> Option < TemplateTagContext > {
243
- let line = self . get_line ( position. line ) ?;
263
+ pub fn get_template_tag_context (
264
+ self ,
265
+ db : & dyn Database ,
266
+ position : Position ,
267
+ ) -> Option < TemplateTagContext > {
268
+ let line = self . get_line ( db, position. line ) ?;
244
269
let char_pos: usize = position. character . try_into ( ) . ok ( ) ?;
245
270
let prefix = & line[ ..char_pos] ;
246
271
let rest_of_line = & line[ char_pos..] ;
@@ -252,7 +277,7 @@ impl TextDocument {
252
277
253
278
let closing_brace = if rest_trimmed. starts_with ( "%}" ) {
254
279
ClosingBrace :: FullClose
255
- } else if rest_trimmed. starts_with ( "}" ) {
280
+ } else if rest_trimmed. starts_with ( '}' ) {
256
281
ClosingBrace :: PartialClose
257
282
} else {
258
283
ClosingBrace :: None
@@ -279,7 +304,7 @@ impl LineIndex {
279
304
let mut pos = 0 ;
280
305
281
306
for c in text. chars ( ) {
282
- pos += c. len_utf8 ( ) as u32 ;
307
+ pos += u32 :: try_from ( c. len_utf8 ( ) ) . unwrap_or ( 0 ) ;
283
308
if c == '\n' {
284
309
line_starts. push ( pos) ;
285
310
}
@@ -307,7 +332,7 @@ impl LineIndex {
307
332
let line_start = self . line_starts [ line] ;
308
333
let character = offset - line_start;
309
334
310
- Position :: new ( line as u32 , character)
335
+ Position :: new ( u32:: try_from ( line ) . unwrap_or ( 0 ) , character)
311
336
}
312
337
}
313
338
0 commit comments