Feature/cleanups1 (#114)

* Intellisense cleanups.

* Additional intellisense cleanups for default list

* Add missing Monitor.Exit in completion resolve

* A couple more cleanups.

* Bug fixes for auto-complete.

* Add comment regarding conditional logic
This commit is contained in:
Karl Burtram
2016-10-24 18:11:49 +00:00
committed by GitHub
parent 2a688cb87f
commit 1d7e6e353f
5 changed files with 268 additions and 210 deletions

View File

@@ -3,6 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
// //
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@@ -31,89 +32,42 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private static Regex ValidSqlNameRegex = new Regex(@"^[\p{L}_][\p{L}\p{N}@$#_]{0,127}$"); private static Regex ValidSqlNameRegex = new Regex(@"^[\p{L}_][\p{L}\p{N}@$#_]{0,127}$");
private static CompletionItem[] emptyCompletionList = new CompletionItem[0];
private static readonly string[] DefaultCompletionText = new string[] private static readonly string[] DefaultCompletionText = new string[]
{ {
"absolute", "all",
"accent_sensitivity",
"action",
"activation",
"add",
"address",
"admin",
"after",
"aggregate",
"algorithm",
"allow_page_locks",
"allow_row_locks",
"allow_snapshot_isolation",
"alter", "alter",
"always", "and",
"ansi_null_default", "apply",
"ansi_nulls",
"ansi_padding",
"ansi_warnings",
"application",
"arithabort",
"as", "as",
"asc", "asc",
"assembly",
"asymmetric",
"at", "at",
"atomic",
"audit",
"authentication",
"authorization",
"auto",
"auto_close",
"auto_shrink",
"auto_update_statistics",
"auto_update_statistics_async",
"availability",
"backup", "backup",
"before",
"begin", "begin",
"binary", "binary",
"bit", "bit",
"block",
"break", "break",
"browse",
"bucket_count",
"bulk", "bulk",
"by", "by",
"call", "call",
"caller",
"card",
"cascade", "cascade",
"case", "case",
"catalog",
"catch", "catch",
"change_tracking",
"changes",
"char", "char",
"character", "character",
"check", "check",
"checkpoint", "checkpoint",
"close", "close",
"clustered", "clustered",
"collection",
"column", "column",
"column_encryption_key",
"columnstore", "columnstore",
"commit", "commit",
"compatibility_level",
"compress_all_row_groups",
"compression",
"compression_delay",
"compute",
"concat_null_yields_null",
"configuration",
"connect", "connect",
"constraint", "constraint",
"containstable",
"continue", "continue",
"create", "create",
"cube", "cross",
"current",
"current_date", "current_date",
"cursor", "cursor",
"cursor_close_on_commit", "cursor_close_on_commit",
@@ -122,45 +76,31 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"data_compression", "data_compression",
"database", "database",
"date", "date",
"date_correlation_optimization",
"datefirst",
"datetime", "datetime",
"datetime2", "datetime2",
"days", "days",
"db_chaining",
"dbcc", "dbcc",
"deallocate",
"dec", "dec",
"decimal", "decimal",
"declare", "declare",
"default", "default",
"delayed_durability",
"delete", "delete",
"deny", "deny",
"desc", "desc",
"description", "description",
"disable_broker",
"disabled", "disabled",
"disk", "disk",
"distinct", "distinct",
"distributed",
"double", "double",
"drop", "drop",
"drop_existing", "drop_existing",
"dump", "dump",
"durability",
"dynamic", "dynamic",
"else", "else",
"enable", "enable",
"encrypted", "encrypted",
"encryption_type",
"end", "end",
"end-exec", "end-exec",
"entry",
"errlvl",
"escape",
"event",
"except",
"exec", "exec",
"execute", "execute",
"exit", "exit",
@@ -171,20 +111,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"filegroup", "filegroup",
"filename", "filename",
"filestream", "filestream",
"fillfactor",
"filter", "filter",
"first", "first",
"float", "float",
"for", "for",
"foreign", "foreign",
"freetext",
"freetexttable",
"from", "from",
"full", "full",
"fullscan",
"fulltext",
"function", "function",
"generated",
"geography", "geography",
"get", "get",
"global", "global",
@@ -200,30 +134,26 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"holdlock", "holdlock",
"hours", "hours",
"identity", "identity",
"identity_insert",
"identitycol", "identitycol",
"if", "if",
"ignore_dup_key",
"image", "image",
"immediate", "immediate",
"include", "include",
"index", "index",
"inflectional", "inner",
"insensitive",
"insert", "insert",
"instead", "instead",
"int", "int",
"integer", "integer",
"integrated",
"intersect", "intersect",
"into", "into",
"isolation", "isolation",
"join",
"json", "json",
"key", "key",
"kill",
"language", "language",
"last", "last",
"legacy_cardinality_estimation", "left",
"level", "level",
"lineno", "lineno",
"load", "load",
@@ -232,16 +162,12 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"location", "location",
"login", "login",
"masked", "masked",
"master",
"maxdop", "maxdop",
"memory_optimized",
"merge", "merge",
"message", "message",
"modify", "modify",
"move", "move",
"multi_user",
"namespace", "namespace",
"national",
"native_compilation", "native_compilation",
"nchar", "nchar",
"next", "next",
@@ -252,8 +178,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"none", "none",
"norecompute", "norecompute",
"now", "now",
"null",
"numeric", "numeric",
"numeric_roundabort",
"object", "object",
"of", "of",
"off", "off",
@@ -261,21 +187,15 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"on", "on",
"online", "online",
"open", "open",
"opendatasource",
"openquery",
"openrowset", "openrowset",
"openxml", "openxml",
"option", "option",
"or",
"order", "order",
"out", "out",
"output", "output",
"over", "over",
"owner", "owner",
"pad_index",
"page",
"page_verify",
"parameter_sniffing",
"parameterization",
"partial", "partial",
"partition", "partition",
"password", "password",
@@ -286,7 +206,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"persisted", "persisted",
"plan", "plan",
"policy", "policy",
"population",
"precision", "precision",
"predicate", "predicate",
"primary", "primary",
@@ -295,7 +214,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"proc", "proc",
"procedure", "procedure",
"public", "public",
"query_optimizer_hotfixes",
"query_store", "query_store",
"quoted_identifier", "quoted_identifier",
"raiserror", "raiserror",
@@ -318,7 +236,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"relative", "relative",
"remove", "remove",
"reorganize", "reorganize",
"replication",
"required", "required",
"restart", "restart",
"restore", "restore",
@@ -328,7 +245,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"returns", "returns",
"revert", "revert",
"revoke", "revoke",
"role",
"rollback", "rollback",
"rollup", "rollup",
"row", "row",
@@ -344,11 +260,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"scroll", "scroll",
"secondary", "secondary",
"security", "security",
"securityaudit",
"select", "select",
"semantickeyphrasetable",
"semanticsimilaritydetailstable",
"semanticsimilaritytable",
"send", "send",
"sent", "sent",
"sequence", "sequence",
@@ -357,12 +269,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"set", "set",
"sets", "sets",
"setuser", "setuser",
"shutdown",
"simple", "simple",
"smallint", "smallint",
"smallmoney", "smallmoney",
"snapshot", "snapshot",
"sort_in_tempdb",
"sql", "sql",
"standard", "standard",
"start", "start",
@@ -374,20 +284,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"statistics_norecompute", "statistics_norecompute",
"status", "status",
"stopped", "stopped",
"supported",
"symmetric",
"sysname", "sysname",
"system", "system",
"system_time", "system_time",
"system_versioning",
"table", "table",
"tablesample",
"take", "take",
"target", "target",
"textimage_on",
"textsize",
"then", "then",
"thesaurus",
"throw", "throw",
"time", "time",
"timestamp", "timestamp",
@@ -398,14 +301,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"transaction", "transaction",
"trigger", "trigger",
"truncate", "truncate",
"trustworthy",
"try", "try",
"tsql", "tsql",
"type", "type",
"uncommitted",
"union", "union",
"unique", "unique",
"uniqueidentifier", "uniqueidentifier",
"unlimited",
"updatetext", "updatetext",
"use", "use",
"user", "user",
@@ -413,24 +315,32 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
"value", "value",
"values", "values",
"varchar", "varchar",
"varying",
"version", "version",
"view", "view",
"waitfor", "waitfor",
"weight",
"when", "when",
"where", "where",
"while", "while",
"with", "with",
"within", "within",
"within group",
"without", "without",
"writetext", "writetext",
"xact_abort", "xact_abort",
"xml", "xml",
"zone"
}; };
/// <summary>
/// Gets a static instance of an empty completion list to avoid
// unneeded memory allocations
/// </summary>
internal static CompletionItem[] EmptyCompletionList
{
get
{
return AutoCompleteHelper.emptyCompletionList;
}
}
/// <summary> /// <summary>
/// Gets or sets the current workspace service instance /// Gets or sets the current workspace service instance
/// Setter for internal testing purposes only /// Setter for internal testing purposes only
@@ -462,17 +372,47 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
int row, int row,
int startColumn, int startColumn,
int endColumn, int endColumn,
bool useLowerCase) bool useLowerCase,
string tokenText = null)
{ {
var completionItems = new CompletionItem[DefaultCompletionText.Length]; // determine how many default completion items there will be
for (int i = 0; i < DefaultCompletionText.Length; ++i) int listSize = DefaultCompletionText.Length;
if (!string.IsNullOrWhiteSpace(tokenText))
{ {
completionItems[i] = CreateDefaultCompletionItem( listSize = 0;
useLowerCase ? DefaultCompletionText[i].ToLower() : DefaultCompletionText[i].ToUpper(), foreach (var completionText in DefaultCompletionText)
row, {
startColumn, if (completionText.StartsWith(tokenText, StringComparison.OrdinalIgnoreCase))
endColumn); {
++listSize;
}
}
} }
// special case empty list to avoid unneed array allocations
if (listSize == 0)
{
return emptyCompletionList;
}
// build the default completion list
var completionItems = new CompletionItem[listSize];
int completionItemIndex = 0;
foreach (var completionText in DefaultCompletionText)
{
// add item to list if the tokenText is null (meaning return whole list)
// or if the completion item begins with the tokenText
if (string.IsNullOrWhiteSpace(tokenText) || completionText.StartsWith(tokenText, StringComparison.OrdinalIgnoreCase))
{
completionItems[completionItemIndex] = CreateDefaultCompletionItem(
useLowerCase ? completionText.ToLower() : completionText.ToUpper(),
row,
startColumn,
endColumn);
++completionItemIndex;
}
}
return completionItems; return completionItems;
} }
@@ -560,7 +500,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
int startColumn, int startColumn,
int endColumn) int endColumn)
{ {
List<CompletionItem> completions = new List<CompletionItem>(); List<CompletionItem> completions = new List<CompletionItem>();
foreach (var autoCompleteItem in suggestions) foreach (var autoCompleteItem in suggestions)
@@ -596,8 +535,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
completions.Add(CreateCompletionItem(autoCompleteItem.Title, autoCompleteItem.Title, insertText, kind, row, startColumn, endColumn)); completions.Add(CreateCompletionItem(autoCompleteItem.Title, autoCompleteItem.Title, insertText, kind, row, startColumn, endColumn));
} }
return completions.ToArray(); return completions.ToArray();
} }
@@ -636,6 +573,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
QueueItem queueItem = bindingQueue.QueueBindingOperation( QueueItem queueItem = bindingQueue.QueueBindingOperation(
key: scriptInfo.ConnectionKey, key: scriptInfo.ConnectionKey,
bindingTimeout: AutoCompleteHelper.PrepopulateBindTimeout, bindingTimeout: AutoCompleteHelper.PrepopulateBindTimeout,
waitForLockTimeout: AutoCompleteHelper.PrepopulateBindTimeout,
bindOperation: (bindingContext, cancelToken) => bindOperation: (bindingContext, cancelToken) =>
{ {
// parse a simple statement that returns common metadata // parse a simple statement that returns common metadata

View File

@@ -61,7 +61,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
string key, string key,
Func<IBindingContext, CancellationToken, object> bindOperation, Func<IBindingContext, CancellationToken, object> bindOperation,
Func<IBindingContext, object> timeoutOperation = null, Func<IBindingContext, object> timeoutOperation = null,
int? bindingTimeout = null) int? bindingTimeout = null,
int? waitForLockTimeout = null)
{ {
// don't add null operations to the binding queue // don't add null operations to the binding queue
if (bindOperation == null) if (bindOperation == null)
@@ -74,7 +75,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
Key = key, Key = key,
BindOperation = bindOperation, BindOperation = bindOperation,
TimeoutOperation = timeoutOperation, TimeoutOperation = timeoutOperation,
BindingTimeout = bindingTimeout BindingTimeout = bindingTimeout,
WaitForLockTimeout = waitForLockTimeout
}; };
lock (this.bindingQueueLock) lock (this.bindingQueueLock)
@@ -198,7 +200,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
int bindTimeout = queueItem.BindingTimeout ?? bindingContext.BindingTimeout; int bindTimeout = queueItem.BindingTimeout ?? bindingContext.BindingTimeout;
// handle the case a previous binding operation is still running // handle the case a previous binding operation is still running
if (!bindingContext.BindingLock.WaitOne(0)) if (!bindingContext.BindingLock.WaitOne(queueItem.WaitForLockTimeout ?? 0))
{ {
queueItem.Result = queueItem.TimeoutOperation != null queueItem.Result = queueItem.TimeoutOperation != null
? queueItem.TimeoutOperation(bindingContext) ? queueItem.TimeoutOperation(bindingContext)
@@ -266,8 +268,15 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
finally finally
{ {
// reset the item queued event since we've processed all the pending items lock (this.bindingQueueLock)
this.itemQueuedEvent.Reset(); {
// verify the binding queue is still empty
if (this.bindingQueue.Count == 0)
{
// reset the item queued event since we've processed all the pending items
this.itemQueuedEvent.Reset();
}
}
} }
} }
} }

