mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Improve autocomplete locking
This commit is contained in:
@@ -73,7 +73,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
|
||||
/// <summary>
|
||||
// Callback for ondisconnect handler
|
||||
/// </summary>
|
||||
public delegate Task OnDisconnectHandler(ConnectionSummary summary);
|
||||
public delegate Task OnDisconnectHandler(ConnectionSummary summary, string ownerUri);
|
||||
|
||||
/// <summary>
|
||||
/// List of onconnection handlers
|
||||
@@ -241,7 +241,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
|
||||
// Invoke callback notifications
|
||||
foreach (var activity in this.onDisconnectActivities)
|
||||
{
|
||||
activity(info.ConnectionDetails);
|
||||
activity(info.ConnectionDetails, disconnectParams.OwnerUri);
|
||||
}
|
||||
|
||||
// Success
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
@@ -487,7 +492,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
Label = autoCompleteItem.Title,
|
||||
Kind = CompletionItemKind.Variable,
|
||||
Detail = autoCompleteItem.Title,
|
||||
Documentation = autoCompleteItem.Description,
|
||||
// Documentation = autoCompleteItem.Description,
|
||||
TextEdit = new TextEdit
|
||||
{
|
||||
NewText = autoCompleteItem.Title,
|
||||
@@ -510,5 +515,76 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
|
||||
return completions.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Preinitialize the parser and binder with common metadata.
|
||||
/// This should front load the long binding wait to the time the
|
||||
/// connection is established. Once this is completed other binding
|
||||
/// requests should be faster.
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="scriptInfo"></param>
|
||||
internal static void PrepopulateCommonMetadata(ConnectionInfo info, ScriptParseInfo scriptInfo)
|
||||
{
|
||||
if (scriptInfo.IsConnected)
|
||||
{
|
||||
var scriptFile = WorkspaceService<SqlToolsSettings>.Instance.Workspace.GetFile(info.OwnerUri);
|
||||
LanguageService.Instance.ParseAndBind(scriptFile, info);
|
||||
|
||||
if (scriptInfo.BuildingMetadataEvent.WaitOne(LanguageService.OnConnectionWaitTimeout))
|
||||
{
|
||||
try
|
||||
{
|
||||
scriptInfo.BuildingMetadataEvent.Reset();
|
||||
|
||||
// parse a simple statement that returns common metadata
|
||||
ParseResult parseResult = Parser.Parse(
|
||||
"select ",
|
||||
scriptInfo.ParseOptions);
|
||||
|
||||
List<ParseResult> parseResults = new List<ParseResult>();
|
||||
parseResults.Add(parseResult);
|
||||
scriptInfo.Binder.Bind(
|
||||
parseResults,
|
||||
info.ConnectionDetails.DatabaseName,
|
||||
BindMode.Batch);
|
||||
|
||||
// get the completion list from SQL Parser
|
||||
var suggestions = Resolver.FindCompletions(
|
||||
parseResult, 1, 8,
|
||||
scriptInfo.MetadataDisplayInfoProvider);
|
||||
|
||||
// this forces lazy evaluation of the suggestion metadata
|
||||
AutoCompleteHelper.ConvertDeclarationsToCompletionItems(suggestions, 1, 8, 8);
|
||||
|
||||
parseResult = Parser.Parse(
|
||||
"exec ",
|
||||
scriptInfo.ParseOptions);
|
||||
|
||||
parseResults = new List<ParseResult>();
|
||||
parseResults.Add(parseResult);
|
||||
scriptInfo.Binder.Bind(
|
||||
parseResults,
|
||||
info.ConnectionDetails.DatabaseName,
|
||||
BindMode.Batch);
|
||||
|
||||
// get the completion list from SQL Parser
|
||||
suggestions = Resolver.FindCompletions(
|
||||
parseResult, 1, 6,
|
||||
scriptInfo.MetadataDisplayInfoProvider);
|
||||
|
||||
// this forces lazy evaluation of the suggestion metadata
|
||||
AutoCompleteHelper.ConvertDeclarationsToCompletionItems(suggestions, 1, 6, 6);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
scriptInfo.BuildingMetadataEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.SqlParser;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlServer.Management.SmoMetadataProvider;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
|
||||
@@ -15,16 +22,9 @@ using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.SqlParser;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using Microsoft.SqlServer.Management.SmoMetadataProvider;
|
||||
using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
@@ -35,15 +35,19 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// </summary>
|
||||
public sealed class LanguageService
|
||||
{
|
||||
public const string DefaultBatchSeperator = "GO";
|
||||
internal const string DefaultBatchSeperator = "GO";
|
||||
|
||||
private const int DiagnosticParseDelay = 750;
|
||||
internal const int DiagnosticParseDelay = 750;
|
||||
|
||||
private const int FindCompletionsTimeout = 3000;
|
||||
internal const int FindCompletionsTimeout = 3000;
|
||||
|
||||
private const int FindCompletionStartTimeout = 50;
|
||||
internal const int FindCompletionStartTimeout = 50;
|
||||
|
||||
private const int OnConnectionWaitTimeout = 30000;
|
||||
internal const int OnConnectionWaitTimeout = 300000;
|
||||
|
||||
private object parseMapLock = new object();
|
||||
|
||||
private ScriptParseInfo currentCompletionParseInfo;
|
||||
|
||||
private bool ShouldEnableAutocomplete()
|
||||
{
|
||||
@@ -196,6 +200,21 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
await requestContext.SendResult(completionItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the resolve completion request event to provide additional
|
||||
/// autocomplete metadata to the currently select completion item
|
||||
/// </summary>
|
||||
/// <param name="completionItem"></param>
|
||||
/// <param name="requestContext"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task HandleCompletionResolveRequest(
|
||||
CompletionItem completionItem,
|
||||
RequestContext<CompletionItem> requestContext)
|
||||
{
|
||||
completionItem = LanguageService.Instance.ResolveCompletionItem(completionItem);
|
||||
await requestContext.SendResult(completionItem);
|
||||
}
|
||||
|
||||
private static async Task HandleDefinitionRequest(
|
||||
TextDocumentPosition textDocumentPosition,
|
||||
RequestContext<Location[]> requestContext)
|
||||
@@ -212,14 +231,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private static async Task HandleCompletionResolveRequest(
|
||||
CompletionItem completionItem,
|
||||
RequestContext<CompletionItem> requestContext)
|
||||
{
|
||||
Logger.Write(LogLevel.Verbose, "HandleCompletionResolveRequest");
|
||||
await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private static async Task HandleSignatureHelpRequest(
|
||||
TextDocumentPosition textDocumentPosition,
|
||||
RequestContext<SignatureHelp> requestContext)
|
||||
@@ -327,8 +338,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// it is the last URI connected to a particular connection,
|
||||
/// then remove the cache.
|
||||
/// </summary>
|
||||
public async Task RemoveAutoCompleteCacheUriReference(ConnectionSummary summary)
|
||||
public async Task RemoveAutoCompleteCacheUriReference(ConnectionSummary summary, string ownerUri)
|
||||
{
|
||||
RemoveScriptParseInfo(ownerUri);
|
||||
|
||||
// currently this method is disabled, but we need to reimplement now that the
|
||||
// implementation of the 'cache' has changed.
|
||||
await Task.FromResult(0);
|
||||
@@ -342,16 +355,16 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// <returns></returns>
|
||||
public ParseResult ParseAndBind(ScriptFile scriptFile, ConnectionInfo connInfo)
|
||||
{
|
||||
ScriptParseInfo parseInfo = null;
|
||||
if (this.ScriptParseInfoMap.ContainsKey(scriptFile.ClientFilePath))
|
||||
{
|
||||
parseInfo = this.ScriptParseInfoMap[scriptFile.ClientFilePath];
|
||||
}
|
||||
else
|
||||
{
|
||||
parseInfo = new ScriptParseInfo();
|
||||
this.ScriptParseInfoMap.Add(scriptFile.ClientFilePath, parseInfo);
|
||||
}
|
||||
// get or create the current parse info object
|
||||
ScriptParseInfo parseInfo = GetScriptParseInfo(scriptFile.ClientFilePath, createIfNotExists: true);
|
||||
|
||||
// parse current SQL file contents to retrieve a list of errors
|
||||
ParseResult parseResult = Parser.IncrementalParse(
|
||||
scriptFile.Contents,
|
||||
parseInfo.ParseResult,
|
||||
parseInfo.ParseOptions);
|
||||
|
||||
parseInfo.ParseResult = parseResult;
|
||||
|
||||
if (parseInfo.BuildingMetadataEvent.WaitOne(LanguageService.FindCompletionsTimeout))
|
||||
{
|
||||
@@ -359,14 +372,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
parseInfo.BuildingMetadataEvent.Reset();
|
||||
|
||||
// parse current SQL file contents to retrieve a list of errors
|
||||
ParseResult parseResult = Parser.IncrementalParse(
|
||||
scriptFile.Contents,
|
||||
parseInfo.ParseResult,
|
||||
parseInfo.ParseOptions);
|
||||
|
||||
parseInfo.ParseResult = parseResult;
|
||||
|
||||
if (connInfo != null && parseInfo.IsConnected)
|
||||
{
|
||||
try
|
||||
@@ -398,7 +403,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the cached autocomplete candidate list when the user connects to a database
|
||||
/// Update the autocomplete metadata provider when the user connects to a database
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
public async Task UpdateLanguageServiceOnConnection(ConnectionInfo info)
|
||||
@@ -407,43 +412,38 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
if (ShouldEnableAutocomplete())
|
||||
{
|
||||
ScriptParseInfo scriptInfo =
|
||||
this.ScriptParseInfoMap.ContainsKey(info.OwnerUri)
|
||||
? this.ScriptParseInfoMap[info.OwnerUri]
|
||||
: new ScriptParseInfo();
|
||||
|
||||
try
|
||||
ScriptParseInfo scriptInfo = GetScriptParseInfo(info.OwnerUri, createIfNotExists: true);
|
||||
if (scriptInfo.BuildingMetadataEvent.WaitOne(LanguageService.OnConnectionWaitTimeout))
|
||||
{
|
||||
scriptInfo.BuildingMetadataEvent.WaitOne(LanguageService.OnConnectionWaitTimeout);
|
||||
scriptInfo.BuildingMetadataEvent.Reset();
|
||||
|
||||
var sqlConn = info.SqlConnection as ReliableSqlConnection;
|
||||
if (sqlConn != null)
|
||||
try
|
||||
{
|
||||
ServerConnection serverConn = new ServerConnection(sqlConn.GetUnderlyingConnection());
|
||||
scriptInfo.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
|
||||
scriptInfo.MetadataProvider = SmoMetadataProvider.CreateConnectedProvider(serverConn);
|
||||
scriptInfo.Binder = BinderProvider.CreateBinder(scriptInfo.MetadataProvider);
|
||||
scriptInfo.ServerConnection = new ServerConnection(sqlConn.GetUnderlyingConnection());
|
||||
this.ScriptParseInfoMap[info.OwnerUri] = scriptInfo;
|
||||
scriptInfo.BuildingMetadataEvent.Reset();
|
||||
var sqlConn = info.SqlConnection as ReliableSqlConnection;
|
||||
if (sqlConn != null)
|
||||
{
|
||||
ServerConnection serverConn = new ServerConnection(sqlConn.GetUnderlyingConnection());
|
||||
scriptInfo.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
|
||||
scriptInfo.MetadataProvider = SmoMetadataProvider.CreateConnectedProvider(serverConn);
|
||||
scriptInfo.Binder = BinderProvider.CreateBinder(scriptInfo.MetadataProvider);
|
||||
scriptInfo.ServerConnection = new ServerConnection(sqlConn.GetUnderlyingConnection());
|
||||
scriptInfo.IsConnected = true;
|
||||
AddOrUpdateScriptParseInfo(info.OwnerUri, scriptInfo);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
scriptInfo.IsConnected = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Set Metadata Build event to Signal state.
|
||||
// (Tell Language Service that I am ready with Metadata Provider Object)
|
||||
scriptInfo.BuildingMetadataEvent.Set();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
scriptInfo.IsConnected = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Set Metadata Build event to Signal state.
|
||||
// (Tell Language Service that I am ready with Metadata Provider Object)
|
||||
scriptInfo.BuildingMetadataEvent.Set();
|
||||
}
|
||||
|
||||
if (scriptInfo.IsConnected)
|
||||
{
|
||||
var scriptFile = WorkspaceService<SqlToolsSettings>.Instance.Workspace.GetFile(info.OwnerUri);
|
||||
ParseAndBind(scriptFile, info);
|
||||
}
|
||||
// populate SMO metadata provider with most common info
|
||||
AutoCompleteHelper.PrepopulateCommonMetadata(info, scriptInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -466,6 +466,28 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
|| !string.Equals(prevSqlText, currentSqlText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the details and documentation for a completion item
|
||||
/// </summary>
|
||||
/// <param name="completionItem"></param>
|
||||
internal CompletionItem ResolveCompletionItem(CompletionItem completionItem)
|
||||
{
|
||||
var scriptParseInfo = LanguageService.Instance.currentCompletionParseInfo;
|
||||
if (scriptParseInfo != null && scriptParseInfo.CurrentSuggestions != null)
|
||||
{
|
||||
foreach (var suggestion in scriptParseInfo.CurrentSuggestions)
|
||||
{
|
||||
if (string.Equals(suggestion.Title, completionItem.Label))
|
||||
{
|
||||
completionItem.Detail = suggestion.DatabaseQualifiedName;
|
||||
completionItem.Documentation = suggestion.Description;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return completionItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the completion item list for the current text position.
|
||||
/// This method does not await cache builds since it expects to return quickly
|
||||
@@ -479,20 +501,22 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
string filePath = textDocumentPosition.TextDocument.Uri;
|
||||
int startLine = textDocumentPosition.Position.Line;
|
||||
int startColumn = TextUtilities.PositionOfPrevDelimeter(
|
||||
scriptFile.Contents,
|
||||
scriptFile.Contents,
|
||||
textDocumentPosition.Position.Line,
|
||||
textDocumentPosition.Position.Character);
|
||||
int endColumn = textDocumentPosition.Position.Character;
|
||||
|
||||
this.currentCompletionParseInfo = null;
|
||||
|
||||
// Take a reference to the list at a point in time in case we update and replace the list
|
||||
if (connInfo == null
|
||||
|| !LanguageService.Instance.ScriptParseInfoMap.ContainsKey(textDocumentPosition.TextDocument.Uri))
|
||||
|
||||
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
|
||||
if (connInfo == null || scriptParseInfo == null)
|
||||
{
|
||||
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn);
|
||||
}
|
||||
|
||||
// reparse and bind the SQL statement if needed
|
||||
var scriptParseInfo = ScriptParseInfoMap[textDocumentPosition.TextDocument.Uri];
|
||||
if (RequiresReparse(scriptParseInfo, scriptFile))
|
||||
{
|
||||
ParseAndBind(scriptFile, connInfo);
|
||||
@@ -511,15 +535,18 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
try
|
||||
{
|
||||
// get the completion list from SQL Parser
|
||||
var suggestions = Resolver.FindCompletions(
|
||||
scriptParseInfo.CurrentSuggestions = Resolver.FindCompletions(
|
||||
scriptParseInfo.ParseResult,
|
||||
textDocumentPosition.Position.Line + 1,
|
||||
textDocumentPosition.Position.Character + 1,
|
||||
scriptParseInfo.MetadataDisplayInfoProvider);
|
||||
|
||||
// cache the current script parse info object to resolve completions later
|
||||
this.currentCompletionParseInfo = scriptParseInfo;
|
||||
|
||||
// convert the suggestion list to the VS Code format
|
||||
return AutoCompleteHelper.ConvertDeclarationsToCompletionItems(
|
||||
suggestions,
|
||||
scriptParseInfo.CurrentSuggestions,
|
||||
startLine,
|
||||
startColumn,
|
||||
endColumn);
|
||||
@@ -685,5 +712,60 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void AddOrUpdateScriptParseInfo(string uri, ScriptParseInfo scriptInfo)
|
||||
{
|
||||
lock (this.parseMapLock)
|
||||
{
|
||||
if (this.ScriptParseInfoMap.ContainsKey(uri))
|
||||
{
|
||||
this.ScriptParseInfoMap[uri] = scriptInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ScriptParseInfoMap.Add(uri, scriptInfo);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private ScriptParseInfo GetScriptParseInfo(string uri, bool createIfNotExists = false)
|
||||
{
|
||||
lock (this.parseMapLock)
|
||||
{
|
||||
if (this.ScriptParseInfoMap.ContainsKey(uri))
|
||||
{
|
||||
return this.ScriptParseInfoMap[uri];
|
||||
}
|
||||
else if (createIfNotExists)
|
||||
{
|
||||
ScriptParseInfo scriptInfo = new ScriptParseInfo();
|
||||
this.ScriptParseInfoMap.Add(uri, scriptInfo);
|
||||
return scriptInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool RemoveScriptParseInfo(string uri)
|
||||
{
|
||||
lock (this.parseMapLock)
|
||||
{
|
||||
if (this.ScriptParseInfoMap.ContainsKey(uri))
|
||||
{
|
||||
var scriptInfo = this.ScriptParseInfoMap[uri];
|
||||
scriptInfo.ServerConnection.Disconnect();
|
||||
scriptInfo.ServerConnection = null;
|
||||
return this.ScriptParseInfoMap.Remove(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.SmoMetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Common;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
|
||||
using Microsoft.SqlServer.Management.SqlParser.Parser;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
{
|
||||
@@ -33,7 +35,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
get { return this.buildingMetadataEvent; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag determining is the LanguageService is connected
|
||||
/// </summary>
|
||||
@@ -56,7 +57,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
isQuotedIdentifierSet: true,
|
||||
compatibilityLevel: DatabaseCompatibilityLevel,
|
||||
transactSqlVersion: TransactSqlVersion);
|
||||
this.IsConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +143,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
/// </summary>
|
||||
public MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current autocomplete suggestion list
|
||||
/// </summary>
|
||||
public IEnumerable<Declaration> CurrentSuggestions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the database compatibility level from a server version
|
||||
/// </summary>
|
||||
@@ -193,6 +198,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
||||
default:
|
||||
return TransactSqlVersion.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
|
||||
internal class LogWriter : IDisposable
|
||||
{
|
||||
private object logLock = new object();
|
||||
|
||||
private TextWriter textWriter;
|
||||
private LogLevel minimumLogLevel = LogLevel.Verbose;
|
||||
|
||||
@@ -170,24 +172,28 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
if (this.textWriter != null &&
|
||||
logLevel >= this.minimumLogLevel)
|
||||
{
|
||||
// Print the timestamp and log level
|
||||
this.textWriter.WriteLine(
|
||||
"{0} [{1}] - Method \"{2}\" at line {3} of {4}\r\n",
|
||||
DateTime.Now,
|
||||
logLevel.ToString().ToUpper(),
|
||||
callerName,
|
||||
callerLineNumber,
|
||||
callerSourceFile);
|
||||
|
||||
// Print out indented message lines
|
||||
foreach (var messageLine in logMessage.Split('\n'))
|
||||
// System.IO is not thread safe
|
||||
lock (logLock)
|
||||
{
|
||||
this.textWriter.WriteLine(" " + messageLine.TrimEnd());
|
||||
}
|
||||
// Print the timestamp and log level
|
||||
this.textWriter.WriteLine(
|
||||
"{0} [{1}] - Method \"{2}\" at line {3} of {4}\r\n",
|
||||
DateTime.Now,
|
||||
logLevel.ToString().ToUpper(),
|
||||
callerName,
|
||||
callerLineNumber,
|
||||
callerSourceFile);
|
||||
|
||||
// Finish with a newline and flush the writer
|
||||
this.textWriter.WriteLine();
|
||||
this.textWriter.Flush();
|
||||
// Print out indented message lines
|
||||
foreach (var messageLine in logMessage.Split('\n'))
|
||||
{
|
||||
this.textWriter.WriteLine(" " + messageLine.TrimEnd());
|
||||
}
|
||||
|
||||
// Finish with a newline and flush the writer
|
||||
this.textWriter.WriteLine();
|
||||
this.textWriter.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user