char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
c7a9569
main
1# [ path = "common/lsp.rs" ] 2# [ allow ( dead_code )] 3mod support; 4 5use serde_json::{ Value , json}; 6use support::{ Server , backend, files, position_at}; 7 8fn signature ( server : & mut Server , path : & str , text : & str , offset : usize ) ->Value { 9 server 10. call ( 11"textDocument/signatureHelp" , 12json! ({ 13"textDocument" : { "uri" : server. uri ( path)}, 14"position" : position_at ( text, offset), 15"context" : { "triggerKind" : 1 , "isRetrigger" : false , "triggerCharacter" : null, "activeSignatureHelp" : null} 16}), 17) 18. unwrap () 19} 20 21# [ test ] 22fn call_signature_help () { 23let Some ( backend) =backend () else { 24eprintln! ( "skipping: AVRIL_TEST_TYPESCRIPT is not set" ); 25return ; 26}; 27let dir = tempfile:: tempdir (). unwrap (); 28let root = dir. path (); 29let main =[ 30"export function add(a: number, b?: string, ...rest: boolean[]): boolean { return true; }" , 31"export function pick(x: number): number;" , 32"export function pick(x: string): string;" , 33"export function pick(x: unknown): unknown { return x; }" , 34"export class Box { constructor(public w: number, public h?: number) {} }" , 35"const r1 = add(1, \"hi\");" , 36"const r2 = pick(\"a\");" , 37"const made = new Box(3);" , 38"const nested = add(pick(1), true);" , 39"const mixed = add(\"x,y\", [true], \"s\");" , 40"add(2," , 41] 42. join ( "\n" ); 43files ( root, & [( "main.ts" , & main), ( "avril.conf" , "{}" )]); 44let mut server =Server :: start ( root, & backend, & [ "--offline" ]); 45let initialize = server 46. call ( "initialize" , json! ({ "capabilities" : {}})) 47. unwrap (); 48assert_eq! ( 49 initialize[ "capabilities" ][ "signatureHelpProvider" ][ "triggerCharacters" ], 50json! ([ "(" , "," ]) 51); 52assert_eq! ( 53 initialize[ "capabilities" ][ "signatureHelpProvider" ][ "retriggerCharacters" ], 54json! ([ ")" ]) 55); 56 server. notify ( "initialized" , json! ({})); 57 server. open ( "main.ts" , & main); 58 59// First and second arguments select the active parameter. 60let call = main. find ( "add(1, \"hi\")" ). unwrap (); 61let help =signature ( & mut server, "main.ts" , & main, call +"add(" . len ()); 62assert_eq! ( help[ "activeSignature" ], json! ( 0 )); 63assert_eq! ( help[ "activeParameter" ], json! ( 0 )); 64assert_eq! ( 65 help[ "signatures" ][ 0 ][ "label" ], 66json! ( "add(a: number, b?: string, ...rest: boolean[]): boolean" ) 67); 68let help =signature ( & mut server, "main.ts" , & main, call +"add(1," . len ()); 69assert_eq! ( help[ "activeParameter" ], json! ( 1 )); 70 71// Overloads list every signature with the resolved one active. 72let call = main. find ( "pick(\"a\")" ). unwrap (); 73let help =signature ( & mut server, "main.ts" , & main, call +"pick(" . len ()); 74assert_eq! ( help[ "signatures" ]. as_array (). unwrap (). len (), 2 ); 75assert_eq! ( help[ "activeSignature" ], json! ( 1 )); 76assert_eq! ( 77 help[ "signatures" ][ 1 ][ "label" ], 78json! ( "pick(x: string): string" ) 79); 80assert_eq! ( help[ "activeParameter" ], json! ( 0 )); 81 82// Construct expressions use the constructor signature. 83let call = main. find ( "new Box(3)" ). unwrap (); 84let help =signature ( & mut server, "main.ts" , & main, call +"new Box(" . len ()); 85assert_eq! ( help[ "activeParameter" ], json! ( 0 )); 86let label = help[ "signatures" ][ 0 ][ "label" ]. as_str (). unwrap (); 87assert! ( label. starts_with ( "Box(w: number, h?: number" ), "{label}" ); 88assert! ( label. ends_with ( ": Box" ), "{label}" ); 89 90// Nested calls resolve to the innermost argument list. 91let outer = main. find ( "add(pick(1), true)" ). unwrap (); 92let help =signature ( & mut server, "main.ts" , & main, outer +"add(pick(1)," . len ()); 93assert! ( 94 help[ "signatures" ][ 0 ][ "label" ] 95. as_str () 96. unwrap () 97. starts_with ( "add(" ) 98); 99assert_eq! ( help[ "activeParameter" ], json! ( 1 )); 100let inner = main. find ( "pick(1)" ). unwrap (); 101let help =signature ( & mut server, "main.ts" , & main, inner +"pick(1" . len ()); 102assert_eq! ( help[ "signatures" ]. as_array (). unwrap (). len (), 2 ); 103assert_eq! ( help[ "activeSignature" ], json! ( 0 )); 104 105// Commas inside strings and brackets do not advance the parameter. 106let call = main. find ( "add(\"x,y\", [true], \"s\")" ). unwrap (); 107let help =signature ( 108& mut server, 109"main.ts" , 110& main, 111 call +"add(\"x,y\", [true]," . len (), 112); 113assert_eq! ( help[ "activeParameter" ], json! ( 2 )); 114 115// An unclosed call still reports the argument index. 116let call = main. rfind ( "add(2," ). unwrap (); 117let help =signature ( & mut server, "main.ts" , & main, call +"add(2," . len ()); 118assert_eq! ( help[ "activeParameter" ], json! ( 1 )); 119 120// The callee name and positions past the call have no signature. 121assert_eq! ( 122signature ( & mut server, "main.ts" , & main, call +"add" . len ()), 123Value :: Null 124); 125let closed = main. find ( "add(1, \"hi\")" ). unwrap () +"add(1, \"hi\")" . len (); 126assert_eq! ( 127signature ( & mut server, "main.ts" , & main, closed), 128Value :: Null 129); 130}