LanguageService must send result or intellisense hangs (#395)

* LanguageService must send result or intellisense hangs
- Unless the language services methods return results for requests, the VSCode language service protocol will never send a response up to its higher-level code. This means with intellisense off, it appears to hang instead of saying "No results found". This is clearly sub-optimal and if any other extension wants to provide SQL suggestions, it would break them from sending results
- Minor refactor to fully remove Instance-field references in the code
This commit is contained in:
Kevin Cunnane
2017-06-23 13:36:43 -07:00
committed by GitHub
parent c28a97e6fa
commit 81d031d5eb
2 changed files with 41 additions and 17 deletions

View File

@@ -73,6 +73,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private WorkspaceService<SqlToolsSettings> workspaceServiceInstance; private WorkspaceService<SqlToolsSettings> workspaceServiceInstance;
private ServiceHost serviceHostInstance;
private object parseMapLock = new object(); private object parseMapLock = new object();
private ScriptParseInfo currentCompletionParseInfo; private ScriptParseInfo currentCompletionParseInfo;
@@ -178,6 +180,22 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
} }
internal ServiceHost ServiceHostInstance
{
get
{
if (this.serviceHostInstance == null)
{
this.serviceHostInstance = ServiceHost.Instance;
}
return this.serviceHostInstance;
}
set
{
this.serviceHostInstance = value;
}
}
/// <summary> /// <summary>
/// Gets the current settings /// Gets the current settings
/// </summary> /// </summary>
@@ -233,6 +251,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
await Task.FromResult(0); await Task.FromResult(0);
}); });
ServiceHostInstance = serviceHost;
// Register the configuration update handler // Register the configuration update handler
WorkspaceServiceInstance.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification); WorkspaceServiceInstance.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification);
@@ -270,7 +290,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// check if Intellisense suggestions are enabled // check if Intellisense suggestions are enabled
if (ShouldSkipIntellisense(textDocumentPosition.TextDocument.Uri)) if (ShouldSkipIntellisense(textDocumentPosition.TextDocument.Uri))
{ {
await Task.FromResult(true); await requestContext.SendResult(null);
} }
else else
{ {
@@ -283,7 +303,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
scriptFile.ClientFilePath, scriptFile.ClientFilePath,
out connInfo); out connInfo);
var completionItems = Instance.GetCompletionItems( var completionItems = GetCompletionItems(
textDocumentPosition, scriptFile, connInfo); textDocumentPosition, scriptFile, connInfo);
await requestContext.SendResult(completionItems); await requestContext.SendResult(completionItems);
@@ -305,7 +325,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// Note: Do not know file, so no need to check for MSSQL flavor // Note: Do not know file, so no need to check for MSSQL flavor
if (!CurrentWorkspaceSettings.IsSuggestionsEnabled) if (!CurrentWorkspaceSettings.IsSuggestionsEnabled)
{ {
await Task.FromResult(true); await requestContext.SendResult(completionItem);
} }
else else
{ {
@@ -369,14 +389,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ReferencesParams referencesParams, ReferencesParams referencesParams,
RequestContext<Location[]> requestContext) RequestContext<Location[]> requestContext)
{ {
await Task.FromResult(true); await requestContext.SendResult(null);
} }
private async Task HandleDocumentHighlightRequest( private async Task HandleDocumentHighlightRequest(
TextDocumentPosition textDocumentPosition, TextDocumentPosition textDocumentPosition,
RequestContext<DocumentHighlight[]> requestContext) RequestContext<DocumentHighlight[]> requestContext)
{ {
await Task.FromResult(true); await requestContext.SendResult(null);
} }
#endif #endif
@@ -387,7 +407,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// check if Intellisense suggestions are enabled // check if Intellisense suggestions are enabled
if (ShouldSkipNonMssqlFile(textDocumentPosition)) if (ShouldSkipNonMssqlFile(textDocumentPosition))
{ {
await Task.FromResult(true); await requestContext.SendResult(null);
} }
else else
{ {
@@ -528,19 +548,19 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
// Send a notification to signal that autocomplete is ready // Send a notification to signal that autocomplete is ready
ServiceHost.Instance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = connInfo.OwnerUri}); ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = connInfo.OwnerUri});
}); });
} }
else else
{ {
// Send a notification to signal that autocomplete is ready // Send a notification to signal that autocomplete is ready
await ServiceHost.Instance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri}); await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri});
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Write(LogLevel.Error, "Unknown error " + ex.ToString()); Logger.Write(LogLevel.Error, "Unknown error " + ex.ToString());
await ServiceHost.Instance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri}); await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri});
} }
} }
@@ -721,7 +741,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
PrepopulateCommonMetadata(info, scriptInfo, this.BindingQueue); PrepopulateCommonMetadata(info, scriptInfo, this.BindingQueue);
// Send a notification to signal that autocomplete is ready // Send a notification to signal that autocomplete is ready
ServiceHost.Instance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = info.OwnerUri}); ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = info.OwnerUri});
}); });
} }

View File

@@ -54,27 +54,31 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
} }
[Fact] [Fact]
public void HandleSignatureHelpRequestNonMssqlFile() public async Task HandleSignatureHelpRequestNonMssqlFile()
{ {
InitializeTestObjects(); InitializeTestObjects();
// setup the mock for SendResult // setup the mock for SendResult
var signatureRequestContext = new Mock<RequestContext<SignatureHelp>>(); var signatureRequestContext = new Mock<RequestContext<SignatureHelp>>();
SignatureHelp result = null;
signatureRequestContext.Setup(rc => rc.SendResult(It.IsAny<SignatureHelp>())) signatureRequestContext.Setup(rc => rc.SendResult(It.IsAny<SignatureHelp>()))
.Returns(Task.FromResult(0)); .Returns<SignatureHelp>((signature) => {
result = signature;
return Task.FromResult(0);
});
signatureRequestContext.Setup(rc => rc.SendError(It.IsAny<string>(), It.IsAny<int>())).Returns(Task.FromResult(0)); signatureRequestContext.Setup(rc => rc.SendError(It.IsAny<string>(), It.IsAny<int>())).Returns(Task.FromResult(0));
langService.CurrentWorkspaceSettings.SqlTools.IntelliSense.EnableIntellisense = true; langService.CurrentWorkspaceSettings.SqlTools.IntelliSense.EnableIntellisense = true;
langService.HandleDidChangeLanguageFlavorNotification(new LanguageFlavorChangeParams { await langService.HandleDidChangeLanguageFlavorNotification(new LanguageFlavorChangeParams {
Uri = textDocument.TextDocument.Uri, Uri = textDocument.TextDocument.Uri,
Language = LanguageService.SQL_LANG.ToLower(), Language = LanguageService.SQL_LANG.ToLower(),
Flavor = "NotMSSQL" Flavor = "NotMSSQL"
}, null); }, null);
Assert.NotNull(langService.HandleSignatureHelpRequest(textDocument, signatureRequestContext.Object)); await langService.HandleSignatureHelpRequest(textDocument, signatureRequestContext.Object);
// verify that the response was sent with a null response value
// verify that no events were sent signatureRequestContext.Verify(m => m.SendResult(It.IsAny<SignatureHelp>()), Times.Once());
signatureRequestContext.Verify(m => m.SendResult(It.IsAny<SignatureHelp>()), Times.Never()); Assert.Null(result);
signatureRequestContext.Verify(m => m.SendError(It.IsAny<string>(), It.IsAny<int>()), Times.Never()); signatureRequestContext.Verify(m => m.SendError(It.IsAny<string>(), It.IsAny<int>()), Times.Never());
} }