View File

@@ -583,28 +583,45 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <param name="completionItem"></param> /// <param name="completionItem"></param>
internal CompletionItem ResolveCompletionItem(CompletionItem completionItem) internal CompletionItem ResolveCompletionItem(CompletionItem completionItem)
{ {
try var scriptParseInfo = LanguageService.Instance.currentCompletionParseInfo;
if (scriptParseInfo != null && scriptParseInfo.CurrentSuggestions != null)
{ {
var scriptParseInfo = LanguageService.Instance.currentCompletionParseInfo; if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
if (scriptParseInfo != null && scriptParseInfo.CurrentSuggestions != null)
{ {
foreach (var suggestion in scriptParseInfo.CurrentSuggestions) try
{ {
if (string.Equals(suggestion.Title, completionItem.Label)) QueueItem queueItem = this.BindingQueue.QueueBindingOperation(
{ key: scriptParseInfo.ConnectionKey,
completionItem.Detail = suggestion.DatabaseQualifiedName; bindingTimeout: LanguageService.BindingTimeout,
completionItem.Documentation = suggestion.Description; bindOperation: (bindingContext, cancelToken) =>
break; {
} foreach (var suggestion in scriptParseInfo.CurrentSuggestions)
{
if (string.Equals(suggestion.Title, completionItem.Label))
{
completionItem.Detail = suggestion.DatabaseQualifiedName;
completionItem.Documentation = suggestion.Description;
break;
}
}
return completionItem;
});
queueItem.ItemProcessed.WaitOne();
}
catch (Exception ex)
{
// if any exceptions are raised looking up extended completion metadata
// then just return the original completion item
Logger.Write(LogLevel.Error, "Exeception in ResolveCompletionItem " + ex.ToString());
}
finally
{
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
} }
} }
} }
catch (Exception ex)
{
// if any exceptions are raised looking up extended completion metadata
// then just return the original completion item
Logger.Write(LogLevel.Error, "Exeception in ResolveCompletionItem " + ex.ToString());
}
return completionItem; return completionItem;
} }
@@ -674,27 +691,32 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ScriptFile scriptFile, ScriptFile scriptFile,
ConnectionInfo connInfo) ConnectionInfo connInfo)
{ {
// initialize some state to parse and bind the current script file
this.currentCompletionParseInfo = null;
CompletionItem[] resultCompletionItems = null;
string filePath = textDocumentPosition.TextDocument.Uri; string filePath = textDocumentPosition.TextDocument.Uri;
int startLine = textDocumentPosition.Position.Line; int startLine = textDocumentPosition.Position.Line;
int parserLine = textDocumentPosition.Position.Line + 1;
int startColumn = TextUtilities.PositionOfPrevDelimeter( int startColumn = TextUtilities.PositionOfPrevDelimeter(
scriptFile.Contents, scriptFile.Contents,
textDocumentPosition.Position.Line, textDocumentPosition.Position.Line,
textDocumentPosition.Position.Character); textDocumentPosition.Position.Character);
int endColumn = textDocumentPosition.Position.Character; int endColumn = TextUtilities.PositionOfNextDelimeter(
scriptFile.Contents,
textDocumentPosition.Position.Line,
textDocumentPosition.Position.Character);
int parserColumn = textDocumentPosition.Position.Character + 1;
bool useLowerCaseSuggestions = this.CurrentSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value; bool useLowerCaseSuggestions = this.CurrentSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value;
this.currentCompletionParseInfo = null;
CompletionItem[] defaultCompletionItems = AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
CompletionItem[] resultCompletionItems = defaultCompletionItems;
CompletionItem[] emptyCompletionItems = new CompletionItem[0];
int line = textDocumentPosition.Position.Line + 1;
int column = textDocumentPosition.Position.Character + 1;
// get the current script parse info object // get the current script parse info object
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri); ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
if (connInfo == null || scriptParseInfo == null) if (scriptParseInfo == null)
{ {
return defaultCompletionItems; return AutoCompleteHelper.GetDefaultCompletionItems(
startLine,
startColumn,
endColumn,
useLowerCaseSuggestions);
} }
// reparse and bind the SQL statement if needed // reparse and bind the SQL statement if needed
@@ -703,12 +725,21 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ParseAndBind(scriptFile, connInfo); ParseAndBind(scriptFile, connInfo);
} }
// if the parse failed then return the default list
if (scriptParseInfo.ParseResult == null) if (scriptParseInfo.ParseResult == null)
{ {
return defaultCompletionItems; return AutoCompleteHelper.GetDefaultCompletionItems(
startLine,
startColumn,
endColumn,
useLowerCaseSuggestions);
} }
Token token = GetToken(scriptParseInfo, line, column);
// need to adjust line & column for base-1 parser indices
Token token = GetToken(scriptParseInfo, parserLine, parserColumn);
string tokenText = token != null ? token.Text : null;
// check if the file is connected and the file lock is available
if (scriptParseInfo.IsConnected && Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock)) if (scriptParseInfo.IsConnected && Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
{ {
try try
@@ -719,33 +750,35 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
bindingTimeout: LanguageService.BindingTimeout, bindingTimeout: LanguageService.BindingTimeout,
bindOperation: (bindingContext, cancelToken) => bindOperation: (bindingContext, cancelToken) =>
{ {
CompletionItem[] completions = null;
// get the completion list from SQL Parser // get the completion list from SQL Parser
scriptParseInfo.CurrentSuggestions = Resolver.FindCompletions( scriptParseInfo.CurrentSuggestions = Resolver.FindCompletions(
scriptParseInfo.ParseResult, scriptParseInfo.ParseResult,
line, parserLine,
column, parserColumn,
bindingContext.MetadataDisplayInfoProvider); bindingContext.MetadataDisplayInfoProvider);
// cache the current script parse info object to resolve completions later // cache the current script parse info object to resolve completions later
this.currentCompletionParseInfo = scriptParseInfo; this.currentCompletionParseInfo = scriptParseInfo;
// convert the suggestion list to the VS Code format // convert the suggestion list to the VS Code format
completions = AutoCompleteHelper.ConvertDeclarationsToCompletionItems( return AutoCompleteHelper.ConvertDeclarationsToCompletionItems(
scriptParseInfo.CurrentSuggestions, scriptParseInfo.CurrentSuggestions,
startLine, startLine,
startColumn, startColumn,
endColumn endColumn);
);
return completions;
}, },
timeoutOperation: (bindingContext) => timeoutOperation: (bindingContext) =>
{ {
return defaultCompletionItems; // return the default list if the connected bind fails
return AutoCompleteHelper.GetDefaultCompletionItems(
startLine,
startColumn,
endColumn,
useLowerCaseSuggestions,
tokenText);
}); });
// wait for the queue item
queueItem.ItemProcessed.WaitOne(); queueItem.ItemProcessed.WaitOne();
var completionItems = queueItem.GetResultAsT<CompletionItem[]>(); var completionItems = queueItem.GetResultAsT<CompletionItem[]>();
@@ -755,7 +788,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
} }
else if (!ShouldShowCompletionList(token)) else if (!ShouldShowCompletionList(token))
{ {
resultCompletionItems = emptyCompletionItems; resultCompletionItems = AutoCompleteHelper.EmptyCompletionList;
} }
} }
finally finally
@@ -763,7 +796,18 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
Monitor.Exit(scriptParseInfo.BuildingMetadataLock); Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
} }
} }
//resultCompletionItems = AutoCompleteHelper.AddTokenToItems(resultCompletionItems, token, startLine, startColumn, endColumn);
// if there are no completions then provide the default list
if (resultCompletionItems == null)
{
resultCompletionItems = AutoCompleteHelper.GetDefaultCompletionItems(
startLine,
startColumn,
endColumn,
useLowerCaseSuggestions,
tokenText);
}
return resultCompletionItems; return resultCompletionItems;
} }
@@ -774,7 +818,16 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
var tokenIndex = scriptParseInfo.ParseResult.Script.TokenManager.FindToken(startLine, startColumn); var tokenIndex = scriptParseInfo.ParseResult.Script.TokenManager.FindToken(startLine, startColumn);
if (tokenIndex >= 0) if (tokenIndex >= 0)
{ {
return scriptParseInfo.ParseResult.Script.Tokens.ToList()[tokenIndex]; // return the current token
int currentIndex = 0;
foreach (var token in scriptParseInfo.ParseResult.Script.Tokens)
{
if (currentIndex == tokenIndex)
{
return token;
}
++currentIndex;
}
} }
} }
return null; return null;
@@ -930,6 +983,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// Get the requested files // Get the requested files
foreach (ScriptFile scriptFile in filesToAnalyze) foreach (ScriptFile scriptFile in filesToAnalyze)
{ {
if (IsPreviewWindow(scriptFile))
{
continue;
}
Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath); Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath);
ScriptFileMarker[] semanticMarkers = GetSemanticMarkers(scriptFile); ScriptFileMarker[] semanticMarkers = GetSemanticMarkers(scriptFile);
Logger.Write(LogLevel.Verbose, "Analysis complete."); Logger.Write(LogLevel.Verbose, "Analysis complete.");

