mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 18:47:57 -05:00
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:
@@ -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)
|
||||||
|
{
|
||||||
|
if (completionText.StartsWith(tokenText, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
++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,
|
row,
|
||||||
startColumn,
|
startColumn,
|
||||||
endColumn);
|
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
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -265,6 +267,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
lock (this.bindingQueueLock)
|
||||||
|
{
|
||||||
|
// 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
|
// reset the item queued event since we've processed all the pending items
|
||||||
this.itemQueuedEvent.Reset();
|
this.itemQueuedEvent.Reset();
|
||||||
@@ -273,3 +280,5 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -582,11 +582,18 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="completionItem"></param>
|
/// <param name="completionItem"></param>
|
||||||
internal CompletionItem ResolveCompletionItem(CompletionItem completionItem)
|
internal CompletionItem ResolveCompletionItem(CompletionItem completionItem)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var scriptParseInfo = LanguageService.Instance.currentCompletionParseInfo;
|
var scriptParseInfo = LanguageService.Instance.currentCompletionParseInfo;
|
||||||
if (scriptParseInfo != null && scriptParseInfo.CurrentSuggestions != null)
|
if (scriptParseInfo != null && scriptParseInfo.CurrentSuggestions != null)
|
||||||
|
{
|
||||||
|
if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QueueItem queueItem = this.BindingQueue.QueueBindingOperation(
|
||||||
|
key: scriptParseInfo.ConnectionKey,
|
||||||
|
bindingTimeout: LanguageService.BindingTimeout,
|
||||||
|
bindOperation: (bindingContext, cancelToken) =>
|
||||||
{
|
{
|
||||||
foreach (var suggestion in scriptParseInfo.CurrentSuggestions)
|
foreach (var suggestion in scriptParseInfo.CurrentSuggestions)
|
||||||
{
|
{
|
||||||
@@ -597,7 +604,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return completionItem;
|
||||||
|
});
|
||||||
|
|
||||||
|
queueItem.ItemProcessed.WaitOne();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -605,6 +615,13 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
// then just return the original completion item
|
// then just return the original completion item
|
||||||
Logger.Write(LogLevel.Error, "Exeception in ResolveCompletionItem " + ex.ToString());
|
Logger.Write(LogLevel.Error, "Exeception in ResolveCompletionItem " + ex.ToString());
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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.");
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 == ',';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user