@@ -19,6 +19,7 @@ use std::collections::hash_map::Entry;
19
19
use std:: collections:: HashMap ;
20
20
use std:: collections:: HashSet ;
21
21
use std:: collections:: VecDeque ;
22
+ use std:: path:: Path ;
22
23
use std:: path:: PathBuf ;
23
24
use std:: sync:: Arc ;
24
25
use std:: sync:: RwLock ;
@@ -68,6 +69,12 @@ use crate::lsp::server::ResolveLoadError;
68
69
use crate :: lsp:: server:: StringLiteralResult ;
69
70
use crate :: syntax:: AstModule ;
70
71
use crate :: syntax:: Dialect ;
72
+ use crate :: values:: docs:: render_docs_as_code;
73
+ use crate :: values:: docs:: Doc ;
74
+ use crate :: values:: docs:: DocItem ;
75
+ use crate :: values:: docs:: Function ;
76
+ use crate :: values:: docs:: Identifier ;
77
+ use crate :: values:: docs:: Location ;
71
78
72
79
/// Get the path from a URL, trimming off things like the leading slash that gets
73
80
/// appended in some windows test environments.
@@ -99,13 +106,14 @@ pub(crate) enum TestServerError {
99
106
struct TestServerContext {
100
107
file_contents : Arc < RwLock < HashMap < PathBuf , String > > > ,
101
108
dirs : Arc < RwLock < HashSet < PathBuf > > > ,
109
+ builtin_docs : Arc < HashMap < LspUrl , String > > ,
102
110
}
103
111
104
112
impl LspContext for TestServerContext {
105
113
fn parse_file_with_contents ( & self , uri : & LspUrl , content : String ) -> LspEvalResult {
106
114
match uri {
107
- LspUrl :: File ( uri ) => {
108
- match AstModule :: parse ( & uri . to_string_lossy ( ) , content, & Dialect :: Extended ) {
115
+ LspUrl :: File ( path ) | LspUrl :: Starlark ( path ) => {
116
+ match AstModule :: parse ( & path . to_string_lossy ( ) , content, & Dialect :: Extended ) {
109
117
Ok ( ast) => {
110
118
let diagnostics = ast. lint ( None ) . into_map ( |l| EvalMessage :: from ( l) . into ( ) ) ;
111
119
LspEvalResult {
@@ -114,7 +122,7 @@ impl LspContext for TestServerContext {
114
122
}
115
123
}
116
124
Err ( e) => {
117
- let diagnostics = vec ! [ EvalMessage :: from_anyhow( uri , & e) . into( ) ] ;
125
+ let diagnostics = vec ! [ EvalMessage :: from_anyhow( path , & e) . into( ) ] ;
118
126
LspEvalResult {
119
127
diagnostics,
120
128
ast : None ,
@@ -196,6 +204,7 @@ impl LspContext for TestServerContext {
196
204
( false , _) => Err ( LoadContentsError :: NotAbsolute ( uri. clone ( ) ) . into ( ) ) ,
197
205
}
198
206
}
207
+ LspUrl :: Starlark ( _) => Ok ( self . builtin_docs . get ( uri) . cloned ( ) ) ,
199
208
_ => Ok ( None ) ,
200
209
}
201
210
}
@@ -223,6 +232,8 @@ pub struct TestServer {
223
232
dirs : Arc < RwLock < HashSet < PathBuf > > > ,
224
233
/// If it's been received, the response payload for initialization.
225
234
initialize_response : Option < InitializeResult > ,
235
+ /// Documentation for built in symbols.
236
+ builtin_docs : Arc < HashMap < LspUrl , String > > ,
226
237
}
227
238
228
239
impl Drop for TestServer {
@@ -255,6 +266,49 @@ impl Drop for TestServer {
255
266
}
256
267
257
268
impl TestServer {
269
+ pub ( crate ) fn docs_as_code ( & self , uri : & LspUrl ) -> Option < String > {
270
+ self . builtin_docs . get ( uri) . cloned ( )
271
+ }
272
+
273
+ /// A static set of "builtins" to use for testing
274
+ fn testing_builtins ( root : & Path ) -> anyhow:: Result < HashMap < LspUrl , Vec < Doc > > > {
275
+ let prelude_path = root. join ( "dir/prelude.bzl" ) ;
276
+ let ret = hashmap ! {
277
+ LspUrl :: try_from( Url :: parse( "starlark:/native/builtin.bzl" ) ?) ? => vec![
278
+ Doc {
279
+ id: Identifier {
280
+ name: "native_function1" . to_owned( ) ,
281
+ location: None ,
282
+ } ,
283
+ item: DocItem :: Function ( Function :: default ( ) ) ,
284
+ custom_attrs: Default :: default ( ) ,
285
+ } ,
286
+ Doc {
287
+ id: Identifier {
288
+ name: "native_function2" . to_owned( ) ,
289
+ location: None ,
290
+ } ,
291
+ item: DocItem :: Function ( Function :: default ( ) ) ,
292
+ custom_attrs: Default :: default ( ) ,
293
+ } ,
294
+ ] ,
295
+ LspUrl :: try_from( Url :: from_file_path( prelude_path) . unwrap( ) ) ? => vec![
296
+ Doc {
297
+ id: Identifier {
298
+ name: "prelude_function" . to_owned( ) ,
299
+ location: Some ( Location {
300
+ path: "//dir/prelude.bzl" . to_owned( ) ,
301
+ position: None ,
302
+ } ) ,
303
+ } ,
304
+ item: DocItem :: Function ( Function :: default ( ) ) ,
305
+ custom_attrs: Default :: default ( ) ,
306
+ } ,
307
+ ]
308
+ } ;
309
+ Ok ( ret)
310
+ }
311
+
258
312
/// Generate a new request ID
259
313
fn next_request_id ( & mut self ) -> RequestId {
260
314
self . req_counter += 1 ;
@@ -281,11 +335,25 @@ impl TestServer {
281
335
pub ( crate ) fn new_with_settings ( settings : Option < LspServerSettings > ) -> anyhow:: Result < Self > {
282
336
let ( server_connection, client_connection) = Connection :: memory ( ) ;
283
337
284
- let file_contents = Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ;
338
+ let builtin_docs = Arc :: new (
339
+ Self :: testing_builtins ( & std:: env:: current_dir ( ) ?) ?
340
+ . into_iter ( )
341
+ . map ( |( u, ds) | ( u, render_docs_as_code ( & ds) . join ( "\n \n " ) ) )
342
+ . collect :: < HashMap < _ , _ > > ( ) ,
343
+ ) ;
344
+ let prelude_file_contents = builtin_docs
345
+ . iter ( )
346
+ . filter_map ( |( u, d) | match u {
347
+ LspUrl :: File ( p) => Some ( ( p. clone ( ) , d. clone ( ) ) ) ,
348
+ _ => None ,
349
+ } )
350
+ . collect ( ) ;
351
+ let file_contents = Arc :: new ( RwLock :: new ( prelude_file_contents) ) ;
285
352
let dirs = Arc :: new ( RwLock :: new ( HashSet :: new ( ) ) ) ;
286
353
let ctx = TestServerContext {
287
354
file_contents : file_contents. dupe ( ) ,
288
355
dirs : dirs. dupe ( ) ,
356
+ builtin_docs : builtin_docs. dupe ( ) ,
289
357
} ;
290
358
291
359
let server_thread = std:: thread:: spawn ( || {
@@ -305,6 +373,7 @@ impl TestServer {
305
373
file_contents,
306
374
dirs,
307
375
initialize_response : None ,
376
+ builtin_docs,
308
377
} ;
309
378
ret. initialize ( settings)
310
379
}
0 commit comments