-
Notifications
You must be signed in to change notification settings - Fork 666
Generate LSP response types, redo nullable, delete aliases, statically type LSP handlers #1441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 25 commits
49cdeb4
5174451
f10463f
a10f21c
d137984
2dfcb22
7eb0285
92b08b2
27f3a0d
ac16f29
baa769f
f45bcf6
f2c67b5
901e2ff
2474821
ffa8966
f1ce4fa
d7ae5a2
073938b
0ead675
b3cbf06
1b6c908
84b8eb8
95a3822
b74c621
8cb0b69
2afa446
6cfcada
827369b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -230,8 +230,8 @@ func (f *FourslashTest) initialize(t *testing.T, capabilities *lsproto.ClientCap | |
params := &lsproto.InitializeParams{} | ||
params.Capabilities = getCapabilitiesWithDefaults(capabilities) | ||
// !!! check for errors? | ||
f.sendRequest(t, lsproto.MethodInitialize, params) | ||
f.sendNotification(t, lsproto.MethodInitialized, &lsproto.InitializedParams{}) | ||
sendRequest(t, f, lsproto.InitializeInfo, params) | ||
sendNotification(t, f, lsproto.InitializedInfo, &lsproto.InitializedParams{}) | ||
} | ||
|
||
var ( | ||
|
@@ -267,20 +267,25 @@ func getCapabilitiesWithDefaults(capabilities *lsproto.ClientCapabilities) *lspr | |
return &capabilitiesWithDefaults | ||
} | ||
|
||
func (f *FourslashTest) sendRequest(t *testing.T, method lsproto.Method, params any) *lsproto.Message { | ||
func sendRequest[Params, Resp any](t *testing.T, f *FourslashTest, mapping lsproto.RequestInfo[Params, Resp], params Params) (*lsproto.Message, Resp, bool) { | ||
id := f.nextID() | ||
req := lsproto.NewRequestMessage( | ||
method, | ||
mapping.Method, | ||
lsproto.NewID(lsproto.IntegerOrString{Integer: &id}), | ||
params, | ||
) | ||
f.writeMsg(t, req.Message()) | ||
return f.readMsg(t) | ||
resp := f.readMsg(t) | ||
if resp == nil { | ||
return nil, *new(Resp), false | ||
} | ||
result, ok := resp.AsResponse().Result.(Resp) | ||
return resp, result, ok | ||
} | ||
|
||
func (f *FourslashTest) sendNotification(t *testing.T, method lsproto.Method, params any) { | ||
func sendNotification[Params any](t *testing.T, f *FourslashTest, info lsproto.NotificationInfo[Params], params Params) { | ||
notification := lsproto.NewNotificationMessage( | ||
method, | ||
info.Method, | ||
params, | ||
) | ||
f.writeMsg(t, notification.Message()) | ||
|
@@ -430,7 +435,7 @@ func (f *FourslashTest) openFile(t *testing.T, filename string) { | |
t.Fatalf("File %s not found in test data", filename) | ||
} | ||
f.activeFilename = filename | ||
f.sendNotification(t, lsproto.MethodTextDocumentDidOpen, &lsproto.DidOpenTextDocumentParams{ | ||
sendNotification(t, f, lsproto.TextDocumentDidOpenInfo, &lsproto.DidOpenTextDocumentParams{ | ||
TextDocument: &lsproto.TextDocumentItem{ | ||
Uri: ls.FileNameToDocumentURI(filename), | ||
LanguageId: getLanguageKind(filename), | ||
|
@@ -544,17 +549,14 @@ func (f *FourslashTest) verifyCompletionsWorker(t *testing.T, expected *Completi | |
TextDocumentPositionParams: f.currentTextDocumentPositionParams(), | ||
Context: &lsproto.CompletionContext{}, | ||
} | ||
resMsg := f.sendRequest(t, lsproto.MethodTextDocumentCompletion, params) | ||
resMsg, result, resultOk := sendRequest(t, f, lsproto.TextDocumentCompletionInfo, params) | ||
if resMsg == nil { | ||
t.Fatalf(prefix+"Nil response received for completion request", f.lastKnownMarkerName) | ||
} | ||
result := resMsg.AsResponse().Result | ||
switch result := result.(type) { | ||
case *lsproto.CompletionList: | ||
f.verifyCompletionsResult(t, f.currentCaretPosition, result, expected, prefix) | ||
default: | ||
t.Fatalf(prefix+"Unexpected response type for completion request: %v", result) | ||
if !resultOk { | ||
t.Fatalf(prefix+"Unexpected response type for completion request: %T", resMsg.AsResponse().Result) | ||
} | ||
Comment on lines
553
to
558
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It'd be ideal if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to do this, but it means I have to also pass in |
||
f.verifyCompletionsResult(t, f.currentCaretPosition, result.CompletionList, expected, prefix) | ||
} | ||
|
||
func (f *FourslashTest) verifyCompletionsResult( | ||
|
@@ -732,15 +734,14 @@ var completionIgnoreOpts = cmp.FilterPath( | |
|
||
func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual *lsproto.CompletionItem, expected *lsproto.CompletionItem) { | ||
if expected.Detail != nil || expected.Documentation != nil { | ||
response := f.sendRequest(t, lsproto.MethodCompletionItemResolve, actual) | ||
if response == nil { | ||
resMsg, result, resultOk := sendRequest(t, f, lsproto.CompletionItemResolveInfo, actual) | ||
if resMsg == nil { | ||
t.Fatal(prefix + "Expected non-nil response for completion item resolve, got nil") | ||
} | ||
resolvedItem, ok := response.AsResponse().Result.(*lsproto.CompletionItem) | ||
if !ok { | ||
t.Fatalf(prefix+"Expected response to be *lsproto.CompletionItem, got %T", response.AsResponse().Result) | ||
if !resultOk { | ||
t.Fatalf(prefix+"Unexpected response type for completion item resolve: %T", resMsg.AsResponse().Result) | ||
} | ||
actual = resolvedItem | ||
actual = result | ||
} | ||
assertDeepEqual(t, actual, expected, prefix, completionIgnoreOpts) | ||
if expected.Kind != nil { | ||
|
@@ -799,28 +800,27 @@ func (f *FourslashTest) VerifyBaselineFindAllReferences( | |
TextDocumentPositionParams: f.currentTextDocumentPositionParams(), | ||
Context: &lsproto.ReferenceContext{}, | ||
} | ||
resMsg := f.sendRequest(t, lsproto.MethodTextDocumentReferences, params) | ||
resMsg, result, resultOk := sendRequest(t, f, lsproto.TextDocumentReferencesInfo, params) | ||
if resMsg == nil { | ||
if f.lastKnownMarkerName == nil { | ||
t.Fatalf("Nil response received for references request at pos %v", f.currentCaretPosition) | ||
} else { | ||
t.Fatalf("Nil response received for references request at marker '%s'", *f.lastKnownMarkerName) | ||
} | ||
} | ||
|
||
result := resMsg.AsResponse().Result | ||
if resultAsLocation, ok := result.([]*lsproto.Location); ok { | ||
f.baseline.addResult("findAllReferences", f.getBaselineForLocationsWithFileContents(resultAsLocation, baselineFourslashLocationsOptions{ | ||
marker: markerOrRange.GetMarker(), | ||
markerName: "/*FIND ALL REFS*/", | ||
})) | ||
} else { | ||
if !resultOk { | ||
if f.lastKnownMarkerName == nil { | ||
t.Fatalf("Unexpected references response type at pos %v: %T", f.currentCaretPosition, result) | ||
t.Fatalf("Unexpected references response type at pos %v: %T", f.currentCaretPosition, resMsg.AsResponse().Result) | ||
} else { | ||
t.Fatalf("Unexpected references response type at marker '%s': %T", *f.lastKnownMarkerName, result) | ||
t.Fatalf("Unexpected references response type at marker '%s': %T", *f.lastKnownMarkerName, resMsg.AsResponse().Result) | ||
} | ||
} | ||
|
||
f.baseline.addResult("findAllReferences", f.getBaselineForLocationsWithFileContents(*result, baselineFourslashLocationsOptions{ | ||
marker: markerOrRange.GetMarker(), | ||
markerName: "/*FIND ALL REFS*/", | ||
})) | ||
|
||
} | ||
|
||
baseline.Run(t, f.baseline.getBaselineFileName(), f.baseline.content.String(), baseline.Options{}) | ||
|
@@ -854,39 +854,38 @@ func (f *FourslashTest) VerifyBaselineGoToDefinition( | |
params := &lsproto.DefinitionParams{ | ||
TextDocumentPositionParams: f.currentTextDocumentPositionParams(), | ||
} | ||
resMsg := f.sendRequest(t, lsproto.MethodTextDocumentDefinition, params) | ||
|
||
resMsg, result, resultOk := sendRequest(t, f, lsproto.TextDocumentDefinitionInfo, params) | ||
if resMsg == nil { | ||
if f.lastKnownMarkerName == nil { | ||
t.Fatalf("Nil response received for definition request at pos %v", f.currentCaretPosition) | ||
} else { | ||
t.Fatalf("Nil response received for definition request at marker '%s'", *f.lastKnownMarkerName) | ||
} | ||
} | ||
|
||
result := resMsg.AsResponse().Result | ||
if resultAsLocOrLocations, ok := result.(*lsproto.LocationOrLocations); ok { | ||
var resultAsLocations []*lsproto.Location | ||
if resultAsLocOrLocations != nil { | ||
if resultAsLocOrLocations.Locations != nil { | ||
resultAsLocations = core.Map(*resultAsLocOrLocations.Locations, func(loc lsproto.Location) *lsproto.Location { | ||
return &loc | ||
}) | ||
} else { | ||
resultAsLocations = []*lsproto.Location{resultAsLocOrLocations.Location} | ||
} | ||
if !resultOk { | ||
if f.lastKnownMarkerName == nil { | ||
t.Fatalf("Unexpected definition response type at pos %v: %T", f.currentCaretPosition, resMsg.AsResponse().Result) | ||
} else { | ||
t.Fatalf("Unexpected definition response type at marker '%s': %T", *f.lastKnownMarkerName, resMsg.AsResponse().Result) | ||
} | ||
} | ||
|
||
f.baseline.addResult("goToDefinition", f.getBaselineForLocationsWithFileContents(resultAsLocations, baselineFourslashLocationsOptions{ | ||
marker: markerOrRange.GetMarker(), | ||
markerName: "/*GO TO DEFINITION*/", | ||
})) | ||
} else { | ||
if f.lastKnownMarkerName == nil { | ||
t.Fatalf("Unexpected definition response type at pos %v: %T", f.currentCaretPosition, result) | ||
var resultAsLocations []lsproto.Location | ||
if result != nil { | ||
if result.Locations != nil { | ||
resultAsLocations = *result.Locations | ||
} else if result.Location != nil { | ||
resultAsLocations = []lsproto.Location{*result.Location} | ||
} else { | ||
t.Fatalf("Unexpected definition response type at marker '%s': %T", *f.lastKnownMarkerName, result) | ||
t.Fatalf("Unexpected definition response type at marker '%s': %T", *f.lastKnownMarkerName, result.DefinitionLinks) | ||
} | ||
} | ||
|
||
f.baseline.addResult("goToDefinition", f.getBaselineForLocationsWithFileContents(resultAsLocations, baselineFourslashLocationsOptions{ | ||
marker: markerOrRange.GetMarker(), | ||
markerName: "/*GO TO DEFINITION*/", | ||
})) | ||
} | ||
|
||
baseline.Run(t, f.baseline.getBaselineFileName(), f.baseline.content.String(), baseline.Options{}) | ||
|
@@ -1060,14 +1059,14 @@ func (f *FourslashTest) editScript(t *testing.T, fileName string, start int, end | |
if err != nil { | ||
panic(fmt.Sprintf("Failed to write file %s: %v", fileName, err)) | ||
} | ||
f.sendNotification(t, lsproto.MethodTextDocumentDidChange, &lsproto.DidChangeTextDocumentParams{ | ||
sendNotification(t, f, lsproto.TextDocumentDidChangeInfo, &lsproto.DidChangeTextDocumentParams{ | ||
TextDocument: lsproto.VersionedTextDocumentIdentifier{ | ||
TextDocumentIdentifier: lsproto.TextDocumentIdentifier{ | ||
Uri: ls.FileNameToDocumentURI(fileName), | ||
}, | ||
Version: script.version, | ||
}, | ||
ContentChanges: []lsproto.TextDocumentContentChangeEvent{ | ||
ContentChanges: []lsproto.TextDocumentContentChangePartialOrTextDocumentContentChangeWholeDocument{ | ||
{ | ||
TextDocumentContentChangePartial: &lsproto.TextDocumentContentChangePartial{ | ||
Range: changeRange, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My nit is that I'd prefer fourslash still come first, but it's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I do that, then lint rules that say "
t
comes first" will get mad.