View File

@@ -51,6 +51,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// </summary> /// </summary>
public int? BindingTimeout { get; set; } public int? BindingTimeout { get; set; }
/// <summary>
/// Gets or sets the timeout for how long to wait for the binding lock
/// </summary>
public int? WaitForLockTimeout { get; set; }
/// <summary> /// <summary>
/// Converts the result of the execution to type T /// Converts the result of the execution to type T
/// </summary> /// </summary>

View File

@@ -7,6 +7,33 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
{ {
public static class TextUtilities public static class TextUtilities
{ {
/// <summary>
/// Find the position of the cursor in the SQL script content buffer and return previous new line position
/// </summary>
/// <param name="sql"></param>
/// <param name="startRow"></param>
/// <param name="startColumn"></param>
/// <param name="prevNewLine"></param>
public static int PositionOfCursor(string sql, int startRow, int startColumn, out int prevNewLine)
{
prevNewLine = 0;
if (string.IsNullOrWhiteSpace(sql))
{
return 1;
}
for (int i = 0; i < startRow; ++i)
{
while (prevNewLine < sql.Length && sql[prevNewLine] != '\n')
{
++prevNewLine;
}
++prevNewLine;
}
return startColumn + prevNewLine;
}
/// <summary> /// <summary>
/// Find the position of the previous delimeter for autocomplete token replacement. /// Find the position of the previous delimeter for autocomplete token replacement.
/// SQL Parser may have similar functionality in which case we'll delete this method. /// SQL Parser may have similar functionality in which case we'll delete this method.
@@ -14,49 +41,70 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
/// <param name="sql"></param> /// <param name="sql"></param>
/// <param name="startRow"></param> /// <param name="startRow"></param>
/// <param name="startColumn"></param> /// <param name="startColumn"></param>
/// <returns></returns> /// <param name="tokenText"></param>
public static int PositionOfPrevDelimeter(string sql, int startRow, int startColumn) public static int PositionOfPrevDelimeter(string sql, int startRow, int startColumn)
{ {
if (string.IsNullOrWhiteSpace(sql)) int prevNewLine;
{ int delimeterPos = PositionOfCursor(sql, startRow, startColumn, out prevNewLine);
return 1;
}
int prevLineColumns = 0; if (delimeterPos - 1 < sql.Length)
for (int i = 0; i < startRow; ++i)
{ {
while (sql[prevLineColumns] != '\n' && prevLineColumns < sql.Length) while (--delimeterPos >= prevNewLine)
{ {
++prevLineColumns; if (IsCharacterDelimeter(sql[delimeterPos]))
}
++prevLineColumns;
}
startColumn += prevLineColumns;
if (startColumn - 1 < sql.Length)
{
while (--startColumn >= prevLineColumns)
{
if (sql[startColumn] == ' '
|| sql[startColumn] == '\t'
|| sql[startColumn] == '\n'
|| sql[startColumn] == '.'
|| sql[startColumn] == '+'
|| sql[startColumn] == '-'
|| sql[startColumn] == '*'
|| sql[startColumn] == '>'
|| sql[startColumn] == '<'
|| sql[startColumn] == '='
|| sql[startColumn] == '/'
|| sql[startColumn] == '%')
{ {
break; break;
} }
} }
delimeterPos = delimeterPos + 1 - prevNewLine;
} }
return startColumn + 1 - prevLineColumns; return delimeterPos;
}
/// <summary>
/// Find the position of the next delimeter for autocomplete token replacement.
/// </summary>
/// <param name="sql"></param>
/// <param name="startRow"></param>
/// <param name="startColumn"></param>
public static int PositionOfNextDelimeter(string sql, int startRow, int startColumn)
{
int prevNewLine;
int delimeterPos = PositionOfCursor(sql, startRow, startColumn, out prevNewLine);
while (delimeterPos < sql.Length)
{
if (IsCharacterDelimeter(sql[delimeterPos]))
{
break;
}
++delimeterPos;
}
return delimeterPos - prevNewLine;
}
/// <summary>
/// Determine if the character is a SQL token delimiter
/// </summary>
/// <param name="ch"></param>
private static bool IsCharacterDelimeter(char ch)
{
return ch == ' '
|| ch == '\t'
|| ch == '\n'
|| ch == '.'
|| ch == '+'
|| ch == '-'
|| ch == '*'
|| ch == '>'
|| ch == '<'
|| ch == '='
|| ch == '/'
|| ch == '%'
|| ch == ',';
} }
} }
} }