Fixed autocomplete bugs (#110)

Autocomplete for items with special characters doesn't add [ ]
Autocomplete default list shows when it shouldn't..like in comments or literals
This commit is contained in:
Leila Lali
2016-10-21 15:03:48 -07:00
committed by GitHub
parent f35b9fda27
commit b3d793dc85
3 changed files with 140 additions and 45 deletions

View File

@@ -157,7 +157,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting
CompletionProvider = new CompletionOptions
{
ResolveProvider = true,
TriggerCharacters = new string[] { ".", "-", ":", "\\", ",", " " }
TriggerCharacters = new string[] { ".", "-", ":", "\\", "," }
},
SignatureHelpProvider = new SignatureHelpOptions
{

View File

@@ -4,6 +4,9 @@
//
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
@@ -26,6 +29,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private static WorkspaceService<SqlToolsSettings> workspaceServiceInstance;
private static Regex ValidSqlNameRegex = new Regex(@"^[\p{L}_][\p{L}\p{N}@$#_]{0,127}$");
private static readonly string[] DefaultCompletionText = new string[]
{
"absolute",
@@ -484,14 +489,44 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
int startColumn,
int endColumn)
{
return new CompletionItem()
return CreateCompletionItem(label, label + " keyword", label, CompletionItemKind.Keyword, row, startColumn, endColumn);
}
internal static CompletionItem[] AddTokenToItems(CompletionItem[] currentList, Token token, int row,
int startColumn,
int endColumn)
{
if (currentList != null &&
token != null && !string.IsNullOrWhiteSpace(token.Text) &&
token.Text.All(ch => char.IsLetter(ch)) &&
currentList.All(x => string.Compare(x.Label, token.Text, true) != 0
))
{
var list = currentList.ToList();
list.Insert(0, CreateCompletionItem(token.Text, token.Text, token.Text, CompletionItemKind.Text, row, startColumn, endColumn));
return list.ToArray();
}
return currentList;
}
private static CompletionItem CreateCompletionItem(
string label,
string detail,
string insertText,
CompletionItemKind kind,
int row,
int startColumn,
int endColumn)
{
CompletionItem item = new CompletionItem()
{
Label = label,
Kind = CompletionItemKind.Keyword,
Detail = label + " keyword",
Kind = kind,
Detail = detail,
InsertText = insertText,
TextEdit = new TextEdit
{
NewText = label,
NewText = insertText,
Range = new Range
{
Start = new Position
@@ -507,6 +542,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
}
}
};
return item;
}
/// <summary>
@@ -523,38 +560,56 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
int startColumn,
int endColumn)
{
List<CompletionItem> completions = new List<CompletionItem>();
foreach (var autoCompleteItem in suggestions)
{
// convert the completion item candidates into CompletionItems
completions.Add(new CompletionItem()
string insertText = GetCompletionItemInsertName(autoCompleteItem);
CompletionItemKind kind = CompletionItemKind.Variable;
switch (autoCompleteItem.Type)
{
Label = autoCompleteItem.Title,
Kind = CompletionItemKind.Variable,
Detail = autoCompleteItem.Title,
TextEdit = new TextEdit
{
NewText = autoCompleteItem.Title,
Range = new Range
{
Start = new Position
{
Line = row,
Character = startColumn
},
End = new Position
{
Line = row,
Character = endColumn
}
}
}
});
case DeclarationType.Schema:
kind = CompletionItemKind.Module;
break;
case DeclarationType.Column:
kind = CompletionItemKind.Field;
break;
case DeclarationType.Table:
kind = CompletionItemKind.Method;
break;
case DeclarationType.Database:
kind = CompletionItemKind.File;
break;
case DeclarationType.Server:
kind = CompletionItemKind.Value;
break;
default:
kind = CompletionItemKind.Variable;
break;
}
// convert the completion item candidates into CompletionItems
completions.Add(CreateCompletionItem(autoCompleteItem.Title, autoCompleteItem.Title, insertText, kind, row, startColumn, endColumn));
}
return completions.ToArray();
}
private static string GetCompletionItemInsertName(Declaration autoCompleteItem)
{
string insertText = autoCompleteItem.Title;
if (!string.IsNullOrEmpty(autoCompleteItem.Title) && !ValidSqlNameRegex.IsMatch(autoCompleteItem.Title))
{
insertText = string.Format(CultureInfo.InvariantCulture, "[{0}]", autoCompleteItem.Title);
}
return insertText;
}
/// <summary>
/// Preinitialize the parser and binder with common metadata.
/// This should front load the long binding wait to the time the

View File

@@ -264,10 +264,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
var completionItems = Instance.GetCompletionItems(
textDocumentPosition, scriptFile, connInfo);
await requestContext.SendResult(completionItems);
await requestContext.SendResult(completionItems);
}
}
}
/// <summary>
/// Handle the resolve completion request event to provide additional
@@ -686,12 +686,17 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
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
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
if (connInfo == null || scriptParseInfo == null)
{
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
return defaultCompletionItems;
}
// reparse and bind the SQL statement if needed
@@ -702,8 +707,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
if (scriptParseInfo.ParseResult == null)
{
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
return defaultCompletionItems;
}
Token token = GetToken(scriptParseInfo, line, column);
if (scriptParseInfo.IsConnected
&& Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock, LanguageService.FindCompletionStartTimeout))
@@ -721,42 +727,76 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// get the completion list from SQL Parser
scriptParseInfo.CurrentSuggestions = Resolver.FindCompletions(
scriptParseInfo.ParseResult,
textDocumentPosition.Position.Line + 1,
textDocumentPosition.Position.Character + 1,
line,
column,
bindingContext.MetadataDisplayInfoProvider);
// cache the current script parse info object to resolve completions later
this.currentCompletionParseInfo = scriptParseInfo;
// convert the suggestion list to the VS Code format
completions = AutoCompleteHelper.ConvertDeclarationsToCompletionItems(
scriptParseInfo.CurrentSuggestions,
startLine,
startColumn,
endColumn);
endColumn
);
return completions;
},
timeoutOperation: (bindingContext) =>
{
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
return defaultCompletionItems;
});
queueItem.ItemProcessed.WaitOne();
var completionItems = queueItem.GetResultAsT<CompletionItem[]>();
var completionItems = queueItem.GetResultAsT<CompletionItem[]>();
if (completionItems != null && completionItems.Length > 0)
{
return completionItems;
}
resultCompletionItems = completionItems;
}
else if (!ShouldShowCompletionList(token))
{
resultCompletionItems = emptyCompletionItems;
}
}
finally
{
{
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
}
}
}
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
//resultCompletionItems = AutoCompleteHelper.AddTokenToItems(resultCompletionItems, token, startLine, startColumn, endColumn);
return resultCompletionItems;
}
private static Token GetToken(ScriptParseInfo scriptParseInfo, int startLine, int startColumn)
{
if (scriptParseInfo != null && scriptParseInfo.ParseResult != null && scriptParseInfo.ParseResult.Script != null && scriptParseInfo.ParseResult.Script.Tokens != null)
{
var tokenIndex = scriptParseInfo.ParseResult.Script.TokenManager.FindToken(startLine, startColumn);
if (tokenIndex >= 0)
{
return scriptParseInfo.ParseResult.Script.Tokens.ToList()[tokenIndex];
}
}
return null;
}
private static bool ShouldShowCompletionList(Token token)
{
bool result = true;
if (token != null)
{
switch (token.Id)
{
case (int)Tokens.LEX_MULTILINE_COMMENT:
case (int)Tokens.LEX_END_OF_LINE_COMMENT:
result = false;
break;
}
}
return result;
}
#endregion