Add IntelliSense binding queue (#73)

* Initial code for binding queue

* Fix-up some of the timeout wait code

* Add some initial test code

* Add missing test file

* Update the binding queue tests

* Add more test coverage and refactor a bit.  Disable reliabile connection until we can fix it..it's holding an open data reader connection.

* A few more test updates

* Initial integrate queue with language service.

* Hook up the connected binding queue into al binding calls.

* Cleanup comments and remove dead code

* More missing comments

* Fix build break.  Reenable ReliabileConnection.

* Revert all changes to SqlConnectionFactory

* Resolve merge conflicts

* Cleanup some more of the timeouts and sync code

* Address code review feedback

* Address more code review feedback
This commit is contained in:
Karl Burtram
2016-10-04 14:55:59 -07:00
committed by GitHub
parent 1b8e9c1e86
commit 62525b9c98
18 changed files with 1409 additions and 360 deletions

View File

@@ -4,6 +4,7 @@
//
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlServer.Management.SqlParser.Parser;
@@ -21,6 +22,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// </summary>
public static class AutoCompleteHelper
{
private static WorkspaceService<SqlToolsSettings> workspaceServiceInstance;
private static readonly string[] DefaultCompletionText = new string[]
{
"absolute",
@@ -421,6 +424,26 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"zone"
};
/// <summary>
/// Gets or sets the current workspace service instance
/// Setter for internal testing purposes only
/// </summary>
internal static WorkspaceService<SqlToolsSettings> WorkspaceServiceInstance
{
get
{
if (AutoCompleteHelper.workspaceServiceInstance == null)
{
AutoCompleteHelper.workspaceServiceInstance = WorkspaceService<SqlToolsSettings>.Instance;
}
return AutoCompleteHelper.workspaceServiceInstance;
}
set
{
AutoCompleteHelper.workspaceServiceInstance = value;
}
}
/// <summary>
/// Get the default completion list from hard-coded list
/// </summary>
@@ -538,11 +561,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// </summary>
/// <param name="info"></param>
/// <param name="scriptInfo"></param>
internal static void PrepopulateCommonMetadata(ConnectionInfo info, ScriptParseInfo scriptInfo)
internal static void PrepopulateCommonMetadata(
ConnectionInfo info,
ScriptParseInfo scriptInfo,
ConnectedBindingQueue bindingQueue)
{
if (scriptInfo.IsConnected)
{
var scriptFile = WorkspaceService<SqlToolsSettings>.Instance.Workspace.GetFile(info.OwnerUri);
var scriptFile = AutoCompleteHelper.WorkspaceServiceInstance.Workspace.GetFile(info.OwnerUri);
LanguageService.Instance.ParseAndBind(scriptFile, info);
if (scriptInfo.BuildingMetadataEvent.WaitOne(LanguageService.OnConnectionWaitTimeout))
@@ -551,44 +577,52 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
scriptInfo.BuildingMetadataEvent.Reset();
// parse a simple statement that returns common metadata
ParseResult parseResult = Parser.Parse(
"select ",
scriptInfo.ParseOptions);
QueueItem queueItem = bindingQueue.QueueBindingOperation(
key: scriptInfo.ConnectionKey,
bindOperation: (bindingContext, cancelToken) =>
{
// parse a simple statement that returns common metadata
ParseResult parseResult = Parser.Parse(
"select ",
bindingContext.ParseOptions);
List<ParseResult> parseResults = new List<ParseResult>();
parseResults.Add(parseResult);
scriptInfo.Binder.Bind(
parseResults,
info.ConnectionDetails.DatabaseName,
BindMode.Batch);
List<ParseResult> parseResults = new List<ParseResult>();
parseResults.Add(parseResult);
bindingContext.Binder.Bind(
parseResults,
info.ConnectionDetails.DatabaseName,
BindMode.Batch);
// get the completion list from SQL Parser
var suggestions = Resolver.FindCompletions(
parseResult, 1, 8,
scriptInfo.MetadataDisplayInfoProvider);
// get the completion list from SQL Parser
var suggestions = Resolver.FindCompletions(
parseResult, 1, 8,
bindingContext.MetadataDisplayInfoProvider);
// this forces lazy evaluation of the suggestion metadata
AutoCompleteHelper.ConvertDeclarationsToCompletionItems(suggestions, 1, 8, 8);
// this forces lazy evaluation of the suggestion metadata
AutoCompleteHelper.ConvertDeclarationsToCompletionItems(suggestions, 1, 8, 8);
parseResult = Parser.Parse(
"exec ",
scriptInfo.ParseOptions);
parseResult = Parser.Parse(
"exec ",
bindingContext.ParseOptions);
parseResults = new List<ParseResult>();
parseResults.Add(parseResult);
scriptInfo.Binder.Bind(
parseResults,
info.ConnectionDetails.DatabaseName,
BindMode.Batch);
parseResults = new List<ParseResult>();
parseResults.Add(parseResult);
bindingContext.Binder.Bind(
parseResults,
info.ConnectionDetails.DatabaseName,
BindMode.Batch);
// get the completion list from SQL Parser
suggestions = Resolver.FindCompletions(
parseResult, 1, 6,
scriptInfo.MetadataDisplayInfoProvider);
// get the completion list from SQL Parser
suggestions = Resolver.FindCompletions(
parseResult, 1, 6,
bindingContext.MetadataDisplayInfoProvider);
// this forces lazy evaluation of the suggestion metadata
AutoCompleteHelper.ConvertDeclarationsToCompletionItems(suggestions, 1, 6, 6);
// this forces lazy evaluation of the suggestion metadata
AutoCompleteHelper.ConvertDeclarationsToCompletionItems(suggestions, 1, 6, 6);
return Task.FromResult(null as object);
});
queueItem.ItemProcessed.WaitOne();
}
catch
{
@@ -600,5 +634,53 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
}
}
}
/// <summary>
/// Converts a SQL Parser QuickInfo object into a VS Code Hover object
/// </summary>
/// <param name="quickInfo"></param>
/// <param name="row"></param>
/// <param name="startColumn"></param>
/// <param name="endColumn"></param>
internal static Hover ConvertQuickInfoToHover(
Babel.CodeObjectQuickInfo quickInfo,
int row,
int startColumn,
int endColumn)
{
// convert from the parser format to the VS Code wire format
var markedStrings = new MarkedString[1];
if (quickInfo != null)
{
markedStrings[0] = new MarkedString()
{
Language = "SQL",
Value = quickInfo.Text
};
return new Hover()
{
Contents = markedStrings,
Range = new Range
{
Start = new Position
{
Line = row,
Character = startColumn
},
End = new Position
{
Line = row,
Character = endColumn
}
}
};
}
else
{
return null;
}
}
}
}