@@ -19,6 +19,7 @@ use std::collections::hash_map::Entry;
1919use std:: collections:: HashMap ;
2020use std:: collections:: HashSet ;
2121use std:: collections:: VecDeque ;
22+ use std:: path:: Path ;
2223use std:: path:: PathBuf ;
2324use std:: sync:: Arc ;
2425use std:: sync:: RwLock ;
@@ -68,6 +69,12 @@ use crate::lsp::server::ResolveLoadError;
6869use crate :: lsp:: server:: StringLiteralResult ;
6970use crate :: syntax:: AstModule ;
7071use 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 ;
7178
7279/// Get the path from a URL, trimming off things like the leading slash that gets
7380/// appended in some windows test environments.
@@ -99,13 +106,14 @@ pub(crate) enum TestServerError {
99106struct TestServerContext {
100107 file_contents : Arc < RwLock < HashMap < PathBuf , String > > > ,
101108 dirs : Arc < RwLock < HashSet < PathBuf > > > ,
109+ builtin_docs : Arc < HashMap < LspUrl , String > > ,
102110}
103111
104112impl LspContext for TestServerContext {
105113 fn parse_file_with_contents ( & self , uri : & LspUrl , content : String ) -> LspEvalResult {
106114 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 ) {
109117 Ok ( ast) => {
110118 let diagnostics = ast. lint ( None ) . into_map ( |l| EvalMessage :: from ( l) . into ( ) ) ;
111119 LspEvalResult {
@@ -114,7 +122,7 @@ impl LspContext for TestServerContext {
114122 }
115123 }
116124 Err ( e) => {
117- let diagnostics = vec ! [ EvalMessage :: from_anyhow( uri , & e) . into( ) ] ;
125+ let diagnostics = vec ! [ EvalMessage :: from_anyhow( path , & e) . into( ) ] ;
118126 LspEvalResult {
119127 diagnostics,
120128 ast : None ,
@@ -196,6 +204,7 @@ impl LspContext for TestServerContext {
196204 ( false , _) => Err ( LoadContentsError :: NotAbsolute ( uri. clone ( ) ) . into ( ) ) ,
197205 }
198206 }
207+ LspUrl :: Starlark ( _) => Ok ( self . builtin_docs . get ( uri) . cloned ( ) ) ,
199208 _ => Ok ( None ) ,
200209 }
201210 }
@@ -223,6 +232,8 @@ pub struct TestServer {
223232 dirs : Arc < RwLock < HashSet < PathBuf > > > ,
224233 /// If it's been received, the response payload for initialization.
225234 initialize_response : Option < InitializeResult > ,
235+ /// Documentation for built in symbols.
236+ builtin_docs : Arc < HashMap < LspUrl , String > > ,
226237}
227238
228239impl Drop for TestServer {
@@ -255,6 +266,49 @@ impl Drop for TestServer {
255266}
256267
257268impl 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+
258312 /// Generate a new request ID
259313 fn next_request_id ( & mut self ) -> RequestId {
260314 self . req_counter += 1 ;
@@ -281,11 +335,25 @@ impl TestServer {
281335 pub ( crate ) fn new_with_settings ( settings : Option < LspServerSettings > ) -> anyhow:: Result < Self > {
282336 let ( server_connection, client_connection) = Connection :: memory ( ) ;
283337
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) ) ;
285352 let dirs = Arc :: new ( RwLock :: new ( HashSet :: new ( ) ) ) ;
286353 let ctx = TestServerContext {
287354 file_contents : file_contents. dupe ( ) ,
288355 dirs : dirs. dupe ( ) ,
356+ builtin_docs : builtin_docs. dupe ( ) ,
289357 } ;
290358
291359 let server_thread = std:: thread:: spawn ( || {
@@ -305,6 +373,7 @@ impl TestServer {
305373 file_contents,
306374 dirs,
307375 initialize_response : None ,
376+ builtin_docs,
308377 } ;
309378 ret. initialize ( settings)
310379 }
0 commit comments