mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 18:47:57 -05:00
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:
@@ -157,7 +157,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting
|
|||||||
CompletionProvider = new CompletionOptions
|
CompletionProvider = new CompletionOptions
|
||||||
{
|
{
|
||||||
ResolveProvider = true,
|
ResolveProvider = true,
|
||||||
TriggerCharacters = new string[] { ".", "-", ":", "\\", ",", " " }
|
TriggerCharacters = new string[] { ".", "-", ":", "\\", "," }
|
||||||
},
|
},
|
||||||
SignatureHelpProvider = new SignatureHelpOptions
|
SignatureHelpProvider = new SignatureHelpOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
using Microsoft.SqlServer.Management.SqlParser.Binder;
|
||||||
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
|
||||||
@@ -26,6 +29,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
private static WorkspaceService<SqlToolsSettings> workspaceServiceInstance;
|
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[]
|
private static readonly string[] DefaultCompletionText = new string[]
|
||||||
{
|
{
|
||||||
"absolute",
|
"absolute",
|
||||||
@@ -484,14 +489,44 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
int startColumn,
|
int startColumn,
|
||||||
int endColumn)
|
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,
|
Label = label,
|
||||||
Kind = CompletionItemKind.Keyword,
|
Kind = kind,
|
||||||
Detail = label + " keyword",
|
Detail = detail,
|
||||||
|
InsertText = insertText,
|
||||||
TextEdit = new TextEdit
|
TextEdit = new TextEdit
|
||||||
{
|
{
|
||||||
NewText = label,
|
NewText = insertText,
|
||||||
Range = new Range
|
Range = new Range
|
||||||
{
|
{
|
||||||
Start = new Position
|
Start = new Position
|
||||||
@@ -507,6 +542,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -523,38 +560,56 @@ 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)
|
||||||
{
|
{
|
||||||
// convert the completion item candidates into CompletionItems
|
string insertText = GetCompletionItemInsertName(autoCompleteItem);
|
||||||
completions.Add(new CompletionItem()
|
CompletionItemKind kind = CompletionItemKind.Variable;
|
||||||
|
switch (autoCompleteItem.Type)
|
||||||
{
|
{
|
||||||
Label = autoCompleteItem.Title,
|
case DeclarationType.Schema:
|
||||||
Kind = CompletionItemKind.Variable,
|
kind = CompletionItemKind.Module;
|
||||||
Detail = autoCompleteItem.Title,
|
break;
|
||||||
TextEdit = new TextEdit
|
case DeclarationType.Column:
|
||||||
{
|
kind = CompletionItemKind.Field;
|
||||||
NewText = autoCompleteItem.Title,
|
break;
|
||||||
Range = new Range
|
case DeclarationType.Table:
|
||||||
{
|
kind = CompletionItemKind.Method;
|
||||||
Start = new Position
|
break;
|
||||||
{
|
case DeclarationType.Database:
|
||||||
Line = row,
|
kind = CompletionItemKind.File;
|
||||||
Character = startColumn
|
break;
|
||||||
},
|
case DeclarationType.Server:
|
||||||
End = new Position
|
kind = CompletionItemKind.Value;
|
||||||
{
|
break;
|
||||||
Line = row,
|
default:
|
||||||
Character = endColumn
|
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();
|
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>
|
/// <summary>
|
||||||
/// Preinitialize the parser and binder with common metadata.
|
/// Preinitialize the parser and binder with common metadata.
|
||||||
/// This should front load the long binding wait to the time the
|
/// This should front load the long binding wait to the time the
|
||||||
|
|||||||
@@ -264,10 +264,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
var completionItems = Instance.GetCompletionItems(
|
var completionItems = Instance.GetCompletionItems(
|
||||||
textDocumentPosition, scriptFile, connInfo);
|
textDocumentPosition, scriptFile, connInfo);
|
||||||
|
|
||||||
await requestContext.SendResult(completionItems);
|
await requestContext.SendResult(completionItems);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle the resolve completion request event to provide additional
|
/// 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;
|
bool useLowerCaseSuggestions = this.CurrentSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value;
|
||||||
|
|
||||||
this.currentCompletionParseInfo = null;
|
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 (connInfo == null || scriptParseInfo == null)
|
||||||
{
|
{
|
||||||
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
|
return defaultCompletionItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reparse and bind the SQL statement if needed
|
// reparse and bind the SQL statement if needed
|
||||||
@@ -702,8 +707,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
if (scriptParseInfo.ParseResult == null)
|
if (scriptParseInfo.ParseResult == null)
|
||||||
{
|
{
|
||||||
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
|
return defaultCompletionItems;
|
||||||
}
|
}
|
||||||
|
Token token = GetToken(scriptParseInfo, line, column);
|
||||||
|
|
||||||
if (scriptParseInfo.IsConnected
|
if (scriptParseInfo.IsConnected
|
||||||
&& Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock, LanguageService.FindCompletionStartTimeout))
|
&& Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock, LanguageService.FindCompletionStartTimeout))
|
||||||
@@ -721,42 +727,76 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
// 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,
|
||||||
textDocumentPosition.Position.Line + 1,
|
line,
|
||||||
textDocumentPosition.Position.Character + 1,
|
column,
|
||||||
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(
|
completions = AutoCompleteHelper.ConvertDeclarationsToCompletionItems(
|
||||||
scriptParseInfo.CurrentSuggestions,
|
scriptParseInfo.CurrentSuggestions,
|
||||||
startLine,
|
startLine,
|
||||||
startColumn,
|
startColumn,
|
||||||
endColumn);
|
endColumn
|
||||||
|
);
|
||||||
|
|
||||||
return completions;
|
return completions;
|
||||||
},
|
},
|
||||||
timeoutOperation: (bindingContext) =>
|
timeoutOperation: (bindingContext) =>
|
||||||
{
|
{
|
||||||
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
|
return defaultCompletionItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
queueItem.ItemProcessed.WaitOne();
|
queueItem.ItemProcessed.WaitOne();
|
||||||
|
|
||||||
var completionItems = queueItem.GetResultAsT<CompletionItem[]>();
|
var completionItems = queueItem.GetResultAsT<CompletionItem[]>();
|
||||||
if (completionItems != null && completionItems.Length > 0)
|
if (completionItems != null && completionItems.Length > 0)
|
||||||
{
|
{
|
||||||
return completionItems;
|
resultCompletionItems = completionItems;
|
||||||
}
|
}
|
||||||
|
else if (!ShouldShowCompletionList(token))
|
||||||
|
{
|
||||||
|
resultCompletionItems = emptyCompletionItems;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
Monitor.Exit(scriptParseInfo.BuildingMetadataLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//resultCompletionItems = AutoCompleteHelper.AddTokenToItems(resultCompletionItems, token, startLine, startColumn, endColumn);
|
||||||
return AutoCompleteHelper.GetDefaultCompletionItems(startLine, startColumn, endColumn, useLowerCaseSuggestions);
|
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
|
#endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user