@@ -43,6 +43,7 @@ type FourslashTest struct {
4343 scriptInfos map [string ]* scriptInfo
4444 converters * ls.Converters
4545
46+ userPreferences * ls.UserPreferences
4647 currentCaretPosition lsproto.Position
4748 lastKnownMarkerName * string
4849 activeFilename string
@@ -180,14 +181,15 @@ func NewFourslash(t *testing.T, capabilities *lsproto.ClientCapabilities, conten
180181 })
181182
182183 f := & FourslashTest {
183- server : server ,
184- in : inputWriter ,
185- out : outputReader ,
186- testData : & testData ,
187- vfs : fs ,
188- scriptInfos : scriptInfos ,
189- converters : converters ,
190- baselines : make (map [string ]* strings.Builder ),
184+ server : server ,
185+ in : inputWriter ,
186+ out : outputReader ,
187+ testData : & testData ,
188+ userPreferences : ls .NewDefaultUserPreferences (), // !!! parse default preferences for fourslash case?
189+ vfs : fs ,
190+ scriptInfos : scriptInfos ,
191+ converters : converters ,
192+ baselines : make (map [string ]* strings.Builder ),
191193 }
192194
193195 // !!! temporary; remove when we have `handleDidChangeConfiguration`/implicit project config support
@@ -257,6 +259,12 @@ func getCapabilitiesWithDefaults(capabilities *lsproto.ClientCapabilities) *lspr
257259 if capabilitiesWithDefaults .TextDocument .Completion == nil {
258260 capabilitiesWithDefaults .TextDocument .Completion = defaultCompletionCapabilities
259261 }
262+ if capabilitiesWithDefaults .Workspace == nil {
263+ capabilitiesWithDefaults .Workspace = & lsproto.WorkspaceClientCapabilities {}
264+ }
265+ if capabilitiesWithDefaults .Workspace .Configuration == nil {
266+ capabilitiesWithDefaults .Workspace .Configuration = ptrTrue
267+ }
260268 return & capabilitiesWithDefaults
261269}
262270
@@ -269,6 +277,29 @@ func sendRequest[Params, Resp any](t *testing.T, f *FourslashTest, info lsproto.
269277 )
270278 f .writeMsg (t , req .Message ())
271279 resp := f .readMsg (t )
280+ if resp == nil {
281+ return nil , * new (Resp ), false
282+ }
283+
284+ // currently, the only request that may be sent by the server during a client request is one `config` request
285+ // !!! remove if `config` is handled in initialization and there are no other server-initiated requests
286+ if resp .Kind == lsproto .MessageKindRequest {
287+ req := resp .AsRequest ()
288+ switch req .Method {
289+ case lsproto .MethodWorkspaceConfiguration :
290+ req := lsproto.ResponseMessage {
291+ ID : req .ID ,
292+ JSONRPC : req .JSONRPC ,
293+ Result : []any {f .userPreferences },
294+ }
295+ f .writeMsg (t , req .Message ())
296+ resp = f .readMsg (t )
297+ default :
298+ // other types of requests not yet used in fourslash; implement them if needed
299+ t .Fatalf ("Unexpected request received: %s" , req .Method )
300+ }
301+ }
302+
272303 if resp == nil {
273304 return nil , * new (Resp ), false
274305 }
@@ -301,6 +332,21 @@ func (f *FourslashTest) readMsg(t *testing.T) *lsproto.Message {
301332 return msg
302333}
303334
335+ func (f * FourslashTest ) Configure (t * testing.T , config * ls.UserPreferences ) {
336+ f .userPreferences = config
337+ sendNotification (t , f , lsproto .WorkspaceDidChangeConfigurationInfo , & lsproto.DidChangeConfigurationParams {
338+ Settings : config ,
339+ })
340+ }
341+
342+ func (f * FourslashTest ) ConfigureWithReset (t * testing.T , config * ls.UserPreferences ) (reset func ()) {
343+ originalConfig := f .userPreferences .Copy ()
344+ f .Configure (t , config )
345+ return func () {
346+ f .Configure (t , originalConfig )
347+ }
348+ }
349+
304350func (f * FourslashTest ) GoToMarkerOrRange (t * testing.T , markerOrRange MarkerOrRange ) {
305351 f .goToMarker (t , markerOrRange )
306352}
@@ -568,12 +614,16 @@ func (f *FourslashTest) VerifyCompletions(t *testing.T, markerInput MarkerInput,
568614
569615func (f * FourslashTest ) verifyCompletionsWorker (t * testing.T , expected * CompletionsExpectedList ) * lsproto.CompletionList {
570616 prefix := f .getCurrentPositionPrefix ()
571- list := f .getCompletions (t )
617+ var userPreferences * ls.UserPreferences
618+ if expected != nil {
619+ userPreferences = expected .UserPreferences
620+ }
621+ list := f .getCompletions (t , userPreferences )
572622 f .verifyCompletionsResult (t , list , expected , prefix )
573623 return list
574624}
575625
576- func (f * FourslashTest ) getCompletions (t * testing.T ) * lsproto.CompletionList {
626+ func (f * FourslashTest ) getCompletions (t * testing.T , userPreferences * ls. UserPreferences ) * lsproto.CompletionList {
577627 prefix := f .getCurrentPositionPrefix ()
578628 params := & lsproto.CompletionParams {
579629 TextDocument : lsproto.TextDocumentIdentifier {
@@ -582,6 +632,10 @@ func (f *FourslashTest) getCompletions(t *testing.T) *lsproto.CompletionList {
582632 Position : f .currentCaretPosition ,
583633 Context : & lsproto.CompletionContext {},
584634 }
635+ if userPreferences != nil {
636+ reset := f .ConfigureWithReset (t , userPreferences )
637+ defer reset ()
638+ }
585639 resMsg , result , resultOk := sendRequest (t , f , lsproto .TextDocumentCompletionInfo , params )
586640 if resMsg == nil {
587641 t .Fatalf (prefix + "Nil response received for completion request" , f .lastKnownMarkerName )
@@ -867,11 +921,22 @@ type ApplyCodeActionFromCompletionOptions struct {
867921 Description string
868922 NewFileContent * string
869923 NewRangeContent * string
924+ UserPreferences * ls.UserPreferences
870925}
871926
872927func (f * FourslashTest ) VerifyApplyCodeActionFromCompletion (t * testing.T , markerName * string , options * ApplyCodeActionFromCompletionOptions ) {
873928 f .GoToMarker (t , * markerName )
874- completionsList := f .getCompletions (t )
929+ var userPreferences * ls.UserPreferences
930+ if options != nil && options .UserPreferences != nil {
931+ userPreferences = options .UserPreferences
932+ } else {
933+ // Default preferences: enables auto-imports
934+ userPreferences = ls .NewDefaultUserPreferences ()
935+ }
936+
937+ reset := f .ConfigureWithReset (t , userPreferences )
938+ defer reset ()
939+ completionsList := f .getCompletions (t , nil ) // Already configured, so we do not need to pass it in again
875940 item := core .Find (completionsList .Items , func (item * lsproto.CompletionItem ) bool {
876941 if item .Label != options .Name || item .Data == nil {
877942 return false
@@ -1663,6 +1728,12 @@ func (f *FourslashTest) getCurrentPositionPrefix() string {
16631728}
16641729
16651730func (f * FourslashTest ) BaselineAutoImportsCompletions (t * testing.T , markerNames []string ) {
1731+ reset := f .ConfigureWithReset (t , & ls.UserPreferences {
1732+ IncludeCompletionsForModuleExports : core .TSTrue ,
1733+ IncludeCompletionsForImportStatements : core .TSTrue ,
1734+ })
1735+ defer reset ()
1736+
16661737 for _ , markerName := range markerNames {
16671738 f .GoToMarker (t , markerName )
16681739 params := & lsproto.CompletionParams {
0 commit comments