Fix auto-complete inserting brackets around function names (#895)

* Fix reserved words not to be bracket quoted

* wip

* More fixes

* Better name

* Format files and update test
This commit is contained in:
Charles Gagnon
2019-11-26 17:16:05 -08:00
committed by GitHub
parent 4f749c73cc
commit 314d01739d
3 changed files with 87 additions and 315 deletions

View File

@@ -28,7 +28,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
private static CompletionItem[] emptyCompletionList = new CompletionItem[0];
private static readonly string[] DefaultCompletionText = new string[]
public static readonly string[] DefaultCompletionText = new string[]
{
"abs",
"acos",
@@ -488,8 +488,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// </summary>
internal static bool IsReservedWord(string text)
{
int pos = Array.IndexOf(DefaultCompletionText, text.ToLower());
return pos > -1;
return DefaultCompletionText.Contains(text, StringComparer.InvariantCultureIgnoreCase);
}
/// <summary>

View File

@@ -19,9 +19,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
public class SqlCompletionItem
{
private static Regex ValidSqlNameRegex = new Regex(@"^[\p{L}_@#][\p{L}\p{N}@$#_]{0,127}$");
private static DelimitedIdentifier BracketedIdentifiers = new DelimitedIdentifier { Start = "[", End = "]"};
private static DelimitedIdentifier BracketedIdentifiers = new DelimitedIdentifier { Start = "[", End = "]" };
private static DelimitedIdentifier FunctionPostfix = new DelimitedIdentifier { Start = "", End = "()" };
private static DelimitedIdentifier[] DelimitedIdentifiers =
new DelimitedIdentifier[] { BracketedIdentifiers, new DelimitedIdentifier {Start = "\"", End = "\"" } };
new DelimitedIdentifier[] { BracketedIdentifiers, new DelimitedIdentifier { Start = "\"", End = "\"" } };
/// <summary>
/// Create new instance given the SQL parser declaration
@@ -48,14 +49,39 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
private void Init()
{
InsertText = DeclarationTitle;
DelimitedIdentifier delimitedIdentifier = GetDelimitedIdentifier(TokenText);
Label = DeclarationTitle;
DelimitedIdentifier delimitedIdentifier = GetDelimitedIdentifier(TokenText);
if (delimitedIdentifier == null && !string.IsNullOrEmpty(DeclarationTitle) &&
(!ValidSqlNameRegex.IsMatch(DeclarationTitle) || AutoCompleteHelper.IsReservedWord(InsertText)))
// If we're not already going to quote this then handle special cases for various
// DeclarationTypes
if (delimitedIdentifier == null && !string.IsNullOrEmpty(DeclarationTitle))
{
InsertText = WithDelimitedIdentifier(BracketedIdentifiers, DeclarationTitle);
switch (this.DeclarationType)
{
case DeclarationType.Server:
case DeclarationType.Database:
case DeclarationType.Table:
case DeclarationType.Column:
case DeclarationType.View:
case DeclarationType.Schema:
// Only quote if we need to - i.e. if this isn't a valid name (has characters that need escaping such as [)
// or if it's a reserved word
if (!ValidSqlNameRegex.IsMatch(DeclarationTitle) || AutoCompleteHelper.IsReservedWord(InsertText))
{
InsertText = WithDelimitedIdentifier(BracketedIdentifiers, DeclarationTitle);
}
break;
case DeclarationType.BuiltInFunction:
case DeclarationType.ScalarValuedFunction:
case DeclarationType.TableValuedFunction:
// Functions we add on the () at the end since they'll always have them
InsertText = WithDelimitedIdentifier(FunctionPostfix, DeclarationTitle);
break;
}
}
// If the user typed a token that starts with a delimiter then always quote both
// the display label and text to be inserted
if (delimitedIdentifier != null)
{
Label = WithDelimitedIdentifier(delimitedIdentifier, Label);
@@ -184,7 +210,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
private bool HasDelimitedIdentifier(DelimitedIdentifier delimiteIidentifier, string text)
{
return text != null && delimiteIidentifier != null && text.StartsWith(delimiteIidentifier.Start)
return text != null && delimiteIidentifier != null && text.StartsWith(delimiteIidentifier.Start)
&& text.EndsWith(delimiteIidentifier.End);
}
@@ -193,11 +219,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
return text != null ? DelimitedIdentifiers.FirstOrDefault(x => text.StartsWith(x.Start)) : null;
}
private string WithDelimitedIdentifier(DelimitedIdentifier delimiteIidentifier, string text)
private string WithDelimitedIdentifier(DelimitedIdentifier delimitedIdentifier, string text)
{
if (!HasDelimitedIdentifier(delimiteIidentifier, text))
if (!HasDelimitedIdentifier(delimitedIdentifier, text))
{
return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", delimiteIidentifier.Start, text, delimiteIidentifier.End);
return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", delimitedIdentifier.Start, text, delimitedIdentifier.End);
}
else
{